@tanstack/db 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cjs/query/compiled-query.cjs +40 -59
  2. package/dist/cjs/query/compiled-query.cjs.map +1 -1
  3. package/dist/cjs/query/compiled-query.d.cts +0 -4
  4. package/dist/cjs/query/group-by.cjs +3 -3
  5. package/dist/cjs/query/group-by.cjs.map +1 -1
  6. package/dist/cjs/query/group-by.d.cts +1 -1
  7. package/dist/cjs/query/joins.cjs +16 -16
  8. package/dist/cjs/query/joins.cjs.map +1 -1
  9. package/dist/cjs/query/joins.d.cts +1 -1
  10. package/dist/cjs/query/order-by.cjs +6 -6
  11. package/dist/cjs/query/order-by.cjs.map +1 -1
  12. package/dist/cjs/query/pipeline-compiler.cjs +5 -5
  13. package/dist/cjs/query/pipeline-compiler.cjs.map +1 -1
  14. package/dist/cjs/query/pipeline-compiler.d.cts +1 -1
  15. package/dist/cjs/query/select.cjs +2 -2
  16. package/dist/cjs/query/select.cjs.map +1 -1
  17. package/dist/cjs/transactions.cjs +5 -12
  18. package/dist/cjs/transactions.cjs.map +1 -1
  19. package/dist/cjs/transactions.d.cts +1 -1
  20. package/dist/cjs/types.d.cts +1 -1
  21. package/dist/esm/query/compiled-query.d.ts +0 -4
  22. package/dist/esm/query/compiled-query.js +40 -59
  23. package/dist/esm/query/compiled-query.js.map +1 -1
  24. package/dist/esm/query/group-by.d.ts +1 -1
  25. package/dist/esm/query/group-by.js +1 -1
  26. package/dist/esm/query/group-by.js.map +1 -1
  27. package/dist/esm/query/joins.d.ts +1 -1
  28. package/dist/esm/query/joins.js +1 -1
  29. package/dist/esm/query/joins.js.map +1 -1
  30. package/dist/esm/query/order-by.js +1 -1
  31. package/dist/esm/query/order-by.js.map +1 -1
  32. package/dist/esm/query/pipeline-compiler.d.ts +1 -1
  33. package/dist/esm/query/pipeline-compiler.js +1 -1
  34. package/dist/esm/query/pipeline-compiler.js.map +1 -1
  35. package/dist/esm/query/select.js +1 -1
  36. package/dist/esm/query/select.js.map +1 -1
  37. package/dist/esm/transactions.d.ts +1 -1
  38. package/dist/esm/transactions.js +5 -12
  39. package/dist/esm/transactions.js.map +1 -1
  40. package/dist/esm/types.d.ts +1 -1
  41. package/package.json +2 -2
  42. package/src/query/compiled-query.ts +44 -66
  43. package/src/query/group-by.ts +1 -1
  44. package/src/query/joins.ts +2 -2
  45. package/src/query/order-by.ts +1 -1
  46. package/src/query/pipeline-compiler.ts +2 -2
  47. package/src/query/select.ts +1 -1
  48. package/src/transactions.ts +8 -20
  49. package/src/types.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-compiler.cjs","sources":["../../../src/query/pipeline-compiler.ts"],"sourcesContent":["import { filter, map } from \"@electric-sql/d2ts\"\nimport { evaluateWhereOnNamespacedRow } from \"./evaluators.js\"\nimport { processJoinClause } from \"./joins.js\"\nimport { processGroupBy } from \"./group-by.js\"\nimport { processOrderBy } from \"./order-by.js\"\nimport { processSelect } from \"./select.js\"\nimport type { Query } from \"./schema.js\"\nimport type { IStreamBuilder } from \"@electric-sql/d2ts\"\nimport type {\n InputRow,\n KeyedStream,\n NamespacedAndKeyedStream,\n} from \"../types.js\"\n\n/**\n * Compiles a query into a D2 pipeline\n * @param query The query to compile\n * @param inputs Mapping of table names to input streams\n * @returns A stream builder representing the compiled query\n */\nexport function compileQueryPipeline<T extends IStreamBuilder<unknown>>(\n query: Query,\n inputs: Record<string, KeyedStream>\n): T {\n // Create a copy of the inputs map to avoid modifying the original\n const allInputs = { ...inputs }\n\n // Process WITH queries if they exist\n if (query.with && query.with.length > 0) {\n // Process each WITH query in order\n for (const withQuery of query.with) {\n // Ensure the WITH query has an alias\n if (!withQuery.as) {\n throw new Error(`WITH query must have an \"as\" property`)\n }\n\n // Check if this CTE name already exists in the inputs\n if (allInputs[withQuery.as]) {\n throw new Error(`CTE with name \"${withQuery.as}\" already exists`)\n }\n\n // Create a new query without the 'with' property to avoid circular references\n const withQueryWithoutWith = { ...withQuery, with: undefined }\n\n // Compile the WITH query using the current set of inputs\n // (which includes previously compiled WITH queries)\n const compiledWithQuery = compileQueryPipeline(\n withQueryWithoutWith,\n allInputs\n )\n\n // Add the compiled query to the inputs map using its alias\n allInputs[withQuery.as] = compiledWithQuery as KeyedStream\n }\n }\n\n // Create a map of table aliases to inputs\n const tables: Record<string, KeyedStream> = {}\n\n // The main table is the one in the FROM clause\n const mainTableAlias = query.as || query.from\n\n // Get the main input from the inputs map (now including CTEs)\n const input = allInputs[query.from]\n if (!input) {\n throw new Error(`Input for table \"${query.from}\" not found in inputs map`)\n }\n\n tables[mainTableAlias] = input\n\n // Prepare the initial pipeline with the main table wrapped in its alias\n let pipeline: NamespacedAndKeyedStream = input.pipe(\n map(([key, row]) => {\n // Initialize the record with a nested structure\n const ret = [key, { [mainTableAlias]: row }] as [\n string,\n Record<string, typeof row>,\n ]\n return ret\n })\n )\n\n // Process JOIN clauses if they exist\n if (query.join) {\n pipeline = processJoinClause(\n pipeline,\n query,\n tables,\n mainTableAlias,\n allInputs\n )\n }\n\n // Process the WHERE clause if it exists\n if (query.where) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n const result = evaluateWhereOnNamespacedRow(\n row,\n query.where!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process the GROUP BY clause if it exists\n if (query.groupBy) {\n pipeline = processGroupBy(pipeline, query, mainTableAlias)\n }\n\n // Process the HAVING clause if it exists\n // This works similarly to WHERE but is applied after any aggregations\n if (query.having) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n // For HAVING, we're working with the flattened row that contains both\n // the group by keys and the aggregate results directly\n const result = evaluateWhereOnNamespacedRow(\n row,\n query.having!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process orderBy parameter if it exists\n if (query.orderBy) {\n pipeline = processOrderBy(pipeline, query, mainTableAlias)\n } else if (query.limit !== undefined || query.offset !== undefined) {\n // If there's a limit or offset without orderBy, throw an error\n throw new Error(\n `LIMIT and OFFSET require an ORDER BY clause to ensure deterministic results`\n )\n }\n\n // Process the SELECT clause - this is where we flatten the structure\n const resultPipeline: KeyedStream | NamespacedAndKeyedStream = query.select\n ? processSelect(pipeline, query, mainTableAlias, allInputs)\n : !query.join && !query.groupBy\n ? pipeline.pipe(\n map(([key, row]) => [key, row[mainTableAlias]] as InputRow)\n )\n : pipeline\n return resultPipeline as T\n}\n"],"names":["map","processJoinClause","filter","evaluateWhereOnNamespacedRow","processGroupBy","processOrderBy","processSelect"],"mappings":";;;;;;;;AAoBgB,SAAA,qBACd,OACA,QACG;AAEG,QAAA,YAAY,EAAE,GAAG,OAAO;AAG9B,MAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GAAG;AAE5B,eAAA,aAAa,MAAM,MAAM;AAE9B,UAAA,CAAC,UAAU,IAAI;AACX,cAAA,IAAI,MAAM,uCAAuC;AAAA,MAAA;AAIrD,UAAA,UAAU,UAAU,EAAE,GAAG;AAC3B,cAAM,IAAI,MAAM,kBAAkB,UAAU,EAAE,kBAAkB;AAAA,MAAA;AAIlE,YAAM,uBAAuB,EAAE,GAAG,WAAW,MAAM,OAAU;AAI7D,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAGU,gBAAA,UAAU,EAAE,IAAI;AAAA,IAAA;AAAA,EAC5B;AAIF,QAAM,SAAsC,CAAC;AAGvC,QAAA,iBAAiB,MAAM,MAAM,MAAM;AAGnC,QAAA,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,oBAAoB,MAAM,IAAI,2BAA2B;AAAA,EAAA;AAG3E,SAAO,cAAc,IAAI;AAGzB,MAAI,WAAqC,MAAM;AAAA,IAC7CA,KAAAA,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM;AAEZ,YAAA,MAAM,CAAC,KAAK,EAAE,CAAC,cAAc,GAAG,KAAK;AAIpC,aAAA;AAAA,IACR,CAAA;AAAA,EACH;AAGA,MAAI,MAAM,MAAM;AACH,eAAAC,MAAA;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAIF,MAAI,MAAM,OAAO;AACf,eAAW,SAAS;AAAA,MAClBC,KAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AACtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAC,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA;AAK3D,MAAI,MAAM,QAAQ;AAChB,eAAW,SAAS;AAAA,MAClBF,KAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AAGtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAE,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA,WAChD,MAAM,UAAU,UAAa,MAAM,WAAW,QAAW;AAElE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAIF,QAAM,iBAAyD,MAAM,SACjEC,OAAAA,cAAc,UAAU,OAAO,gBAAgB,SAAS,IACxD,CAAC,MAAM,QAAQ,CAAC,MAAM,UACpB,SAAS;AAAA,IACPN,SAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,cAAc,CAAC,CAAa;AAAA,EAAA,IAE5D;AACC,SAAA;AACT;;"}
