-
Notifications
You must be signed in to change notification settings - Fork 0
Features
Full dataset lifecycle management:
-
Create:
client.CreateDataset(datasetId) -
Get:
client.GetDataset(datasetId) -
List:
client.ListDatasets() -
Update:
client.UpdateDataset(datasetId, ...) -
Delete:
client.DeleteDataset(datasetId)(withdeleteContentsoption)
Full table lifecycle with schema enforcement:
-
Create:
client.CreateTable(datasetId, tableId, schema) -
Get:
client.GetTable(datasetId, tableId) -
List:
client.ListTables(datasetId) -
Update:
client.UpdateTable(datasetId, tableId, ...)(add columns) -
Delete:
client.DeleteTable(datasetId, tableId)
Insert rows with schema validation:
await client.InsertRowsAsync("dataset", "table", new[]
{
new BigQueryInsertRow { ["id"] = 1, ["name"] = "Alice" },
});- Type validation against schema
-
insertIddedup (optional) - Per-row error reporting
- Rows immediately queryable (no buffer delay)
GoogleSQL dialect with 325+ built-in functions. See SQL Queries for full reference.
var results = await client.ExecuteQueryAsync(
"SELECT name, COUNT(*) as cnt FROM dataset.table GROUP BY name",
parameters: null);Data Manipulation Language via SQL:
INSERT INTO ... VALUESINSERT INTO ... SELECTUPDATE ... SET ... WHEREDELETE FROM ... WHEREMERGE INTO ... USING ... ON ... WHEN MATCHED/NOT MATCHEDTRUNCATE TABLE
Data Definition Language via SQL:
CREATE TABLE / CREATE TABLE IF NOT EXISTSCREATE OR REPLACE TABLE-
CREATE TABLE ... AS SELECT(CTAS) -
CREATE TABLE LIKE/CREATE TABLE COPY -
CREATE SNAPSHOT TABLE/CREATE TABLE CLONE DROP TABLE / DROP TABLE IF EXISTSALTER TABLE ADD COLUMN / DROP COLUMNALTER TABLE RENAME TO / RENAME COLUMNALTER TABLE SET OPTIONSALTER COLUMN SET DATA TYPE / SET DEFAULT / DROP DEFAULT / DROP NOT NULLCREATE SCHEMA / DROP SCHEMA-
CREATE [OR REPLACE] MATERIALIZED VIEW(treated as regular view) -
CREATE [OR REPLACE] EXTERNAL TABLE(creates regular table) -
CREATE [OR REPLACE] PROCEDURE / DROP PROCEDURE(no-op stubs) -
CREATE [OR REPLACE] TABLE FUNCTION / DROP TABLE FUNCTION(no-op stubs) -
CREATE ROW ACCESS POLICY / DROP ROW ACCESS POLICY(no-op stubs) -
CREATE SEARCH INDEX / DROP SEARCH INDEX(no-op stubs)
CREATE VIEW ... AS SELECTCREATE OR REPLACE VIEW- View queries re-execute the stored SQL against current data
- Views appear in
INFORMATION_SCHEMA.TABLESwithtable_type = 'VIEW'
Simulate errors for testing retry logic and error handling:
bq.SetFaultInjector(request =>
new HttpResponseMessage(HttpStatusCode.ServiceUnavailable));Supported error codes: 403, 404, 429, 500, 503
Record all HTTP requests and SQL queries for assertions:
bq.Handler.RequestLog // All HTTP requests
bq.Handler.QueryLog // All SQL queries-
CREATE TABLE ... PARTITION BY(time partitioning, range partitioning) -
_PARTITIONTIME/_PARTITIONDATEpseudo-columns - Partition pruning in
WHEREclauses
SQL and JavaScript UDFs via CREATE FUNCTION:
// SQL UDF
await client.ExecuteQueryAsync(
@"CREATE TEMP FUNCTION double_it(x INT64) AS (x * 2);
SELECT double_it(21) AS result;", parameters: null);
// JavaScript UDF (requires JsUdfs package)
await client.ExecuteQueryAsync(
@"CREATE TEMP FUNCTION plusOne(x FLOAT64) RETURNS FLOAT64
LANGUAGE js AS ""return x+1;"";
SELECT plusOne(4) AS result;", parameters: null);-
CREATE [OR REPLACE] [TEMP] FUNCTION name(params) AS (body)— SQL UDFs -
CREATE [OR REPLACE] [TEMP] FUNCTION name(params) RETURNS type LANGUAGE js AS "body"— JavaScript UDFs DROP FUNCTION [IF EXISTS] name- Multi-parameter support, string/numeric return types
- Case-insensitive routine names (matching real BigQuery)
Install InMemoryEmulator.BigQuery.JsUdfs to enable LANGUAGE js support:
using InMemoryEmulator.BigQuery.JsUdfs;
var bq = InMemoryBigQuery.Create("project", "dataset");
bq.Store.UseJsUdfs(); // Register the Jint JavaScript engineSupported JS features: return statements, arithmetic, string manipulation, null handling, multi-line bodies (triple-quoted r"""...""").
Install InMemoryEmulator.BigQuery.ProductionExtensions for IAsyncEnumerable and typed mapping:
using InMemoryEmulator.BigQuery.ProductionExtensions;
var results = await client.ExecuteQueryAsync("SELECT ...", parameters: null);
// IAsyncEnumerable iteration
await foreach (var row in results.AsAsyncEnumerable())
Console.WriteLine(row["name"]);
// Typed mapping
var items = await results.ToListAsync(row => new { Id = (long)row["id"], Name = (string)row["name"] });Range type support for date/numeric ranges:
-
RANGE(lower, upper)— construct a range -
RANGE_START(range)/RANGE_END(range)— extract bounds -
RANGE_CONTAINS(range, value)/RANGE_CONTAINS(range, range)— containment check -
RANGE_OVERLAPS(range1, range2)— overlap check -
GENERATE_RANGE_ARRAY(range)— generate array from range
41 spatial functions via the ST_* namespace:
-
Constructors:
ST_GEOGPOINT,ST_GEOGFROMTEXT,ST_GEOGFROMWKT,ST_GEOGFROMGEOJSON,ST_GEOGFROMWKB -
Output:
ST_ASTEXT,ST_ASGEOJSON,ST_ASBINARY -
Accessors:
ST_X,ST_Y,ST_NUMPOINTS,ST_NPOINTS,ST_DIMENSION,ST_ISEMPTY,ST_ISCOLLECTION,ST_GEOMETRYTYPE -
Measurement:
ST_DISTANCE,ST_AREA,ST_LENGTH,ST_PERIMETER -
Predicates:
ST_CONTAINS,ST_WITHIN,ST_INTERSECTS,ST_DISJOINT,ST_EQUALS,ST_DWITHIN,ST_COVEREDBY,ST_COVERS,ST_TOUCHES -
Transformers:
ST_MAKELINE,ST_CENTROID,ST_BOUNDARY,ST_CLOSESTPOINT,ST_CONVEXHULL,ST_DIFFERENCE,ST_INTERSECTION,ST_UNION,ST_BUFFER,ST_SIMPLIFY,ST_DUMP -
Aggregates:
ST_CENTROID_AGG,ST_UNION_AGG
6 vector similarity and distance functions:
-
COSINE_DISTANCE(v1, v2)— cosine distance between two vectors -
EUCLIDEAN_DISTANCE(v1, v2)— Euclidean distance between two vectors -
DOT_PRODUCT(v1, v2)— dot product of two vectors -
APPROX_COSINE_DISTANCE(v1, v2)— approximate cosine distance (exact in-memory) -
APPROX_EUCLIDEAN_DISTANCE(v1, v2)— approximate Euclidean distance (exact in-memory) -
APPROX_DOT_PRODUCT(v1, v2)— approximate dot product (exact in-memory)
Full procedural language support for scripting:
-
DECLARE(withDEFAULTexpressions) /SET IF ... THEN ... ELSE ... END IFWHILE ... DO ... END WHILE-
LOOP ... END LOOP/BREAK/CONTINUE FOR ... IN (query) DO ... END FORREPEAT ... UNTIL ... END REPEAT-
CASE(procedural form) -
BEGIN ... END(withEXCEPTIONhandling and@@error.message) -
RETURN/RAISE(withUSING MESSAGE) /ASSERT EXECUTE IMMEDIATE-
CALL(procedure invocation) -
BEGIN TRANSACTION/COMMIT/ROLLBACK(no-op stubs) - Labels on
BEGIN,LOOP,WHILE,FOR,REPEATblocks
3 metadata views:
-
INFORMATION_SCHEMA.TABLES— table catalog, schema, name, type, creation time -
INFORMATION_SCHEMA.COLUMNS— column metadata (name, position, type, nullability) -
INFORMATION_SCHEMA.SCHEMATA— dataset listing
-
QUALIFY— filter on window function results -
PIVOT/UNPIVOT— row-to-column and column-to-row transformations -
GROUP BY ROLLUP— hierarchical grouping with subtotals -
WITH RECURSIVE— recursive CTEs -
TABLESAMPLE— random row sampling -
WINDOWclause — named window definitions -
UNNEST WITH OFFSET— array flattening with position - Wildcard tables (
table_*) with_TABLE_SUFFIXfiltering
-
GRANT/REVOKE— parsed and accepted (no-op stubs)
-
EXPORT DATA/LOAD DATA— parsed and accepted (no-op stubs)
Full support for the BigQuery SDK's UploadCsvAsync and UploadJsonAsync methods:
-
CSV: Parses comma-separated values, supports
SkipLeadingRowsfor header rows -
JSON: Parses newline-delimited JSON (
NEWLINE_DELIMITED_JSON) - Creates the destination table automatically if it does not exist (schema required)
- Data is inserted into the in-memory store and is immediately queryable
- Uses the Google APIs resumable upload protocol under the hood
CreateExtractJobAsync returns a completed job without writing data (no real GCS to export to):
- Validates that the source table exists
- Supports single and multiple destination URIs
- Returns a
DONEjob — useful for integration tests that exercise the extract API path
Full support for the BigQuery Storage Read API via InMemoryBigQueryResult.CreateReadClient():
using var bq = InMemoryBigQuery.Create("test-project", "my_dataset", ds =>
{
ds.AddTable("users", schema);
});
// Get a BigQueryReadClient backed by the same in-memory data
var readClient = bq.CreateReadClient();
// Use the standard Storage API
var session = readClient.CreateReadSession(new CreateReadSessionRequest
{
Parent = "projects/test-project",
ReadSession = new ReadSession
{
Table = "projects/test-project/datasets/my_dataset/tables/users",
DataFormat = DataFormat.Avro,
},
MaxStreamCount = 1,
});Supported RPCs:
-
CreateReadSession— create a read session with configurable stream count -
ReadRows— stream Avro-serialized rows from a read stream -
SplitReadStream— split a stream into two child streams
Getting Started
Integration & DI
Data Management
Reference