1
+ {"version":3,"file":"pipeline-compiler.cjs","sources":["../../../src/query/pipeline-compiler.ts"],"sourcesContent":["import { filter, map } from \"@electric-sql/d2mini\"\nimport { evaluateWhereOnNamespacedRow } from \"./evaluators.js\"\nimport { processJoinClause } from \"./joins.js\"\nimport { processGroupBy } from \"./group-by.js\"\nimport { processOrderBy } from \"./order-by.js\"\nimport { processSelect } from \"./select.js\"\nimport type { Query } from \"./schema.js\"\nimport type { IStreamBuilder } from \"@electric-sql/d2mini\"\nimport type {\n InputRow,\n KeyedStream,\n NamespacedAndKeyedStream,\n} from \"../types.js\"\n\n/**\n * Compiles a query into a D2 pipeline\n * @param query The query to compile\n * @param inputs Mapping of table names to input streams\n * @returns A stream builder representing the compiled query\n */\nexport function compileQueryPipeline<T extends IStreamBuilder<unknown>>(\n query: Query,\n inputs: Record<string, KeyedStream>\n): T {\n // Create a copy of the inputs map to avoid modifying the original\n const allInputs = { ...inputs }\n\n // Process WITH queries if they exist\n if (query.with && query.with.length > 0) {\n // Process each WITH query in order\n for (const withQuery of query.with) {\n // Ensure the WITH query has an alias\n if (!withQuery.as) {\n throw new Error(`WITH query must have an \"as\" property`)\n }\n\n // Check if this CTE name already exists in the inputs\n if (allInputs[withQuery.as]) {\n throw new Error(`CTE with name \"${withQuery.as}\" already exists`)\n }\n\n // Create a new query without the 'with' property to avoid circular references\n const withQueryWithoutWith = { ...withQuery, with: undefined }\n\n // Compile the WITH query using the current set of inputs\n // (which includes previously compiled WITH queries)\n const compiledWithQuery = compileQueryPipeline(\n withQueryWithoutWith,\n allInputs\n )\n\n // Add the compiled query to the inputs map using its alias\n allInputs[withQuery.as] = compiledWithQuery as KeyedStream\n }\n }\n\n // Create a map of table aliases to inputs\n const tables: Record<string, KeyedStream> = {}\n\n // The main table is the one in the FROM clause\n const mainTableAlias = query.as || query.from\n\n // Get the main input from the inputs map (now including CTEs)\n const input = allInputs[query.from]\n if (!input) {\n throw new Error(`Input for table \"${query.from}\" not found in inputs map`)\n }\n\n tables[mainTableAlias] = input\n\n // Prepare the initial pipeline with the main table wrapped in its alias\n let pipeline: NamespacedAndKeyedStream = input.pipe(\n map(([key, row]) => {\n // Initialize the record with a nested structure\n const ret = [key, { [mainTableAlias]: row }] as [\n string,\n Record<string, typeof row>,\n ]\n return ret\n })\n )\n\n // Process JOIN clauses if they exist\n if (query.join) {\n pipeline = processJoinClause(\n pipeline,\n query,\n tables,\n mainTableAlias,\n allInputs\n )\n }\n\n // Process the WHERE clause if it exists\n if (query.where) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n const result = evaluateWhereOnNamespacedRow(\n row,\n query.where!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process the GROUP BY clause if it exists\n if (query.groupBy) {\n pipeline = processGroupBy(pipeline, query, mainTableAlias)\n }\n\n // Process the HAVING clause if it exists\n // This works similarly to WHERE but is applied after any aggregations\n if (query.having) {\n pipeline = pipeline.pipe(\n filter(([_key, row]) => {\n // For HAVING, we're working with the flattened row that contains both\n // the group by keys and the aggregate results directly\n const result = evaluateWhereOnNamespacedRow(\n row,\n query.having!,\n mainTableAlias\n )\n return result\n })\n )\n }\n\n // Process orderBy parameter if it exists\n if (query.orderBy) {\n pipeline = processOrderBy(pipeline, query, mainTableAlias)\n } else if (query.limit !== undefined || query.offset !== undefined) {\n // If there's a limit or offset without orderBy, throw an error\n throw new Error(\n `LIMIT and OFFSET require an ORDER BY clause to ensure deterministic results`\n )\n }\n\n // Process the SELECT clause - this is where we flatten the structure\n const resultPipeline: KeyedStream | NamespacedAndKeyedStream = query.select\n ? processSelect(pipeline, query, mainTableAlias, allInputs)\n : !query.join && !query.groupBy\n ? pipeline.pipe(\n map(([key, row]) => [key, row[mainTableAlias]] as InputRow)\n )\n : pipeline\n return resultPipeline as T\n}\n"],"names":["map","processJoinClause","filter","evaluateWhereOnNamespacedRow","processGroupBy","processOrderBy","processSelect"],"mappings":";;;;;;;;AAoBgB,SAAA,qBACd,OACA,QACG;AAEG,QAAA,YAAY,EAAE,GAAG,OAAO;AAG9B,MAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GAAG;AAE5B,eAAA,aAAa,MAAM,MAAM;AAE9B,UAAA,CAAC,UAAU,IAAI;AACX,cAAA,IAAI,MAAM,uCAAuC;AAAA,MAAA;AAIrD,UAAA,UAAU,UAAU,EAAE,GAAG;AAC3B,cAAM,IAAI,MAAM,kBAAkB,UAAU,EAAE,kBAAkB;AAAA,MAAA;AAIlE,YAAM,uBAAuB,EAAE,GAAG,WAAW,MAAM,OAAU;AAI7D,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAGU,gBAAA,UAAU,EAAE,IAAI;AAAA,IAAA;AAAA,EAC5B;AAIF,QAAM,SAAsC,CAAC;AAGvC,QAAA,iBAAiB,MAAM,MAAM,MAAM;AAGnC,QAAA,QAAQ,UAAU,MAAM,IAAI;AAClC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,oBAAoB,MAAM,IAAI,2BAA2B;AAAA,EAAA;AAG3E,SAAO,cAAc,IAAI;AAGzB,MAAI,WAAqC,MAAM;AAAA,IAC7CA,OAAAA,IAAI,CAAC,CAAC,KAAK,GAAG,MAAM;AAEZ,YAAA,MAAM,CAAC,KAAK,EAAE,CAAC,cAAc,GAAG,KAAK;AAIpC,aAAA;AAAA,IACR,CAAA;AAAA,EACH;AAGA,MAAI,MAAM,MAAM;AACH,eAAAC,MAAA;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAAA;AAIF,MAAI,MAAM,OAAO;AACf,eAAW,SAAS;AAAA,MAClBC,OAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AACtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAC,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA;AAK3D,MAAI,MAAM,QAAQ;AAChB,eAAW,SAAS;AAAA,MAClBF,OAAAA,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM;AAGtB,cAAM,SAASC,WAAA;AAAA,UACb;AAAA,UACA,MAAM;AAAA,UACN;AAAA,QACF;AACO,eAAA;AAAA,MACR,CAAA;AAAA,IACH;AAAA,EAAA;AAIF,MAAI,MAAM,SAAS;AACN,eAAAE,QAAA,eAAe,UAAU,OAAO,cAAc;AAAA,EAAA,WAChD,MAAM,UAAU,UAAa,MAAM,WAAW,QAAW;AAElE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAIF,QAAM,iBAAyD,MAAM,SACjEC,OAAAA,cAAc,UAAU,OAAO,gBAAgB,SAAS,IACxD,CAAC,MAAM,QAAQ,CAAC,MAAM,UACpB,SAAS;AAAA,IACPN,WAAI,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,cAAc,CAAC,CAAa;AAAA,EAAA,IAE5D;AACC,SAAA;AACT;;"}
@@ -1,5 +1,5 @@
1
1
  import { Query } from './schema.js';
2
- import { IStreamBuilder } from '@electric-sql/d2ts';
2
+ import { IStreamBuilder } from '@electric-sql/d2mini';
3
3
  import { KeyedStream } from '../types.js';
4
4
  /**
5
5
  * Compiles a query into a D2 pipeline
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const d2ts = require("@electric-sql/d2ts");
3
+ const d2mini = require("@electric-sql/d2mini");
4
4
  const extractors = require("./extractors.cjs");
5
5
  function processSelect(pipeline, query, mainTableAlias, inputs) {
6
6
  return pipeline.pipe(
7
- d2ts.map(([key, namespacedRow]) => {
7
+ d2mini.map(([key, namespacedRow]) => {
8
8
  const result = {};
9
9
  const isGroupedResult = query.groupBy && Object.keys(namespacedRow).some(
10
10
  (namespaceKey) => !Object.keys(inputs).includes(namespaceKey) && typeof namespacedRow[namespaceKey] !== `object`
@@ -1 +1 @@
1
- {"version":3,"file":"select.cjs","sources":["../../../src/query/select.ts"],"sourcesContent":["import { map } from \"@electric-sql/d2ts\"\nimport {\n evaluateOperandOnNamespacedRow,\n extractValueFromNamespacedRow,\n} from \"./extractors\"\nimport type { ConditionOperand, Query, SelectCallback } from \"./schema\"\nimport type { KeyedStream, NamespacedAndKeyedStream } from \"../types\"\n\nexport function processSelect(\n pipeline: NamespacedAndKeyedStream,\n query: Query,\n mainTableAlias: string,\n inputs: Record<string, KeyedStream>\n): KeyedStream {\n return pipeline.pipe(\n map(([key, namespacedRow]) => {\n const result: Record<string, unknown> = {}\n\n // Check if this is a grouped result (has no nested table structure)\n // If it's a grouped result, we need to handle it differently\n const isGroupedResult =\n query.groupBy &&\n Object.keys(namespacedRow).some(\n (namespaceKey) =>\n !Object.keys(inputs).includes(namespaceKey) &&\n typeof namespacedRow[namespaceKey] !== `object`\n )\n\n if (!query.select) {\n throw new Error(`Cannot process missing SELECT clause`)\n }\n\n for (const item of query.select) {\n // Handle callback functions\n if (typeof item === `function`) {\n const callback = item as SelectCallback\n const callbackResult = callback(namespacedRow)\n\n // If the callback returns an object, merge its properties into the result\n if (\n callbackResult &&\n typeof callbackResult === `object` &&\n !Array.isArray(callbackResult)\n ) {\n Object.assign(result, callbackResult)\n } else {\n // If the callback returns a primitive value, we can't merge it\n // This would need a specific key, but since we don't have one, we'll skip it\n // In practice, select callbacks should return objects with keys\n console.warn(\n `SelectCallback returned a non-object value. SelectCallbacks should return objects with key-value pairs.`\n )\n }\n continue\n }\n\n if (typeof item === `string`) {\n // Handle wildcard select - all columns from all tables\n if ((item as string) === `@*`) {\n // For grouped results, just return the row as is\n if (isGroupedResult) {\n Object.assign(result, namespacedRow)\n } else {\n // Extract all columns from all tables\n Object.assign(\n result,\n extractAllColumnsFromAllTables(namespacedRow)\n )\n }\n continue\n }\n\n // Handle @table.* syntax - all columns from a specific table\n if (\n (item as string).startsWith(`@`) &&\n (item as string).endsWith(`.*`)\n ) {\n const tableAlias = (item as string).slice(1, -2) // Remove the '@' and '.*' parts\n\n // For grouped results, check if we have columns from this table\n if (isGroupedResult) {\n // In grouped results, we don't have the nested structure anymore\n // So we can't extract by table. Just continue to the next item.\n continue\n } else {\n // Extract all columns from the specified table\n Object.assign(\n result,\n extractAllColumnsFromTable(namespacedRow, tableAlias)\n )\n }\n continue\n }\n\n // Handle simple column references like \"@table.column\" or \"@column\"\n if ((item as string).startsWith(`@`)) {\n const columnRef = (item as string).substring(1)\n const alias = columnRef\n\n // For grouped results, check if the column is directly in the row first\n if (isGroupedResult && columnRef in namespacedRow) {\n result[alias] = namespacedRow[columnRef]\n } else {\n // Extract the value from the nested structure\n result[alias] = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef,\n mainTableAlias,\n undefined\n )\n }\n\n // If the alias contains a dot (table.column),\n // use just the column part as the field name\n if (alias.includes(`.`)) {\n const columnName = alias.split(`.`)[1]\n result[columnName!] = result[alias]\n delete result[alias]\n }\n }\n } else {\n // Handle aliased columns like { alias: \"@column_name\" }\n for (const [alias, expr] of Object.entries(item)) {\n if (typeof expr === `string` && (expr as string).startsWith(`@`)) {\n const columnRef = (expr as string).substring(1)\n\n // For grouped results, check if the column is directly in the row first\n if (isGroupedResult && columnRef in namespacedRow) {\n result[alias] = namespacedRow[columnRef]\n } else {\n // Extract the value from the nested structure\n result[alias] = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef,\n mainTableAlias,\n undefined\n )\n }\n } else if (typeof expr === `object`) {\n // For grouped results, the aggregate results are already in the row\n if (isGroupedResult && alias in namespacedRow) {\n result[alias] = namespacedRow[alias]\n } else if ((expr as { ORDER_INDEX: unknown }).ORDER_INDEX) {\n result[alias] = namespacedRow[mainTableAlias]![alias]\n } else {\n // This might be a function call\n result[alias] = evaluateOperandOnNamespacedRow(\n namespacedRow,\n expr as ConditionOperand,\n mainTableAlias,\n undefined\n )\n }\n }\n }\n }\n }\n\n return [key, result] as [string, typeof result]\n })\n )\n}\n\n// Helper function to extract all columns from all tables in a nested row\nfunction extractAllColumnsFromAllTables(\n namespacedRow: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n // Process each table in the nested row\n for (const [tableAlias, tableData] of Object.entries(namespacedRow)) {\n if (tableData && typeof tableData === `object`) {\n // Add all columns from this table to the result\n // If there are column name conflicts, the last table's columns will overwrite previous ones\n Object.assign(\n result,\n extractAllColumnsFromTable(namespacedRow, tableAlias)\n )\n }\n }\n\n return result\n}\n\n// Helper function to extract all columns from a table in a nested row\nfunction extractAllColumnsFromTable(\n namespacedRow: Record<string, unknown>,\n tableAlias: string\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n // Get the table data\n const tableData = namespacedRow[tableAlias] as\n | Record<string, unknown>\n | null\n | undefined\n\n if (!tableData || typeof tableData !== `object`) {\n return result\n }\n\n // Add all columns from the table to the result\n for (const [columnName, value] of Object.entries(tableData)) {\n result[columnName] = value\n }\n\n return result\n}\n"],"names":["map","extractValueFromNamespacedRow","evaluateOperandOnNamespacedRow"],"mappings":"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"}
1
+ {"version":3,"file":"select.cjs","sources":["../../../src/query/select.ts"],"sourcesContent":["import { map } from \"@electric-sql/d2mini\"\nimport {\n evaluateOperandOnNamespacedRow,\n extractValueFromNamespacedRow,\n} from \"./extractors\"\nimport type { ConditionOperand, Query, SelectCallback } from \"./schema\"\nimport type { KeyedStream, NamespacedAndKeyedStream } from \"../types\"\n\nexport function processSelect(\n pipeline: NamespacedAndKeyedStream,\n query: Query,\n mainTableAlias: string,\n inputs: Record<string, KeyedStream>\n): KeyedStream {\n return pipeline.pipe(\n map(([key, namespacedRow]) => {\n const result: Record<string, unknown> = {}\n\n // Check if this is a grouped result (has no nested table structure)\n // If it's a grouped result, we need to handle it differently\n const isGroupedResult =\n query.groupBy &&\n Object.keys(namespacedRow).some(\n (namespaceKey) =>\n !Object.keys(inputs).includes(namespaceKey) &&\n typeof namespacedRow[namespaceKey] !== `object`\n )\n\n if (!query.select) {\n throw new Error(`Cannot process missing SELECT clause`)\n }\n\n for (const item of query.select) {\n // Handle callback functions\n if (typeof item === `function`) {\n const callback = item as SelectCallback\n const callbackResult = callback(namespacedRow)\n\n // If the callback returns an object, merge its properties into the result\n if (\n callbackResult &&\n typeof callbackResult === `object` &&\n !Array.isArray(callbackResult)\n ) {\n Object.assign(result, callbackResult)\n } else {\n // If the callback returns a primitive value, we can't merge it\n // This would need a specific key, but since we don't have one, we'll skip it\n // In practice, select callbacks should return objects with keys\n console.warn(\n `SelectCallback returned a non-object value. SelectCallbacks should return objects with key-value pairs.`\n )\n }\n continue\n }\n\n if (typeof item === `string`) {\n // Handle wildcard select - all columns from all tables\n if ((item as string) === `@*`) {\n // For grouped results, just return the row as is\n if (isGroupedResult) {\n Object.assign(result, namespacedRow)\n } else {\n // Extract all columns from all tables\n Object.assign(\n result,\n extractAllColumnsFromAllTables(namespacedRow)\n )\n }\n continue\n }\n\n // Handle @table.* syntax - all columns from a specific table\n if (\n (item as string).startsWith(`@`) &&\n (item as string).endsWith(`.*`)\n ) {\n const tableAlias = (item as string).slice(1, -2) // Remove the '@' and '.*' parts\n\n // For grouped results, check if we have columns from this table\n if (isGroupedResult) {\n // In grouped results, we don't have the nested structure anymore\n // So we can't extract by table. Just continue to the next item.\n continue\n } else {\n // Extract all columns from the specified table\n Object.assign(\n result,\n extractAllColumnsFromTable(namespacedRow, tableAlias)\n )\n }\n continue\n }\n\n // Handle simple column references like \"@table.column\" or \"@column\"\n if ((item as string).startsWith(`@`)) {\n const columnRef = (item as string).substring(1)\n const alias = columnRef\n\n // For grouped results, check if the column is directly in the row first\n if (isGroupedResult && columnRef in namespacedRow) {\n result[alias] = namespacedRow[columnRef]\n } else {\n // Extract the value from the nested structure\n result[alias] = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef,\n mainTableAlias,\n undefined\n )\n }\n\n // If the alias contains a dot (table.column),\n // use just the column part as the field name\n if (alias.includes(`.`)) {\n const columnName = alias.split(`.`)[1]\n result[columnName!] = result[alias]\n delete result[alias]\n }\n }\n } else {\n // Handle aliased columns like { alias: \"@column_name\" }\n for (const [alias, expr] of Object.entries(item)) {\n if (typeof expr === `string` && (expr as string).startsWith(`@`)) {\n const columnRef = (expr as string).substring(1)\n\n // For grouped results, check if the column is directly in the row first\n if (isGroupedResult && columnRef in namespacedRow) {\n result[alias] = namespacedRow[columnRef]\n } else {\n // Extract the value from the nested structure\n result[alias] = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef,\n mainTableAlias,\n undefined\n )\n }\n } else if (typeof expr === `object`) {\n // For grouped results, the aggregate results are already in the row\n if (isGroupedResult && alias in namespacedRow) {\n result[alias] = namespacedRow[alias]\n } else if ((expr as { ORDER_INDEX: unknown }).ORDER_INDEX) {\n result[alias] = namespacedRow[mainTableAlias]![alias]\n } else {\n // This might be a function call\n result[alias] = evaluateOperandOnNamespacedRow(\n namespacedRow,\n expr as ConditionOperand,\n mainTableAlias,\n undefined\n )\n }\n }\n }\n }\n }\n\n return [key, result] as [string, typeof result]\n })\n )\n}\n\n// Helper function to extract all columns from all tables in a nested row\nfunction extractAllColumnsFromAllTables(\n namespacedRow: Record<string, unknown>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n // Process each table in the nested row\n for (const [tableAlias, tableData] of Object.entries(namespacedRow)) {\n if (tableData && typeof tableData === `object`) {\n // Add all columns from this table to the result\n // If there are column name conflicts, the last table's columns will overwrite previous ones\n Object.assign(\n result,\n extractAllColumnsFromTable(namespacedRow, tableAlias)\n )\n }\n }\n\n return result\n}\n\n// Helper function to extract all columns from a table in a nested row\nfunction extractAllColumnsFromTable(\n namespacedRow: Record<string, unknown>,\n tableAlias: string\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n\n // Get the table data\n const tableData = namespacedRow[tableAlias] as\n | Record<string, unknown>\n | null\n | undefined\n\n if (!tableData || typeof tableData !== `object`) {\n return result\n }\n\n // Add all columns from the table to the result\n for (const [columnName, value] of Object.entries(tableData)) {\n result[columnName] = value\n }\n\n return result\n}\n"],"names":["map","extractValueFromNamespacedRow","evaluateOperandOnNamespacedRow"],"mappings":"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"}
@@ -1,16 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const deferred = require("./deferred.cjs");
4
- function generateUUID() {
5
- if (typeof crypto !== `undefined` && typeof crypto.randomUUID === `function`) {
6
- return crypto.randomUUID();
7
- }
8
- return `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g, function(c) {
9
- const r = Math.random() * 16 | 0;
10
- const v = c === `x` ? r : r & 3 | 8;
11
- return v.toString(16);
12
- });
13
- }
14
4
  const transactions = [];
15
5
  let transactionStack = [];
16
6
  function createTransaction(config) {
@@ -19,9 +9,12 @@ function createTransaction(config) {
19
9
  }
20
10
  let transactionId = config.id;
21
11
  if (!transactionId) {
22
- transactionId = generateUUID();
12
+ transactionId = crypto.randomUUID();
23
13
  }
24
- const newTransaction = new Transaction({ ...config, id: transactionId });
14
+ const newTransaction = new Transaction({
15
+ ...config,
16
+ id: transactionId
17
+ });
25
18
  transactions.push(newTransaction);
26
19
  return newTransaction;
27
20
  }
@@ -1 +1 @@
1
- {"version":3,"file":"transactions.cjs","sources":["../../src/transactions.ts"],"sourcesContent":["import { createDeferred } from \"./deferred\"\nimport type { Deferred } from \"./deferred\"\nimport type {\n MutationFn,\n PendingMutation,\n TransactionConfig,\n TransactionState,\n TransactionWithMutations,\n} from \"./types\"\n\nfunction generateUUID() {\n // Check if crypto.randomUUID is available (modern browsers and Node.js 15+)\n if (\n typeof crypto !== `undefined` &&\n typeof crypto.randomUUID === `function`\n ) {\n return crypto.randomUUID()\n }\n\n // Fallback implementation for older environments\n return `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g, function (c) {\n const r = (Math.random() * 16) | 0\n const v = c === `x` ? r : (r & 0x3) | 0x8\n return v.toString(16)\n })\n}\n\nconst transactions: Array<Transaction<any>> = []\nlet transactionStack: Array<Transaction<any>> = []\n\nexport function createTransaction(config: TransactionConfig): Transaction {\n if (typeof config.mutationFn === `undefined`) {\n throw `mutationFn is required when creating a transaction`\n }\n\n let transactionId = config.id\n if (!transactionId) {\n transactionId = generateUUID()\n }\n const newTransaction = new Transaction({ ...config, id: transactionId })\n\n transactions.push(newTransaction)\n\n return newTransaction\n}\n\nexport function getActiveTransaction(): Transaction | undefined {\n if (transactionStack.length > 0) {\n return transactionStack.slice(-1)[0]\n } else {\n return undefined\n }\n}\n\nfunction registerTransaction(tx: Transaction<any>) {\n transactionStack.push(tx)\n}\n\nfunction unregisterTransaction(tx: Transaction<any>) {\n transactionStack = transactionStack.filter((t) => t.id !== tx.id)\n}\n\nfunction removeFromPendingList(tx: Transaction<any>) {\n const index = transactions.findIndex((t) => t.id === tx.id)\n if (index !== -1) {\n transactions.splice(index, 1)\n }\n}\n\nexport class Transaction<T extends object = Record<string, unknown>> {\n public id: string\n public state: TransactionState\n public mutationFn: MutationFn<T>\n public mutations: Array<PendingMutation<T>>\n public isPersisted: Deferred<Transaction<T>>\n public autoCommit: boolean\n public createdAt: Date\n public metadata: Record<string, unknown>\n public error?: {\n message: string\n error: Error\n }\n\n constructor(config: TransactionConfig<T>) {\n this.id = config.id!\n this.mutationFn = config.mutationFn\n this.state = `pending`\n this.mutations = []\n this.isPersisted = createDeferred<Transaction<T>>()\n this.autoCommit = config.autoCommit ?? true\n this.createdAt = new Date()\n this.metadata = config.metadata ?? {}\n }\n\n setState(newState: TransactionState) {\n this.state = newState\n\n if (newState === `completed` || newState === `failed`) {\n removeFromPendingList(this)\n }\n }\n\n mutate(callback: () => void): Transaction<T> {\n if (this.state !== `pending`) {\n throw `You can no longer call .mutate() as the transaction is no longer pending`\n }\n\n registerTransaction(this)\n try {\n callback()\n } finally {\n unregisterTransaction(this)\n }\n\n if (this.autoCommit) {\n this.commit()\n }\n\n return this\n }\n\n applyMutations(mutations: Array<PendingMutation<any>>): void {\n for (const newMutation of mutations) {\n const existingIndex = this.mutations.findIndex(\n (m) => m.globalKey === newMutation.globalKey\n )\n\n if (existingIndex >= 0) {\n // Replace existing mutation\n this.mutations[existingIndex] = newMutation\n } else {\n // Insert new mutation\n this.mutations.push(newMutation)\n }\n }\n }\n\n rollback(config?: { isSecondaryRollback?: boolean }): Transaction<T> {\n const isSecondaryRollback = config?.isSecondaryRollback ?? false\n if (this.state === `completed`) {\n throw `You can no longer call .rollback() as the transaction is already completed`\n }\n\n this.setState(`failed`)\n\n // See if there's any other transactions w/ mutations on the same ids\n // and roll them back as well.\n if (!isSecondaryRollback) {\n const mutationIds = new Set()\n this.mutations.forEach((m) => mutationIds.add(m.globalKey))\n for (const t of transactions) {\n t.state === `pending` &&\n t.mutations.some((m) => mutationIds.has(m.globalKey)) &&\n t.rollback({ isSecondaryRollback: true })\n }\n }\n\n // Reject the promise\n this.isPersisted.reject(this.error?.error)\n this.touchCollection()\n\n return this\n }\n\n // Tell collection that something has changed with the transaction\n touchCollection(): void {\n const hasCalled = new Set()\n for (const mutation of this.mutations) {\n if (!hasCalled.has(mutation.collection.id)) {\n mutation.collection.onTransactionStateChange()\n mutation.collection.commitPendingTransactions()\n hasCalled.add(mutation.collection.id)\n }\n }\n }\n\n async commit(): Promise<Transaction<T>> {\n if (this.state !== `pending`) {\n throw `You can no longer call .commit() as the transaction is no longer pending`\n }\n\n this.setState(`persisting`)\n\n if (this.mutations.length === 0) {\n this.setState(`completed`)\n\n return this\n }\n\n // Run mutationFn\n try {\n // At this point we know there's at least one mutation\n // We've already verified mutations is non-empty, so this cast is safe\n // Use a direct type assertion instead of object spreading to preserve the original type\n await this.mutationFn({\n transaction: this as unknown as TransactionWithMutations<T>,\n })\n\n this.setState(`completed`)\n this.touchCollection()\n\n this.isPersisted.resolve(this)\n } catch (error) {\n // Update transaction with error information\n this.error = {\n message: error instanceof Error ? error.message : String(error),\n error: error instanceof Error ? error : new Error(String(error)),\n }\n\n // rollback the transaction\n return this.rollback()\n }\n\n return this\n }\n}\n"],"names":["createDeferred"],"mappings":"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"}
1
+ {"version":3,"file":"transactions.cjs","sources":["../../src/transactions.ts"],"sourcesContent":["import { createDeferred } from \"./deferred\"\nimport type { Deferred } from \"./deferred\"\nimport type {\n MutationFn,\n PendingMutation,\n TransactionConfig,\n TransactionState,\n TransactionWithMutations,\n} from \"./types\"\n\nconst transactions: Array<Transaction<any>> = []\nlet transactionStack: Array<Transaction<any>> = []\n\nexport function createTransaction<\n TData extends object = Record<string, unknown>,\n>(config: TransactionConfig<TData>): Transaction<TData> {\n if (typeof config.mutationFn === `undefined`) {\n throw `mutationFn is required when creating a transaction`\n }\n\n let transactionId = config.id\n if (!transactionId) {\n transactionId = crypto.randomUUID()\n }\n const newTransaction = new Transaction<TData>({\n ...config,\n id: transactionId,\n })\n\n transactions.push(newTransaction)\n\n return newTransaction\n}\n\nexport function getActiveTransaction(): Transaction | undefined {\n if (transactionStack.length > 0) {\n return transactionStack.slice(-1)[0]\n } else {\n return undefined\n }\n}\n\nfunction registerTransaction(tx: Transaction<any>) {\n transactionStack.push(tx)\n}\n\nfunction unregisterTransaction(tx: Transaction<any>) {\n transactionStack = transactionStack.filter((t) => t.id !== tx.id)\n}\n\nfunction removeFromPendingList(tx: Transaction<any>) {\n const index = transactions.findIndex((t) => t.id === tx.id)\n if (index !== -1) {\n transactions.splice(index, 1)\n }\n}\n\nexport class Transaction<T extends object = Record<string, unknown>> {\n public id: string\n public state: TransactionState\n public mutationFn: MutationFn<T>\n public mutations: Array<PendingMutation<T>>\n public isPersisted: Deferred<Transaction<T>>\n public autoCommit: boolean\n public createdAt: Date\n public metadata: Record<string, unknown>\n public error?: {\n message: string\n error: Error\n }\n\n constructor(config: TransactionConfig<T>) {\n this.id = config.id!\n this.mutationFn = config.mutationFn\n this.state = `pending`\n this.mutations = []\n this.isPersisted = createDeferred<Transaction<T>>()\n this.autoCommit = config.autoCommit ?? true\n this.createdAt = new Date()\n this.metadata = config.metadata ?? {}\n }\n\n setState(newState: TransactionState) {\n this.state = newState\n\n if (newState === `completed` || newState === `failed`) {\n removeFromPendingList(this)\n }\n }\n\n mutate(callback: () => void): Transaction<T> {\n if (this.state !== `pending`) {\n throw `You can no longer call .mutate() as the transaction is no longer pending`\n }\n\n registerTransaction(this)\n try {\n callback()\n } finally {\n unregisterTransaction(this)\n }\n\n if (this.autoCommit) {\n this.commit()\n }\n\n return this\n }\n\n applyMutations(mutations: Array<PendingMutation<any>>): void {\n for (const newMutation of mutations) {\n const existingIndex = this.mutations.findIndex(\n (m) => m.globalKey === newMutation.globalKey\n )\n\n if (existingIndex >= 0) {\n // Replace existing mutation\n this.mutations[existingIndex] = newMutation\n } else {\n // Insert new mutation\n this.mutations.push(newMutation)\n }\n }\n }\n\n rollback(config?: { isSecondaryRollback?: boolean }): Transaction<T> {\n const isSecondaryRollback = config?.isSecondaryRollback ?? false\n if (this.state === `completed`) {\n throw `You can no longer call .rollback() as the transaction is already completed`\n }\n\n this.setState(`failed`)\n\n // See if there's any other transactions w/ mutations on the same ids\n // and roll them back as well.\n if (!isSecondaryRollback) {\n const mutationIds = new Set()\n this.mutations.forEach((m) => mutationIds.add(m.globalKey))\n for (const t of transactions) {\n t.state === `pending` &&\n t.mutations.some((m) => mutationIds.has(m.globalKey)) &&\n t.rollback({ isSecondaryRollback: true })\n }\n }\n\n // Reject the promise\n this.isPersisted.reject(this.error?.error)\n this.touchCollection()\n\n return this\n }\n\n // Tell collection that something has changed with the transaction\n touchCollection(): void {\n const hasCalled = new Set()\n for (const mutation of this.mutations) {\n if (!hasCalled.has(mutation.collection.id)) {\n mutation.collection.onTransactionStateChange()\n mutation.collection.commitPendingTransactions()\n hasCalled.add(mutation.collection.id)\n }\n }\n }\n\n async commit(): Promise<Transaction<T>> {\n if (this.state !== `pending`) {\n throw `You can no longer call .commit() as the transaction is no longer pending`\n }\n\n this.setState(`persisting`)\n\n if (this.mutations.length === 0) {\n this.setState(`completed`)\n\n return this\n }\n\n // Run mutationFn\n try {\n // At this point we know there's at least one mutation\n // We've already verified mutations is non-empty, so this cast is safe\n // Use a direct type assertion instead of object spreading to preserve the original type\n await this.mutationFn({\n transaction: this as unknown as TransactionWithMutations<T>,\n })\n\n this.setState(`completed`)\n this.touchCollection()\n\n this.isPersisted.resolve(this)\n } catch (error) {\n // Update transaction with error information\n this.error = {\n message: error instanceof Error ? error.message : String(error),\n error: error instanceof Error ? error : new Error(String(error)),\n }\n\n // rollback the transaction\n return this.rollback()\n }\n\n return this\n }\n}\n"],"names":["createDeferred"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { Deferred } from './deferred.cjs';
2
2
  import { MutationFn, PendingMutation, TransactionConfig, TransactionState } from './types.cjs';
3
- export declare function createTransaction(config: TransactionConfig): Transaction;
3
+ export declare function createTransaction<TData extends object = Record<string, unknown>>(config: TransactionConfig<TData>): Transaction<TData>;
4
4
  export declare function getActiveTransaction(): Transaction | undefined;
5
5
  export declare class Transaction<T extends object = Record<string, unknown>> {
6
6
  id: string;
@@ -1,4 +1,4 @@
1
- import { IStreamBuilder } from '@electric-sql/d2ts';
1
+ import { IStreamBuilder } from '@electric-sql/d2mini';
2
2
  import { Collection } from './collection.cjs';
3
3
  import { StandardSchemaV1 } from '@standard-schema/spec';
4
4
  import { Transaction } from './transactions.cjs';
@@ -10,14 +10,10 @@ export declare class CompiledQuery<TResults extends object = Record<string, unkn
10
10
  private inputCollections;
11
11
  private resultCollection;
12
12
  state: `compiled` | `running` | `stopped`;
13
- private version;
14
13
  private unsubscribeCallbacks;
15
14
  constructor(queryBuilder: QueryBuilder<Context<Schema>>);
16
15
  get results(): Collection<TResults, string | number, {}>;
17
16
  private sendChangesToInput;
18
- private sendFrontierToInput;
19
- private sendFrontierToAllInputs;
20
- private incrementVersion;
21
17
  private runGraph;
22
18
  start(): () => void;
23
19
  stop(): void;
@@ -1,4 +1,4 @@
1
- import { D2, MultiSet, output, MessageType } from "@electric-sql/d2ts";
1
+ import { D2, MultiSet, output } from "@electric-sql/d2mini";
2
2
  import { createCollection } from "../collection.js";
3
3
  import { compileQueryPipeline } from "./pipeline-compiler.js";
4
4
  function compileQuery(queryBuilder) {
@@ -7,7 +7,6 @@ function compileQuery(queryBuilder) {
7
7
  class CompiledQuery {
8
8
  constructor(queryBuilder) {
9
9
  this.state = `compiled`;
10
- this.version = 0;
11
10
  this.unsubscribeCallbacks = [];
12
11
  const query = queryBuilder._query;
13
12
  const collections = query.collections;
@@ -15,7 +14,7 @@ class CompiledQuery {
15
14
  throw new Error(`No collections provided`);
16
15
  }
17
16
  this.inputCollections = collections;
18
- const graph = new D2({ initialFrontier: this.version });
17
+ const graph = new D2();
19
18
  const inputs = Object.fromEntries(
20
19
  Object.entries(collections).map(([key]) => [key, graph.newInput()])
21
20
  );
@@ -24,45 +23,43 @@ class CompiledQuery {
24
23
  query,
25
24
  inputs
26
25
  ).pipe(
27
- output(({ type, data }) => {
28
- if (type === MessageType.DATA) {
29
- begin();
30
- data.collection.getInner().reduce((acc, [[key, value], multiplicity]) => {
31
- const changes = acc.get(key) || {
32
- deletes: 0,
33
- inserts: 0,
34
- value
35
- };
36
- if (multiplicity < 0) {
37
- changes.deletes += Math.abs(multiplicity);
38
- } else if (multiplicity > 0) {
39
- changes.inserts += multiplicity;
40
- changes.value = value;
41
- }
42
- acc.set(key, changes);
43
- return acc;
44
- }, /* @__PURE__ */ new Map()).forEach((changes, rawKey) => {
45
- const { deletes, inserts, value } = changes;
46
- const valueWithKey = { ...value, _key: rawKey };
47
- if (inserts && !deletes) {
48
- write({
49
- value: valueWithKey,
50
- type: `insert`
51
- });
52
- } else if (inserts >= deletes) {
53
- write({
54
- value: valueWithKey,
55
- type: `update`
56
- });
57
- } else if (deletes > 0) {
58
- write({
59
- value: valueWithKey,
60
- type: `delete`
61
- });
62
- }
63
- });
64
- commit();
65
- }
26
+ output((data) => {
27
+ begin();
28
+ data.getInner().reduce((acc, [[key, value], multiplicity]) => {
29
+ const changes = acc.get(key) || {
30
+ deletes: 0,
31
+ inserts: 0,
32
+ value
33
+ };
34
+ if (multiplicity < 0) {
35
+ changes.deletes += Math.abs(multiplicity);
36
+ } else if (multiplicity > 0) {
37
+ changes.inserts += multiplicity;
38
+ changes.value = value;
39
+ }
40
+ acc.set(key, changes);
41
+ return acc;
42
+ }, /* @__PURE__ */ new Map()).forEach((changes, rawKey) => {
43
+ const { deletes, inserts, value } = changes;
44
+ const valueWithKey = { ...value, _key: rawKey };
45
+ if (inserts && !deletes) {
46
+ write({
47
+ value: valueWithKey,
48
+ type: `insert`
49
+ });
50
+ } else if (inserts >= deletes) {
51
+ write({
52
+ value: valueWithKey,
53
+ type: `update`
54
+ });
55
+ } else if (deletes > 0) {
56
+ write({
57
+ value: valueWithKey,
58
+ type: `delete`
59
+ });
60
+ }
61
+ });
62
+ commit();
66
63
  })
67
64
  );
68
65
  graph.finalize();
@@ -97,19 +94,7 @@ class CompiledQuery {
97
94
  multiSetArray.push([[key, change.value], -1]);
98
95
  }
99
96
  }
100
- input.sendData(this.version, new MultiSet(multiSetArray));
101
- }
102
- sendFrontierToInput(inputKey) {
103
- const input = this.inputs[inputKey];
104
- input.sendFrontier(this.version);
105
- }
106
- sendFrontierToAllInputs() {
107
- Object.entries(this.inputs).forEach(([key]) => {
108
- this.sendFrontierToInput(key);
109
- });
110
- }
111
- incrementVersion() {
112
- this.version++;
97
+ input.sendData(new MultiSet(multiSetArray));
113
98
  }
114
99
  runGraph() {
115
100
  this.graph.run();
@@ -127,14 +112,10 @@ class CompiledQuery {
127
112
  collection.config.getKey
128
113
  );
129
114
  });
130
- this.incrementVersion();
131
- this.sendFrontierToAllInputs();
132
115
  this.runGraph();
133
116
  Object.entries(this.inputCollections).forEach(([key, collection]) => {
134
117
  const unsubscribe = collection.subscribeChanges((changes) => {
135
118
  this.sendChangesToInput(key, changes, collection.config.getKey);
136
- this.incrementVersion();
137
- this.sendFrontierToAllInputs();
138
119
  this.runGraph();
139
120
  });
140
121
  this.unsubscribeCallbacks.push(unsubscribe);
@@ -1 +1 @@
1
- {"version":3,"file":"compiled-query.js","sources":["../../../src/query/compiled-query.ts"],"sourcesContent":["import { D2, MessageType, MultiSet, output } from \"@electric-sql/d2ts\"\nimport { createCollection } from \"../collection.js\"\nimport { compileQueryPipeline } from \"./pipeline-compiler.js\"\nimport type { Collection } from \"../collection.js\"\nimport type { ChangeMessage, SyncConfig } from \"../types.js\"\nimport type {\n IStreamBuilder,\n MultiSetArray,\n RootStreamBuilder,\n} from \"@electric-sql/d2ts\"\nimport type { QueryBuilder, ResultsFromContext } from \"./query-builder.js\"\nimport type { Context, Schema } from \"./types.js\"\n\nexport function compileQuery<TContext extends Context<Schema>>(\n queryBuilder: QueryBuilder<TContext>\n) {\n return new CompiledQuery<\n ResultsFromContext<TContext> & { _key?: string | number }\n >(queryBuilder)\n}\n\nexport class CompiledQuery<TResults extends object = Record<string, unknown>> {\n private graph: D2\n private inputs: Record<string, RootStreamBuilder<any>>\n private inputCollections: Record<string, Collection<any>>\n private resultCollection: Collection<TResults>\n public state: `compiled` | `running` | `stopped` = `compiled`\n private version = 0\n private unsubscribeCallbacks: Array<() => void> = []\n\n constructor(queryBuilder: QueryBuilder<Context<Schema>>) {\n const query = queryBuilder._query\n const collections = query.collections\n\n if (!collections) {\n throw new Error(`No collections provided`)\n }\n\n this.inputCollections = collections\n\n const graph = new D2({ initialFrontier: this.version })\n const inputs = Object.fromEntries(\n Object.entries(collections).map(([key]) => [key, graph.newInput<any>()])\n )\n\n const sync: SyncConfig<TResults>[`sync`] = ({ begin, write, commit }) => {\n compileQueryPipeline<IStreamBuilder<[unknown, TResults]>>(\n query,\n inputs\n ).pipe(\n output(({ type, data }) => {\n if (type === MessageType.DATA) {\n begin()\n data.collection\n .getInner()\n .reduce((acc, [[key, value], multiplicity]) => {\n const changes = acc.get(key) || {\n deletes: 0,\n inserts: 0,\n value,\n }\n if (multiplicity < 0) {\n changes.deletes += Math.abs(multiplicity)\n } else if (multiplicity > 0) {\n changes.inserts += multiplicity\n changes.value = value\n }\n acc.set(key, changes)\n return acc\n }, new Map<unknown, { deletes: number; inserts: number; value: TResults }>())\n .forEach((changes, rawKey) => {\n const { deletes, inserts, value } = changes\n const valueWithKey = { ...value, _key: rawKey }\n if (inserts && !deletes) {\n write({\n value: valueWithKey,\n type: `insert`,\n })\n } else if (inserts >= deletes) {\n write({\n value: valueWithKey,\n type: `update`,\n })\n } else if (deletes > 0) {\n write({\n value: valueWithKey,\n type: `delete`,\n })\n }\n })\n commit()\n }\n })\n )\n graph.finalize()\n }\n\n this.graph = graph\n this.inputs = inputs\n this.resultCollection = createCollection<TResults>({\n id: crypto.randomUUID(), // TODO: remove when we don't require any more\n getKey: (val: unknown) => {\n return (val as any)._key\n },\n sync: {\n sync,\n },\n })\n }\n\n get results() {\n return this.resultCollection\n }\n\n private sendChangesToInput(\n inputKey: string,\n changes: Array<ChangeMessage>,\n getKey: (item: ChangeMessage[`value`]) => any\n ) {\n const input = this.inputs[inputKey]!\n const multiSetArray: MultiSetArray<unknown> = []\n for (const change of changes) {\n const key = getKey(change.value)\n if (change.type === `insert`) {\n multiSetArray.push([[key, change.value], 1])\n } else if (change.type === `update`) {\n multiSetArray.push([[key, change.previousValue], -1])\n multiSetArray.push([[key, change.value], 1])\n } else {\n // change.type === `delete`\n multiSetArray.push([[key, change.value], -1])\n }\n }\n input.sendData(this.version, new MultiSet(multiSetArray))\n }\n\n private sendFrontierToInput(inputKey: string) {\n const input = this.inputs[inputKey]!\n input.sendFrontier(this.version)\n }\n\n private sendFrontierToAllInputs() {\n Object.entries(this.inputs).forEach(([key]) => {\n this.sendFrontierToInput(key)\n })\n }\n\n private incrementVersion() {\n this.version++\n }\n\n private runGraph() {\n this.graph.run()\n }\n\n start() {\n if (this.state === `running`) {\n throw new Error(`Query is already running`)\n } else if (this.state === `stopped`) {\n throw new Error(`Query is stopped`)\n }\n\n // Send initial state\n Object.entries(this.inputCollections).forEach(([key, collection]) => {\n this.sendChangesToInput(\n key,\n collection.currentStateAsChanges(),\n collection.config.getKey\n )\n })\n this.incrementVersion()\n this.sendFrontierToAllInputs()\n this.runGraph()\n\n // Subscribe to changes\n Object.entries(this.inputCollections).forEach(([key, collection]) => {\n const unsubscribe = collection.subscribeChanges((changes) => {\n this.sendChangesToInput(key, changes, collection.config.getKey)\n this.incrementVersion()\n this.sendFrontierToAllInputs()\n this.runGraph()\n })\n\n this.unsubscribeCallbacks.push(unsubscribe)\n })\n\n this.state = `running`\n return () => {\n this.stop()\n }\n }\n\n stop() {\n this.unsubscribeCallbacks.forEach((unsubscribe) => unsubscribe())\n this.unsubscribeCallbacks = []\n this.state = `stopped`\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compiled-query.js","sources":["../../../src/query/compiled-query.ts"],"sourcesContent":["import { D2, MultiSet, output } from \"@electric-sql/d2mini\"\nimport { createCollection } from \"../collection.js\"\nimport { compileQueryPipeline } from \"./pipeline-compiler.js\"\nimport type { Collection } from \"../collection.js\"\nimport type { ChangeMessage, SyncConfig } from \"../types.js\"\nimport type {\n IStreamBuilder,\n MultiSetArray,\n RootStreamBuilder,\n} from \"@electric-sql/d2mini\"\nimport type { QueryBuilder, ResultsFromContext } from \"./query-builder.js\"\nimport type { Context, Schema } from \"./types.js\"\n\nexport function compileQuery<TContext extends Context<Schema>>(\n queryBuilder: QueryBuilder<TContext>\n) {\n return new CompiledQuery<\n ResultsFromContext<TContext> & { _key?: string | number }\n >(queryBuilder)\n}\n\nexport class CompiledQuery<TResults extends object = Record<string, unknown>> {\n private graph: D2\n private inputs: Record<string, RootStreamBuilder<any>>\n private inputCollections: Record<string, Collection<any>>\n private resultCollection: Collection<TResults>\n public state: `compiled` | `running` | `stopped` = `compiled`\n private unsubscribeCallbacks: Array<() => void> = []\n\n constructor(queryBuilder: QueryBuilder<Context<Schema>>) {\n const query = queryBuilder._query\n const collections = query.collections\n\n if (!collections) {\n throw new Error(`No collections provided`)\n }\n\n this.inputCollections = collections\n\n const graph = new D2()\n const inputs = Object.fromEntries(\n Object.entries(collections).map(([key]) => [key, graph.newInput<any>()])\n )\n\n const sync: SyncConfig<TResults>[`sync`] = ({ begin, write, commit }) => {\n compileQueryPipeline<IStreamBuilder<[unknown, TResults]>>(\n query,\n inputs\n ).pipe(\n output((data) => {\n begin()\n data\n .getInner()\n .reduce((acc, [[key, value], multiplicity]) => {\n const changes = acc.get(key) || {\n deletes: 0,\n inserts: 0,\n value,\n }\n if (multiplicity < 0) {\n changes.deletes += Math.abs(multiplicity)\n } else if (multiplicity > 0) {\n changes.inserts += multiplicity\n changes.value = value\n }\n acc.set(key, changes)\n return acc\n }, new Map<unknown, { deletes: number; inserts: number; value: TResults }>())\n .forEach((changes, rawKey) => {\n const { deletes, inserts, value } = changes\n const valueWithKey = { ...value, _key: rawKey }\n if (inserts && !deletes) {\n write({\n value: valueWithKey,\n type: `insert`,\n })\n } else if (inserts >= deletes) {\n write({\n value: valueWithKey,\n type: `update`,\n })\n } else if (deletes > 0) {\n write({\n value: valueWithKey,\n type: `delete`,\n })\n }\n })\n commit()\n })\n )\n graph.finalize()\n }\n\n this.graph = graph\n this.inputs = inputs\n this.resultCollection = createCollection<TResults>({\n id: crypto.randomUUID(), // TODO: remove when we don't require any more\n getKey: (val: unknown) => {\n return (val as any)._key\n },\n sync: {\n sync,\n },\n })\n }\n\n get results() {\n return this.resultCollection\n }\n\n private sendChangesToInput(\n inputKey: string,\n changes: Array<ChangeMessage>,\n getKey: (item: ChangeMessage[`value`]) => any\n ) {\n const input = this.inputs[inputKey]!\n const multiSetArray: MultiSetArray<unknown> = []\n for (const change of changes) {\n const key = getKey(change.value)\n if (change.type === `insert`) {\n multiSetArray.push([[key, change.value], 1])\n } else if (change.type === `update`) {\n multiSetArray.push([[key, change.previousValue], -1])\n multiSetArray.push([[key, change.value], 1])\n } else {\n // change.type === `delete`\n multiSetArray.push([[key, change.value], -1])\n }\n }\n input.sendData(new MultiSet(multiSetArray))\n }\n\n private runGraph() {\n this.graph.run()\n }\n\n start() {\n if (this.state === `running`) {\n throw new Error(`Query is already running`)\n } else if (this.state === `stopped`) {\n throw new Error(`Query is stopped`)\n }\n\n // Send initial state\n Object.entries(this.inputCollections).forEach(([key, collection]) => {\n this.sendChangesToInput(\n key,\n collection.currentStateAsChanges(),\n collection.config.getKey\n )\n })\n this.runGraph()\n\n // Subscribe to changes\n Object.entries(this.inputCollections).forEach(([key, collection]) => {\n const unsubscribe = collection.subscribeChanges((changes) => {\n this.sendChangesToInput(key, changes, collection.config.getKey)\n this.runGraph()\n })\n\n this.unsubscribeCallbacks.push(unsubscribe)\n })\n\n this.state = `running`\n return () => {\n this.stop()\n }\n }\n\n stop() {\n this.unsubscribeCallbacks.forEach((unsubscribe) => unsubscribe())\n this.unsubscribeCallbacks = []\n this.state = `stopped`\n }\n}\n"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ export declare function getAggregateFunction(functionName: string, columnRef: st
12
12
  reduce: (values: [number, number][]) => number;
13
13
  postMap?: ((result: number) => number) | undefined;
14
14
  } | {
15
- pipe: (stream: import('@electric-sql/d2ts').IStreamBuilder<[string, Record<string, unknown>]>) => import('@electric-sql/d2ts').IStreamBuilder<import('@electric-sql/d2ts').KeyValue<string, number>>;
15
+ pipe: (stream: import('@electric-sql/d2mini').IStreamBuilder<[string, Record<string, unknown>]>) => import('@electric-sql/d2mini').IStreamBuilder<import('@electric-sql/d2mini').KeyValue<string, number>>;
16
16
  } | {
17
17
  preMap: (data: [string, Record<string, unknown>]) => {
18
18
  sum: number;
@@ -1,4 +1,4 @@
1
- import { groupBy, groupByOperators } from "@electric-sql/d2ts";
1
+ import { groupBy, groupByOperators } from "@electric-sql/d2mini";
2
2
  import { extractValueFromNamespacedRow, evaluateOperandOnNamespacedRow } from "./extractors.js";
3
3
  import { isAggregateFunctionCall } from "./utils.js";
4
4
  const { sum, count, avg, min, max, median, mode } = groupByOperators;
@@ -1 +1 @@
1
- {"version":3,"file":"group-by.js","sources":["../../../src/query/group-by.ts"],"sourcesContent":["import { groupBy, groupByOperators } from \"@electric-sql/d2ts\"\nimport {\n evaluateOperandOnNamespacedRow,\n extractValueFromNamespacedRow,\n} from \"./extractors\"\nimport { isAggregateFunctionCall } from \"./utils\"\nimport type { ConditionOperand, FunctionCall, Query } from \"./schema\"\nimport type { NamespacedAndKeyedStream } from \"../types.js\"\n\nconst { sum, count, avg, min, max, median, mode } = groupByOperators\n\n/**\n * Process the groupBy clause in a D2QL query\n */\nexport function processGroupBy(\n pipeline: NamespacedAndKeyedStream,\n query: Query,\n mainTableAlias: string\n) {\n // Normalize groupBy to an array of column references\n const groupByColumns = Array.isArray(query.groupBy)\n ? query.groupBy\n : [query.groupBy]\n\n // Create a key extractor function for the groupBy operator\n const keyExtractor = ([_oldKey, namespacedRow]: [\n string,\n Record<string, unknown>,\n ]) => {\n const key: Record<string, unknown> = {}\n\n // Extract each groupBy column value\n for (const column of groupByColumns) {\n if (typeof column === `string` && (column as string).startsWith(`@`)) {\n const columnRef = (column as string).substring(1)\n const columnName = columnRef.includes(`.`)\n ? columnRef.split(`.`)[1]\n : columnRef\n\n key[columnName!] = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef,\n mainTableAlias\n )\n }\n }\n\n return key\n }\n\n // Create aggregate functions for any aggregated columns in the SELECT clause\n const aggregates: Record<string, any> = {}\n\n if (!query.select) {\n throw new Error(`SELECT clause is required for GROUP BY`)\n }\n\n // Scan the SELECT clause for aggregate functions\n for (const item of query.select) {\n if (typeof item === `object`) {\n for (const [alias, expr] of Object.entries(item)) {\n if (typeof expr === `object` && isAggregateFunctionCall(expr)) {\n // Get the function name (the only key in the object)\n const functionName = Object.keys(expr)[0]\n // Get the column reference or expression to aggregate\n const columnRef = (expr as FunctionCall)[\n functionName as keyof FunctionCall\n ]\n\n // Add the aggregate function to our aggregates object\n aggregates[alias] = getAggregateFunction(\n functionName!,\n columnRef,\n mainTableAlias\n )\n }\n }\n }\n }\n\n // Apply the groupBy operator if we have any aggregates\n if (Object.keys(aggregates).length > 0) {\n pipeline = pipeline.pipe(groupBy(keyExtractor, aggregates))\n }\n\n return pipeline\n}\n\n/**\n * Helper function to get an aggregate function based on the function name\n */\nexport function getAggregateFunction(\n functionName: string,\n columnRef: string | ConditionOperand,\n mainTableAlias: string\n) {\n // Create a value extractor function for the column to aggregate\n const valueExtractor = ([_oldKey, namespacedRow]: [\n string,\n Record<string, unknown>,\n ]) => {\n let value: unknown\n if (typeof columnRef === `string` && columnRef.startsWith(`@`)) {\n value = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef.substring(1),\n mainTableAlias\n )\n } else {\n value = evaluateOperandOnNamespacedRow(\n namespacedRow,\n columnRef as ConditionOperand,\n mainTableAlias\n )\n }\n // Ensure we return a number for aggregate functions\n return typeof value === `number` ? value : 0\n }\n\n // Return the appropriate aggregate function\n switch (functionName.toUpperCase()) {\n case `SUM`:\n return sum(valueExtractor)\n case `COUNT`:\n return count() // count() doesn't need a value extractor\n case `AVG`:\n return avg(valueExtractor)\n case `MIN`:\n return min(valueExtractor)\n case `MAX`:\n return max(valueExtractor)\n case `MEDIAN`:\n return median(valueExtractor)\n case `MODE`:\n return mode(valueExtractor)\n default:\n throw new Error(`Unsupported aggregate function: ${functionName}`)\n }\n}\n"],"names":[],"mappings":";;;AASA,MAAM,EAAE,KAAK,OAAO,KAAK,KAAK,KAAK,QAAQ,SAAS;AAKpC,SAAA,eACd,UACA,OACA,gBACA;AAEM,QAAA,iBAAiB,MAAM,QAAQ,MAAM,OAAO,IAC9C,MAAM,UACN,CAAC,MAAM,OAAO;AAGlB,QAAM,eAAe,CAAC,CAAC,SAAS,aAAa,MAGvC;AACJ,UAAM,MAA+B,CAAC;AAGtC,eAAW,UAAU,gBAAgB;AACnC,UAAI,OAAO,WAAW,YAAa,OAAkB,WAAW,GAAG,GAAG;AAC9D,cAAA,YAAa,OAAkB,UAAU,CAAC;AAC1C,cAAA,aAAa,UAAU,SAAS,GAAG,IACrC,UAAU,MAAM,GAAG,EAAE,CAAC,IACtB;AAEJ,YAAI,UAAW,IAAI;AAAA,UACjB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MAAA;AAAA,IACF;AAGK,WAAA;AAAA,EACT;AAGA,QAAM,aAAkC,CAAC;AAErC,MAAA,CAAC,MAAM,QAAQ;AACX,UAAA,IAAI,MAAM,wCAAwC;AAAA,EAAA;AAI/C,aAAA,QAAQ,MAAM,QAAQ;AAC3B,QAAA,OAAO,SAAS,UAAU;AAC5B,iBAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,YAAI,OAAO,SAAS,YAAY,wBAAwB,IAAI,GAAG;AAE7D,gBAAM,eAAe,OAAO,KAAK,IAAI,EAAE,CAAC;AAElC,gBAAA,YAAa,KACjB,YACF;AAGA,qBAAW,KAAK,IAAI;AAAA,YAClB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAIF,MAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACtC,eAAW,SAAS,KAAK,QAAQ,cAAc,UAAU,CAAC;AAAA,EAAA;AAGrD,SAAA;AACT;AAKgB,SAAA,qBACd,cACA,WACA,gBACA;AAEA,QAAM,iBAAiB,CAAC,CAAC,SAAS,aAAa,MAGzC;AACA,QAAA;AACJ,QAAI,OAAO,cAAc,YAAY,UAAU,WAAW,GAAG,GAAG;AACtD,cAAA;AAAA,QACN;AAAA,QACA,UAAU,UAAU,CAAC;AAAA,QACrB;AAAA,MACF;AAAA,IAAA,OACK;AACG,cAAA;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IAAA;AAGK,WAAA,OAAO,UAAU,WAAW,QAAQ;AAAA,EAC7C;AAGQ,UAAA,aAAa,YAAe,GAAA;AAAA,IAClC,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,MAAM;AAAA;AAAA,IACf,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,OAAO,cAAc;AAAA,IAC9B,KAAK;AACH,aAAO,KAAK,cAAc;AAAA,IAC5B;AACE,YAAM,IAAI,MAAM,mCAAmC,YAAY,EAAE;AAAA,EAAA;AAEvE;"}
1
+ {"version":3,"file":"group-by.js","sources":["../../../src/query/group-by.ts"],"sourcesContent":["import { groupBy, groupByOperators } from \"@electric-sql/d2mini\"\nimport {\n evaluateOperandOnNamespacedRow,\n extractValueFromNamespacedRow,\n} from \"./extractors\"\nimport { isAggregateFunctionCall } from \"./utils\"\nimport type { ConditionOperand, FunctionCall, Query } from \"./schema\"\nimport type { NamespacedAndKeyedStream } from \"../types.js\"\n\nconst { sum, count, avg, min, max, median, mode } = groupByOperators\n\n/**\n * Process the groupBy clause in a D2QL query\n */\nexport function processGroupBy(\n pipeline: NamespacedAndKeyedStream,\n query: Query,\n mainTableAlias: string\n) {\n // Normalize groupBy to an array of column references\n const groupByColumns = Array.isArray(query.groupBy)\n ? query.groupBy\n : [query.groupBy]\n\n // Create a key extractor function for the groupBy operator\n const keyExtractor = ([_oldKey, namespacedRow]: [\n string,\n Record<string, unknown>,\n ]) => {\n const key: Record<string, unknown> = {}\n\n // Extract each groupBy column value\n for (const column of groupByColumns) {\n if (typeof column === `string` && (column as string).startsWith(`@`)) {\n const columnRef = (column as string).substring(1)\n const columnName = columnRef.includes(`.`)\n ? columnRef.split(`.`)[1]\n : columnRef\n\n key[columnName!] = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef,\n mainTableAlias\n )\n }\n }\n\n return key\n }\n\n // Create aggregate functions for any aggregated columns in the SELECT clause\n const aggregates: Record<string, any> = {}\n\n if (!query.select) {\n throw new Error(`SELECT clause is required for GROUP BY`)\n }\n\n // Scan the SELECT clause for aggregate functions\n for (const item of query.select) {\n if (typeof item === `object`) {\n for (const [alias, expr] of Object.entries(item)) {\n if (typeof expr === `object` && isAggregateFunctionCall(expr)) {\n // Get the function name (the only key in the object)\n const functionName = Object.keys(expr)[0]\n // Get the column reference or expression to aggregate\n const columnRef = (expr as FunctionCall)[\n functionName as keyof FunctionCall\n ]\n\n // Add the aggregate function to our aggregates object\n aggregates[alias] = getAggregateFunction(\n functionName!,\n columnRef,\n mainTableAlias\n )\n }\n }\n }\n }\n\n // Apply the groupBy operator if we have any aggregates\n if (Object.keys(aggregates).length > 0) {\n pipeline = pipeline.pipe(groupBy(keyExtractor, aggregates))\n }\n\n return pipeline\n}\n\n/**\n * Helper function to get an aggregate function based on the function name\n */\nexport function getAggregateFunction(\n functionName: string,\n columnRef: string | ConditionOperand,\n mainTableAlias: string\n) {\n // Create a value extractor function for the column to aggregate\n const valueExtractor = ([_oldKey, namespacedRow]: [\n string,\n Record<string, unknown>,\n ]) => {\n let value: unknown\n if (typeof columnRef === `string` && columnRef.startsWith(`@`)) {\n value = extractValueFromNamespacedRow(\n namespacedRow,\n columnRef.substring(1),\n mainTableAlias\n )\n } else {\n value = evaluateOperandOnNamespacedRow(\n namespacedRow,\n columnRef as ConditionOperand,\n mainTableAlias\n )\n }\n // Ensure we return a number for aggregate functions\n return typeof value === `number` ? value : 0\n }\n\n // Return the appropriate aggregate function\n switch (functionName.toUpperCase()) {\n case `SUM`:\n return sum(valueExtractor)\n case `COUNT`:\n return count() // count() doesn't need a value extractor\n case `AVG`:\n return avg(valueExtractor)\n case `MIN`:\n return min(valueExtractor)\n case `MAX`:\n return max(valueExtractor)\n case `MEDIAN`:\n return median(valueExtractor)\n case `MODE`:\n return mode(valueExtractor)\n default:\n throw new Error(`Unsupported aggregate function: ${functionName}`)\n }\n}\n"],"names":[],"mappings":";;;AASA,MAAM,EAAE,KAAK,OAAO,KAAK,KAAK,KAAK,QAAQ,SAAS;AAKpC,SAAA,eACd,UACA,OACA,gBACA;AAEM,QAAA,iBAAiB,MAAM,QAAQ,MAAM,OAAO,IAC9C,MAAM,UACN,CAAC,MAAM,OAAO;AAGlB,QAAM,eAAe,CAAC,CAAC,SAAS,aAAa,MAGvC;AACJ,UAAM,MAA+B,CAAC;AAGtC,eAAW,UAAU,gBAAgB;AACnC,UAAI,OAAO,WAAW,YAAa,OAAkB,WAAW,GAAG,GAAG;AAC9D,cAAA,YAAa,OAAkB,UAAU,CAAC;AAC1C,cAAA,aAAa,UAAU,SAAS,GAAG,IACrC,UAAU,MAAM,GAAG,EAAE,CAAC,IACtB;AAEJ,YAAI,UAAW,IAAI;AAAA,UACjB;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,MAAA;AAAA,IACF;AAGK,WAAA;AAAA,EACT;AAGA,QAAM,aAAkC,CAAC;AAErC,MAAA,CAAC,MAAM,QAAQ;AACX,UAAA,IAAI,MAAM,wCAAwC;AAAA,EAAA;AAI/C,aAAA,QAAQ,MAAM,QAAQ;AAC3B,QAAA,OAAO,SAAS,UAAU;AAC5B,iBAAW,CAAC,OAAO,IAAI,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,YAAI,OAAO,SAAS,YAAY,wBAAwB,IAAI,GAAG;AAE7D,gBAAM,eAAe,OAAO,KAAK,IAAI,EAAE,CAAC;AAElC,gBAAA,YAAa,KACjB,YACF;AAGA,qBAAW,KAAK,IAAI;AAAA,YAClB;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAIF,MAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACtC,eAAW,SAAS,KAAK,QAAQ,cAAc,UAAU,CAAC;AAAA,EAAA;AAGrD,SAAA;AACT;AAKgB,SAAA,qBACd,cACA,WACA,gBACA;AAEA,QAAM,iBAAiB,CAAC,CAAC,SAAS,aAAa,MAGzC;AACA,QAAA;AACJ,QAAI,OAAO,cAAc,YAAY,UAAU,WAAW,GAAG,GAAG;AACtD,cAAA;AAAA,QACN;AAAA,QACA,UAAU,UAAU,CAAC;AAAA,QACrB;AAAA,MACF;AAAA,IAAA,OACK;AACG,cAAA;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IAAA;AAGK,WAAA,OAAO,UAAU,WAAW,QAAQ;AAAA,EAC7C;AAGQ,UAAA,aAAa,YAAe,GAAA;AAAA,IAClC,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,MAAM;AAAA;AAAA,IACf,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AACH,aAAO,OAAO,cAAc;AAAA,IAC9B,KAAK;AACH,aAAO,KAAK,cAAc;AAAA,IAC5B;AACE,YAAM,IAAI,MAAM,mCAAmC,YAAY,EAAE;AAAA,EAAA;AAEvE;"}
@@ -1,5 +1,5 @@
1
1
  import { Query } from './index.js';
2
- import { IStreamBuilder } from '@electric-sql/d2ts';
2
+ import { IStreamBuilder } from '@electric-sql/d2mini';
3
3
  import { KeyedStream, NamespacedAndKeyedStream, NamespacedRow } from '../types.js';
4
4
  /**
5
5
  * Creates a processing pipeline for join clauses
@@ -1,4 +1,4 @@
1
- import { map, join, consolidate, filter } from "@electric-sql/d2ts";
1
+ import { map, join, consolidate, filter } from "@electric-sql/d2mini";
2
2
  import { evaluateConditionOnNamespacedRow } from "./evaluators.js";
3
3
  import { extractJoinKey } from "./extractors.js";
4
4
  function processJoinClause(pipeline, query, tables, mainTableAlias, allInputs) {
@@ -1 +1 @@
1
- {"version":3,"file":"joins.js","sources":["../../../src/query/joins.ts"],"sourcesContent":["import {\n consolidate,\n filter,\n join as joinOperator,\n map,\n} from \"@electric-sql/d2ts\"\nimport { evaluateConditionOnNamespacedRow } from \"./evaluators.js\"\nimport { extractJoinKey } from \"./extractors.js\"\nimport type { Query } from \"./index.js\"\nimport type { IStreamBuilder, JoinType } from \"@electric-sql/d2ts\"\nimport type {\n KeyedStream,\n NamespacedAndKeyedStream,\n NamespacedRow,\n} from \"../types.js\"\n\n/**\n * Creates a processing pipeline for join clauses\n */\nexport function processJoinClause(\n pipeline: NamespacedAndKeyedStream,\n query: Query,\n tables: Record<string, KeyedStream>,\n mainTableAlias: string,\n allInputs: Record<string, KeyedStream>\n) {\n if (!query.join) return pipeline\n const input = allInputs[query.from]\n\n for (const joinClause of query.join) {\n // Create a stream for the joined table\n const joinedTableAlias = joinClause.as || joinClause.from\n\n // Get the right join type for the operator\n const joinType: JoinType =\n joinClause.type === `cross` ? `inner` : joinClause.type\n\n // The `in` is formatted as ['@mainKeyRef', '=', '@joinedKeyRef']\n // Destructure the main key reference and the joined key references\n const [mainKeyRef, , joinedKeyRefs] = joinClause.on\n\n // We need to prepare the main pipeline and the joined pipeline\n // to have the correct key format for joining\n const mainPipeline = pipeline.pipe(\n map(([currentKey, namespacedRow]) => {\n // Extract the key from the ON condition left side for the main table\n const mainRow = namespacedRow[mainTableAlias]!\n\n // Extract the join key from the main row\n const key = extractJoinKey(mainRow, mainKeyRef, mainTableAlias)\n\n // Return [key, namespacedRow] as a KeyValue type\n return [key, [currentKey, namespacedRow]] as [\n unknown,\n [string, typeof namespacedRow],\n ]\n })\n )\n\n // Get the joined table input from the inputs map\n let joinedTableInput: KeyedStream\n\n if (allInputs[joinClause.from]) {\n // Use the provided input if available\n joinedTableInput = allInputs[joinClause.from]!\n } else {\n // Create a new input if not provided\n joinedTableInput =\n input!.graph.newInput<[string, Record<string, unknown>]>()\n }\n\n tables[joinedTableAlias] = joinedTableInput\n\n // Create a pipeline for the joined table\n const joinedPipeline = joinedTableInput.pipe(\n map(([currentKey, row]) => {\n // Wrap the row in an object with the table alias as the key\n const namespacedRow: NamespacedRow = { [joinedTableAlias]: row }\n\n // Extract the key from the ON condition right side for the joined table\n const key = extractJoinKey(row, joinedKeyRefs, joinedTableAlias)\n\n // Return [key, namespacedRow] as a KeyValue type\n return [key, [currentKey, namespacedRow]] as [\n string,\n [string, typeof namespacedRow],\n ]\n })\n )\n\n // Apply join with appropriate typings based on join type\n switch (joinType) {\n case `inner`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `inner`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n case `left`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `left`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n case `right`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `right`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n case `full`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `full`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n default:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `inner`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n }\n }\n return pipeline\n}\n\n/**\n * Creates a processing pipeline for join results\n */\nexport function processJoinResults(\n mainTableAlias: string,\n joinedTableAlias: string,\n joinClause: { on: any; type: string }\n) {\n return function (\n pipeline: IStreamBuilder<\n [\n key: string,\n [\n [string, NamespacedRow] | undefined,\n [string, NamespacedRow] | undefined,\n ],\n ]\n >\n ): NamespacedAndKeyedStream {\n return pipeline.pipe(\n // Process the join result and handle nulls in the same step\n map((result) => {\n const [_key, [main, joined]] = result\n const mainKey = main?.[0]\n const mainNamespacedRow = main?.[1]\n const joinedKey = joined?.[0]\n const joinedNamespacedRow = joined?.[1]\n\n // For inner joins, both sides should be non-null\n if (joinClause.type === `inner` || joinClause.type === `cross`) {\n if (!mainNamespacedRow || !joinedNamespacedRow) {\n return undefined // Will be filtered out\n }\n }\n\n // For left joins, the main row must be non-null\n if (joinClause.type === `left` && !mainNamespacedRow) {\n return undefined // Will be filtered out\n }\n\n // For right joins, the joined row must be non-null\n if (joinClause.type === `right` && !joinedNamespacedRow) {\n return undefined // Will be filtered out\n }\n\n // Merge the nested rows\n const mergedNamespacedRow: NamespacedRow = {}\n\n // Add main row data if it exists\n if (mainNamespacedRow) {\n Object.entries(mainNamespacedRow).forEach(\n ([tableAlias, tableData]) => {\n mergedNamespacedRow[tableAlias] = tableData\n }\n )\n }\n\n // If we have a joined row, add it to the merged result\n if (joinedNamespacedRow) {\n Object.entries(joinedNamespacedRow).forEach(\n ([tableAlias, tableData]) => {\n mergedNamespacedRow[tableAlias] = tableData\n }\n )\n } else if (joinClause.type === `left` || joinClause.type === `full`) {\n // For left or full joins, add the joined table with undefined data if missing\n // mergedNamespacedRow[joinedTableAlias] = undefined\n }\n\n // For right or full joins, add the main table with undefined data if missing\n if (\n !mainNamespacedRow &&\n (joinClause.type === `right` || joinClause.type === `full`)\n ) {\n // mergedNamespacedRow[mainTableAlias] = undefined\n }\n\n // New key\n const newKey = `[${mainKey},${joinedKey}]`\n\n return [newKey, mergedNamespacedRow] as [\n string,\n typeof mergedNamespacedRow,\n ]\n }),\n // Filter out undefined results\n filter((value) => value !== undefined),\n // Process the ON condition\n filter(([_key, namespacedRow]: [string, NamespacedRow]) => {\n // If there's no ON condition, or it's a cross join, always return true\n if (!joinClause.on || joinClause.type === `cross`) {\n return true\n }\n\n // For LEFT JOIN, if the right side is null, we should include the row\n if (\n joinClause.type === `left` &&\n namespacedRow[joinedTableAlias] === undefined\n ) {\n return true\n }\n\n // For RIGHT JOIN, if the left side is null, we should include the row\n if (\n joinClause.type === `right` &&\n namespacedRow[mainTableAlias] === undefined\n ) {\n return true\n }\n\n // For FULL JOIN, if either side is null, we should include the row\n if (\n joinClause.type === `full` &&\n (namespacedRow[mainTableAlias] === undefined ||\n namespacedRow[joinedTableAlias] === undefined)\n ) {\n return true\n }\n\n return evaluateConditionOnNamespacedRow(\n namespacedRow,\n joinClause.on,\n mainTableAlias,\n joinedTableAlias\n )\n })\n )\n }\n}\n"],"names":["joinOperator"],"mappings":"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"}
1
+ {"version":3,"file":"joins.js","sources":["../../../src/query/joins.ts"],"sourcesContent":["import {\n consolidate,\n filter,\n join as joinOperator,\n map,\n} from \"@electric-sql/d2mini\"\nimport { evaluateConditionOnNamespacedRow } from \"./evaluators.js\"\nimport { extractJoinKey } from \"./extractors.js\"\nimport type { Query } from \"./index.js\"\nimport type { IStreamBuilder, JoinType } from \"@electric-sql/d2mini\"\nimport type {\n KeyedStream,\n NamespacedAndKeyedStream,\n NamespacedRow,\n} from \"../types.js\"\n\n/**\n * Creates a processing pipeline for join clauses\n */\nexport function processJoinClause(\n pipeline: NamespacedAndKeyedStream,\n query: Query,\n tables: Record<string, KeyedStream>,\n mainTableAlias: string,\n allInputs: Record<string, KeyedStream>\n) {\n if (!query.join) return pipeline\n const input = allInputs[query.from]\n\n for (const joinClause of query.join) {\n // Create a stream for the joined table\n const joinedTableAlias = joinClause.as || joinClause.from\n\n // Get the right join type for the operator\n const joinType: JoinType =\n joinClause.type === `cross` ? `inner` : joinClause.type\n\n // The `in` is formatted as ['@mainKeyRef', '=', '@joinedKeyRef']\n // Destructure the main key reference and the joined key references\n const [mainKeyRef, , joinedKeyRefs] = joinClause.on\n\n // We need to prepare the main pipeline and the joined pipeline\n // to have the correct key format for joining\n const mainPipeline = pipeline.pipe(\n map(([currentKey, namespacedRow]) => {\n // Extract the key from the ON condition left side for the main table\n const mainRow = namespacedRow[mainTableAlias]!\n\n // Extract the join key from the main row\n const key = extractJoinKey(mainRow, mainKeyRef, mainTableAlias)\n\n // Return [key, namespacedRow] as a KeyValue type\n return [key, [currentKey, namespacedRow]] as [\n unknown,\n [string, typeof namespacedRow],\n ]\n })\n )\n\n // Get the joined table input from the inputs map\n let joinedTableInput: KeyedStream\n\n if (allInputs[joinClause.from]) {\n // Use the provided input if available\n joinedTableInput = allInputs[joinClause.from]!\n } else {\n // Create a new input if not provided\n joinedTableInput =\n input!.graph.newInput<[string, Record<string, unknown>]>()\n }\n\n tables[joinedTableAlias] = joinedTableInput\n\n // Create a pipeline for the joined table\n const joinedPipeline = joinedTableInput.pipe(\n map(([currentKey, row]) => {\n // Wrap the row in an object with the table alias as the key\n const namespacedRow: NamespacedRow = { [joinedTableAlias]: row }\n\n // Extract the key from the ON condition right side for the joined table\n const key = extractJoinKey(row, joinedKeyRefs, joinedTableAlias)\n\n // Return [key, namespacedRow] as a KeyValue type\n return [key, [currentKey, namespacedRow]] as [\n string,\n [string, typeof namespacedRow],\n ]\n })\n )\n\n // Apply join with appropriate typings based on join type\n switch (joinType) {\n case `inner`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `inner`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n case `left`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `left`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n case `right`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `right`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n case `full`:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `full`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n break\n default:\n pipeline = mainPipeline.pipe(\n joinOperator(joinedPipeline, `inner`),\n consolidate(),\n processJoinResults(mainTableAlias, joinedTableAlias, joinClause)\n )\n }\n }\n return pipeline\n}\n\n/**\n * Creates a processing pipeline for join results\n */\nexport function processJoinResults(\n mainTableAlias: string,\n joinedTableAlias: string,\n joinClause: { on: any; type: string }\n) {\n return function (\n pipeline: IStreamBuilder<\n [\n key: string,\n [\n [string, NamespacedRow] | undefined,\n [string, NamespacedRow] | undefined,\n ],\n ]\n >\n ): NamespacedAndKeyedStream {\n return pipeline.pipe(\n // Process the join result and handle nulls in the same step\n map((result) => {\n const [_key, [main, joined]] = result\n const mainKey = main?.[0]\n const mainNamespacedRow = main?.[1]\n const joinedKey = joined?.[0]\n const joinedNamespacedRow = joined?.[1]\n\n // For inner joins, both sides should be non-null\n if (joinClause.type === `inner` || joinClause.type === `cross`) {\n if (!mainNamespacedRow || !joinedNamespacedRow) {\n return undefined // Will be filtered out\n }\n }\n\n // For left joins, the main row must be non-null\n if (joinClause.type === `left` && !mainNamespacedRow) {\n return undefined // Will be filtered out\n }\n\n // For right joins, the joined row must be non-null\n if (joinClause.type === `right` && !joinedNamespacedRow) {\n return undefined // Will be filtered out\n }\n\n // Merge the nested rows\n const mergedNamespacedRow: NamespacedRow = {}\n\n // Add main row data if it exists\n if (mainNamespacedRow) {\n Object.entries(mainNamespacedRow).forEach(\n ([tableAlias, tableData]) => {\n mergedNamespacedRow[tableAlias] = tableData\n }\n )\n }\n\n // If we have a joined row, add it to the merged result\n if (joinedNamespacedRow) {\n Object.entries(joinedNamespacedRow).forEach(\n ([tableAlias, tableData]) => {\n mergedNamespacedRow[tableAlias] = tableData\n }\n )\n } else if (joinClause.type === `left` || joinClause.type === `full`) {\n // For left or full joins, add the joined table with undefined data if missing\n // mergedNamespacedRow[joinedTableAlias] = undefined\n }\n\n // For right or full joins, add the main table with undefined data if missing\n if (\n !mainNamespacedRow &&\n (joinClause.type === `right` || joinClause.type === `full`)\n ) {\n // mergedNamespacedRow[mainTableAlias] = undefined\n }\n\n // New key\n const newKey = `[${mainKey},${joinedKey}]`\n\n return [newKey, mergedNamespacedRow] as [\n string,\n typeof mergedNamespacedRow,\n ]\n }),\n // Filter out undefined results\n filter((value) => value !== undefined),\n // Process the ON condition\n filter(([_key, namespacedRow]: [string, NamespacedRow]) => {\n // If there's no ON condition, or it's a cross join, always return true\n if (!joinClause.on || joinClause.type === `cross`) {\n return true\n }\n\n // For LEFT JOIN, if the right side is null, we should include the row\n if (\n joinClause.type === `left` &&\n namespacedRow[joinedTableAlias] === undefined\n ) {\n return true\n }\n\n // For RIGHT JOIN, if the left side is null, we should include the row\n if (\n joinClause.type === `right` &&\n namespacedRow[mainTableAlias] === undefined\n ) {\n return true\n }\n\n // For FULL JOIN, if either side is null, we should include the row\n if (\n joinClause.type === `full` &&\n (namespacedRow[mainTableAlias] === undefined ||\n namespacedRow[joinedTableAlias] === undefined)\n ) {\n return true\n }\n\n return evaluateConditionOnNamespacedRow(\n namespacedRow,\n joinClause.on,\n mainTableAlias,\n joinedTableAlias\n )\n })\n )\n }\n}\n"],"names":["joinOperator"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { orderByWithIndex, map, orderByWithFractionalIndex, orderBy } from "@electric-sql/d2ts";
1
+ import { orderByWithIndex, map, orderByWithFractionalIndex, orderBy } from "@electric-sql/d2mini";
2
2
  import { evaluateOperandOnNamespacedRow } from "./extractors.js";
3
3
  import { isOrderIndexFunctionCall } from "./utils.js";
4
4
  function processOrderBy(resultPipeline, query, mainTableAlias) {