@snowtop/ent 0.2.7 → 0.2.9

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 (61) hide show
  1. package/action/executor.js +4 -4
  2. package/action/operations.js +3 -0
  3. package/action/orchestrator.js +10 -12
  4. package/action/topological_sort.d.ts +9 -0
  5. package/action/topological_sort.js +46 -0
  6. package/core/base.d.ts +11 -4
  7. package/core/clause.d.ts +3 -5
  8. package/core/clause.js +32 -0
  9. package/core/config.d.ts +26 -2
  10. package/core/config.js +7 -1
  11. package/core/context.js +5 -12
  12. package/core/db.d.ts +12 -2
  13. package/core/db.js +102 -7
  14. package/core/dev_schema.d.ts +9 -0
  15. package/core/dev_schema.js +306 -0
  16. package/core/ent.d.ts +3 -5
  17. package/core/ent.js +22 -7
  18. package/core/extensions.d.ts +25 -0
  19. package/core/extensions.js +220 -0
  20. package/core/loaders/assoc_count_loader.js +2 -5
  21. package/core/loaders/assoc_edge_loader.js +5 -8
  22. package/core/loaders/loader.js +1 -1
  23. package/core/loaders/object_loader.js +3 -6
  24. package/core/loaders/query_loader.d.ts +2 -5
  25. package/core/loaders/query_loader.js +11 -10
  26. package/core/memoize.d.ts +1 -0
  27. package/core/memoize.js +15 -0
  28. package/core/query/custom_clause_query.js +5 -1
  29. package/core/query/query.d.ts +1 -1
  30. package/core/query/query.js +10 -7
  31. package/core/query_expression.d.ts +6 -0
  32. package/core/query_expression.js +2 -0
  33. package/core/query_impl.d.ts +19 -3
  34. package/core/query_impl.js +148 -35
  35. package/index.d.ts +5 -1
  36. package/index.js +9 -2
  37. package/package.json +1 -7
  38. package/parse_schema/parse.d.ts +2 -12
  39. package/parse_schema/parse.js +22 -41
  40. package/schema/index.d.ts +1 -1
  41. package/schema/schema.d.ts +20 -1
  42. package/scripts/custom_graphql.js +12 -5
  43. package/scripts/fix_action_exports.js +1 -1
  44. package/scripts/migrate_v0.1.js +2 -5
  45. package/scripts/move_types.js +1 -1
  46. package/scripts/parse_args.d.ts +3 -0
  47. package/scripts/parse_args.js +74 -0
  48. package/scripts/read_schema.js +2 -5
  49. package/testutils/builder.js +1 -2
  50. package/testutils/parse_sql.js +1 -1
  51. package/tsc/compilerOptions.d.ts +2 -2
  52. package/tsc/compilerOptions.js +12 -18
  53. package/tsc/move_generated.js +2 -2
  54. package/tsc/transform.d.ts +1 -1
  55. package/tsc/transform.js +16 -2
  56. package/tsc/transform_action.d.ts +1 -1
  57. package/tsc/transform_action.js +1 -1
  58. package/tsc/transform_ent.d.ts +1 -1
  59. package/tsc/transform_ent.js +1 -1
  60. package/tsc/transform_schema.d.ts +1 -1
  61. package/tsc/transform_schema.js +2 -2
@@ -32,15 +32,12 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.AssocEdgeLoaderFactory = exports.AssocDirectEdgeLoader = exports.AssocEdgeLoader = void 0;
40
- const memoizee_1 = __importDefault(require("memoizee"));
41
37
  const clause = __importStar(require("../clause"));
42
38
  const ent_1 = require("../ent");
43
- const cache_utils_1 = require("../cache_utils");
39
+ const memoize_1 = require("../memoize");
40
+ const query_impl_1 = require("../query_impl");
44
41
  const loader_1 = require("./loader");
45
42
  function getDefaultOrderBy() {
46
43
  return [
@@ -121,7 +118,7 @@ class AssocEdgeLoader {
121
118
  this.edgeCtr = edgeCtr;
122
119
  this.options = options;
123
120
  this.context = context;
124
- this.loaderFn = (0, memoizee_1.default)(this.getLoader);
121
+ this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
125
122
  }
126
123
  async getLoader() {
127
124
  const edgeData = await (0, ent_1.loadEdgeData)(this.edgeType);
@@ -167,7 +164,7 @@ class AssocDirectEdgeLoader {
167
164
  this.options = options;
168
165
  this.context = context;
169
166
  if (this.context) {
170
- this.loaderFn = (0, memoizee_1.default)(this.getLoader);
167
+ this.loaderFn = (0, memoize_1.memoizeNoArgs)(this.getLoader.bind(this));
171
168
  }
172
169
  }
173
170
  async getLoader() {
@@ -264,7 +261,7 @@ class AssocEdgeLoaderFactory {
264
261
  return new AssocDirectEdgeLoader(this.edgeType, edgeCtr, options, context);
265
262
  }
266
263
  const effectiveOptions = getEffectiveOptions(options);
267
- const key = `${this.name}:limit:${effectiveOptions.limit}:orderby:${(0, cache_utils_1.stableStringify)(effectiveOptions.orderby)}:disableTransformations:${effectiveOptions.disableTransformations}`;
264
+ const key = `${this.name}:limit:${effectiveOptions.limit}:orderby:${(0, query_impl_1.getOrderByKey)(effectiveOptions.orderby ?? getDefaultOrderBy())}:disableTransformations:${effectiveOptions.disableTransformations}`;
268
265
  return (0, loader_1.getCustomLoader)(key, () => new AssocEdgeLoader(this.edgeType, ctr, effectiveOptions, context), context);
269
266
  }
270
267
  }
@@ -195,7 +195,7 @@ class CacheMap {
195
195
  // was designed for ObjectLoader time. Now we have different needs e.g. count, assoc etc
196
196
  (0, logger_1.log)("cache", {
197
197
  "dataloader-cache-hit": key,
198
- "tableName": this.options.tableName,
198
+ tableName: this.options.tableName,
199
199
  });
200
200
  }
201
201
  return ret;
@@ -32,9 +32,6 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.ObjectLoaderFactory = exports.ObjectCountLoader = exports.ObjectLoader = exports.mapWithConcurrency = void 0;
40
37
  exports.setClauseLoaderConcurrency = setClauseLoaderConcurrency;
@@ -45,7 +42,7 @@ const clause = __importStar(require("../clause"));
45
42
  const logger_1 = require("../logger");
46
43
  const clause_1 = require("../clause");
47
44
  const loader_1 = require("./loader");
48
- const memoizee_1 = __importDefault(require("memoizee"));
45
+ const memoize_1 = require("../memoize");
49
46
  const DEFAULT_CLAUSE_LOADER_CONCURRENCY = 10;
50
47
  let clauseLoaderConcurrency = DEFAULT_CLAUSE_LOADER_CONCURRENCY;
51
48
  function setClauseLoaderConcurrency(limit) {
@@ -151,7 +148,7 @@ class clauseCacheMap {
151
148
  if (ret) {
152
149
  (0, logger_1.log)("cache", {
153
150
  "dataloader-cache-hit": key2 + (this.count ? ":count" : ""),
154
- "tableName": this.options.tableName,
151
+ tableName: this.options.tableName,
155
152
  });
156
153
  }
157
154
  return ret;
@@ -205,7 +202,7 @@ class ObjectLoader {
205
202
  this.idLoader = createDataLoader(options, context);
206
203
  this.clauseLoader = createClauseDataLoder(options, context);
207
204
  }
208
- this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
205
+ this.memoizedInitPrime = (0, memoize_1.memoizeNoArgs)(this.initPrime.bind(this));
209
206
  }
210
207
  getOptions() {
211
208
  return this.options;
@@ -1,4 +1,4 @@
1
- import { Context, Data, EdgeQueryableDataOptions, Loader, LoaderFactory } from "../base";
1
+ import { Context, Data, EdgeQueryableDataOptions, Loader, LoaderFactory, SelectBaseDataOptions } from "../base";
2
2
  import * as clause from "../clause";
3
3
  import { OrderBy } from "../query_impl";
4
4
  import { ObjectLoaderFactory } from "./object_loader";
@@ -14,10 +14,7 @@ declare class QueryDirectLoader<K extends any> implements Loader<K, Data[]> {
14
14
  clearAll(): void;
15
15
  }
16
16
  interface QueryOptions {
17
- fields: (string | {
18
- alias: string;
19
- column: string;
20
- })[];
17
+ fields: SelectBaseDataOptions["fields"];
21
18
  tableName: string;
22
19
  groupCol?: string;
23
20
  clause?: clause.Clause;
@@ -32,15 +32,12 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.QueryLoaderFactory = void 0;
40
- const memoizee_1 = __importDefault(require("memoizee"));
41
37
  const clause = __importStar(require("../clause"));
42
38
  const ent_1 = require("../ent");
43
- const cache_utils_1 = require("../cache_utils");
39
+ const memoize_1 = require("../memoize");
40
+ const query_impl_1 = require("../query_impl");
44
41
  const loader_1 = require("./loader");
45
42
  function getOrderByLocal(options, queryOptions) {
46
43
  return (options.orderby ??
@@ -105,6 +102,10 @@ function createLoader(options, queryOptions, context) {
105
102
  m.set(keys[i], i);
106
103
  }
107
104
  const col = options.groupCol;
105
+ const effectiveOrderBy = getOrderByLocal(options, queryOptions);
106
+ if ((0, query_impl_1.orderByHasExpressions)(effectiveOrderBy)) {
107
+ throw new Error("grouped query loaders do not support computed order expressions");
108
+ }
108
109
  let extraClause;
109
110
  if (options.clause && queryOptions?.clause) {
110
111
  extraClause = clause.And(options.clause, queryOptions.clause);
@@ -119,7 +120,7 @@ function createLoader(options, queryOptions, context) {
119
120
  tableName: options.tableName,
120
121
  fields: options.fields,
121
122
  values: keys,
122
- orderby: getOrderByLocal(options, queryOptions),
123
+ orderby: effectiveOrderBy,
123
124
  limit: queryOptions?.limit || (0, ent_1.getDefaultLimit)(),
124
125
  groupColumn: col,
125
126
  clause: extraClause,
@@ -142,7 +143,7 @@ class QueryDirectLoader {
142
143
  this.options = options;
143
144
  this.queryOptions = queryOptions;
144
145
  this.context = context;
145
- this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
146
+ this.memoizedInitPrime = (0, memoize_1.memoizeNoArgs)(this.initPrime.bind(this));
146
147
  }
147
148
  initPrime() {
148
149
  if (!this.context || !this.options?.toPrime) {
@@ -187,7 +188,7 @@ class QueryLoader {
187
188
  if (context) {
188
189
  this.loader = createLoader(options, queryOptions, context);
189
190
  }
190
- this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
191
+ this.memoizedInitPrime = (0, memoize_1.memoizeNoArgs)(this.initPrime.bind(this));
191
192
  }
192
193
  initPrime() {
193
194
  if (!this.context || !this.options?.toPrime) {
@@ -259,7 +260,7 @@ class QueryLoaderFactory {
259
260
  ? `baseClause:${queryOptions.clause.instanceKey()}`
260
261
  : undefined,
261
262
  `limit:${effectiveLimit}`,
262
- `orderby:${(0, cache_utils_1.stableStringify)(effectiveOrderBy)}`,
263
+ `orderby:${(0, query_impl_1.getOrderByKey)(effectiveOrderBy)}`,
263
264
  `disableTransformations:${disableTransformations}`,
264
265
  ];
265
266
  const key = keyParts
@@ -270,7 +271,7 @@ class QueryLoaderFactory {
270
271
  const effectiveOrderBy = getOrderByLocal(queryOptions, options);
271
272
  const effectiveLimit = options.limit || (0, ent_1.getDefaultLimit)();
272
273
  const disableTransformations = options.disableTransformations ?? false;
273
- const key = `${name}:limit:${effectiveLimit}:orderby:${(0, cache_utils_1.stableStringify)(effectiveOrderBy)}:disableTransformations:${disableTransformations}`;
274
+ const key = `${name}:limit:${effectiveLimit}:orderby:${(0, query_impl_1.getOrderByKey)(effectiveOrderBy)}:disableTransformations:${disableTransformations}`;
274
275
  return (0, loader_1.getCustomLoader)(key, () => new QueryLoader(queryOptions, context, options), context);
275
276
  }
276
277
  }
@@ -0,0 +1 @@
1
+ export declare function memoizeNoArgs<T>(fn: () => T): () => T;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.memoizeNoArgs = memoizeNoArgs;
4
+ function memoizeNoArgs(fn) {
5
+ let called = false;
6
+ let value;
7
+ return () => {
8
+ if (called) {
9
+ return value;
10
+ }
11
+ value = fn();
12
+ called = true;
13
+ return value;
14
+ };
15
+ }
@@ -81,7 +81,11 @@ class CustomClauseQuery extends query_1.BaseEdgeQuery {
81
81
  const alias = this.options.loadEntOptions.fieldsAlias ??
82
82
  this.options.loadEntOptions.alias;
83
83
  const fieldString = typeof firstRequestedField === "object"
84
- ? `${firstRequestedField.alias}.${firstRequestedField.column}`
84
+ ? "expression" in firstRequestedField
85
+ ? (() => {
86
+ throw new Error("join-backed raw counts do not support computed select expressions");
87
+ })()
88
+ : `${firstRequestedField.alias}.${firstRequestedField.column}`
85
89
  : alias
86
90
  ? `${alias}.${firstRequestedField}`
87
91
  : firstRequestedField;
@@ -84,7 +84,7 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
84
84
  protected genIDInfosToFetchImpl(): Promise<IDInfo[]>;
85
85
  private _defaultEdgeQueryableOptions;
86
86
  protected configureEdgeQueryableDataOptions(opts: EdgeQueryableDataOptionsConfigureLoader): void;
87
- protected getDefaultEdgeQueryOptions(): Partial<Pick<QueryableDataOptions, "clause" | "limit" | "orderby" | "disableTransformations">> | undefined;
87
+ protected getDefaultEdgeQueryOptions(): Partial<Pick<QueryableDataOptions, "limit" | "orderby" | "clause" | "disableTransformations">> | undefined;
88
88
  private loadEdges;
89
89
  getCursor(row: TEdge): string;
90
90
  }
@@ -32,16 +32,13 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
35
  Object.defineProperty(exports, "__esModule", { value: true });
39
36
  exports.BaseEdgeQuery = void 0;
40
- const memoizee_1 = __importDefault(require("memoizee"));
41
37
  const types_1 = require("util/types");
42
38
  const clause = __importStar(require("../clause"));
43
39
  const ent_1 = require("../ent");
44
40
  const privacy_1 = require("../privacy");
41
+ const memoize_1 = require("../memoize");
45
42
  const query_impl_1 = require("../query_impl");
46
43
  // TODO can we generalize EdgeQuery to support any clause
47
44
  function assertPositive(n) {
@@ -51,7 +48,7 @@ function assertPositive(n) {
51
48
  }
52
49
  function translateCursorToKeyValues(cursor, opts) {
53
50
  const { keys } = opts;
54
- const decoded = atob(cursor);
51
+ const decoded = (0, ent_1.decodeCursorPayload)(cursor);
55
52
  let cursorData = [];
56
53
  try {
57
54
  cursorData = JSON.parse(decoded);
@@ -149,6 +146,9 @@ class FirstFilter {
149
146
  options.limit = this.options.limit + 1;
150
147
  const orderBy = this.options.orderby;
151
148
  if (this.offset) {
149
+ if ((0, query_impl_1.orderByHasExpressions)(orderBy)) {
150
+ throw new Error("cursor pagination does not support computed order expressions");
151
+ }
152
152
  const keyValuePairs = {};
153
153
  for (const [key, value] of this.cursorKeyValues) {
154
154
  keyValuePairs[key] = value;
@@ -219,6 +219,9 @@ class LastFilter {
219
219
  // we also sort cursor col in same direction. (direction doesn't matter)
220
220
  const orderBy = (0, query_impl_1.reverseOrderBy)(this.options.orderby);
221
221
  if (this.offset) {
222
+ if ((0, query_impl_1.orderByHasExpressions)(orderBy)) {
223
+ throw new Error("cursor pagination does not support computed order expressions");
224
+ }
222
225
  const keyValuePairs = {};
223
226
  for (const [key, value] of this.cursorKeyValues) {
224
227
  keyValuePairs[key] = value;
@@ -316,8 +319,8 @@ class BaseEdgeQuery {
316
319
  this.edgeQueryOptions = { ...options, orderby: orderBy };
317
320
  this.cursorCol = options.cursorCol;
318
321
  this.cursorKeys = orderBy.map((orderBy) => orderBy.column);
319
- this.memoizedloadEdges = (0, memoizee_1.default)(this.loadEdges.bind(this));
320
- this.genIDInfosToFetch = (0, memoizee_1.default)(this.genIDInfosToFetchImpl.bind(this));
322
+ this.memoizedloadEdges = (0, memoize_1.memoizeNoArgs)(this.loadEdges.bind(this));
323
+ this.genIDInfosToFetch = (0, memoize_1.memoizeNoArgs)(this.genIDInfosToFetchImpl.bind(this));
321
324
  }
322
325
  getCursorCol() {
323
326
  return this.cursorCol;
@@ -0,0 +1,6 @@
1
+ export interface QueryExpression {
2
+ clause(idx: number, alias?: string): string;
3
+ values(): any[];
4
+ logValues(): any[];
5
+ instanceKey(): string;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,17 +1,33 @@
1
1
  import { QueryableDataOptions } from "./base";
2
+ import { QueryExpression } from "./query_expression";
2
3
  export interface OrderByOption {
3
4
  column: string;
4
5
  direction: "ASC" | "DESC";
5
6
  alias?: string;
6
7
  nullsPlacement?: "first" | "last";
8
+ expression?: QueryExpression;
7
9
  }
8
10
  export type OrderBy = OrderByOption[];
9
- export declare function getOrderByPhrase(orderby: OrderBy, alias?: string): string;
10
- export declare function reverseOrderBy(orderby: OrderBy): OrderBy;
11
- interface JoinInfo {
11
+ interface QueryFragmentInfo {
12
12
  phrase: string;
13
+ values: any[];
14
+ logValues: any[];
13
15
  valuesUsed: number;
14
16
  }
17
+ export interface BuiltQueryData {
18
+ query: string;
19
+ values: any[];
20
+ logValues: any[];
21
+ }
22
+ export declare function getSelectFieldsKey(fields: QueryableDataOptions["fields"]): string;
23
+ export declare function getOrderByKey(orderby: OrderBy): string;
24
+ export declare function orderByHasExpressions(orderby?: OrderBy): boolean;
25
+ export declare function getOrderByInfo(orderby: OrderBy, alias?: string, clauseIdx?: number): QueryFragmentInfo;
26
+ export declare function getOrderByPhrase(orderby: OrderBy, alias?: string): string;
27
+ export declare function reverseOrderBy(orderby: OrderBy): OrderBy;
28
+ interface JoinInfo extends QueryFragmentInfo {
29
+ }
15
30
  export declare function getJoinInfo(join: NonNullable<QueryableDataOptions["join"]>, clauseIdx?: number): JoinInfo;
31
+ export declare function buildQueryData(options: QueryableDataOptions): BuiltQueryData;
16
32
  export declare function buildQuery(options: QueryableDataOptions): string;
17
33
  export {};
@@ -1,14 +1,98 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSelectFieldsKey = getSelectFieldsKey;
4
+ exports.getOrderByKey = getOrderByKey;
5
+ exports.orderByHasExpressions = orderByHasExpressions;
6
+ exports.getOrderByInfo = getOrderByInfo;
3
7
  exports.getOrderByPhrase = getOrderByPhrase;
4
8
  exports.reverseOrderBy = reverseOrderBy;
5
9
  exports.getJoinInfo = getJoinInfo;
10
+ exports.buildQueryData = buildQueryData;
6
11
  exports.buildQuery = buildQuery;
7
- function getOrderByPhrase(orderby, alias) {
12
+ const cache_utils_1 = require("./cache_utils");
13
+ function isExpressionField(field) {
14
+ return typeof field === "object" && "expression" in field;
15
+ }
16
+ function getCacheKeyForExpression(expression) {
17
+ return expression.instanceKey();
18
+ }
19
+ function getSelectFieldsKey(fields) {
20
+ return fields
21
+ .map((field) => {
22
+ if (typeof field === "string") {
23
+ return field;
24
+ }
25
+ if (isExpressionField(field)) {
26
+ return (0, cache_utils_1.stableStringify)({
27
+ alias: field.alias,
28
+ expression: getCacheKeyForExpression(field.expression),
29
+ });
30
+ }
31
+ return (0, cache_utils_1.stableStringify)({
32
+ alias: field.alias,
33
+ column: field.column,
34
+ });
35
+ })
36
+ .join(",");
37
+ }
38
+ function getOrderByKey(orderby) {
8
39
  return orderby
9
- .map((v) => {
40
+ .map((entry) => (0, cache_utils_1.stableStringify)({
41
+ column: entry.column,
42
+ direction: entry.direction,
43
+ alias: entry.alias,
44
+ nullsPlacement: entry.nullsPlacement,
45
+ expression: entry.expression
46
+ ? getCacheKeyForExpression(entry.expression)
47
+ : undefined,
48
+ }))
49
+ .join("|");
50
+ }
51
+ function orderByHasExpressions(orderby) {
52
+ return orderby?.some((entry) => entry.expression !== undefined) ?? false;
53
+ }
54
+ function getFieldsInfo(fields, alias, disableFieldsAlias, clauseIdx = 1) {
55
+ let valuesUsed = 0;
56
+ const values = [];
57
+ const logValues = [];
58
+ const phrase = fields
59
+ .map((field) => {
60
+ if (typeof field === "string") {
61
+ if (alias && !disableFieldsAlias) {
62
+ return `${alias}.${field}`;
63
+ }
64
+ return field;
65
+ }
66
+ if (isExpressionField(field)) {
67
+ const expression = field.expression;
68
+ const rendered = expression.clause(clauseIdx + valuesUsed, disableFieldsAlias ? undefined : alias);
69
+ const expressionValues = expression.values();
70
+ valuesUsed += expressionValues.length;
71
+ values.push(...expressionValues);
72
+ logValues.push(...expression.logValues());
73
+ return `${rendered} AS ${field.alias}`;
74
+ }
75
+ if (!disableFieldsAlias) {
76
+ return `${field.alias}.${field.column}`;
77
+ }
78
+ return field.column;
79
+ })
80
+ .join(", ");
81
+ return {
82
+ phrase,
83
+ valuesUsed,
84
+ values,
85
+ logValues,
86
+ };
87
+ }
88
+ function getOrderByInfo(orderby, alias, clauseIdx = 1) {
89
+ let valuesUsed = 0;
90
+ const values = [];
91
+ const logValues = [];
92
+ const phrase = orderby
93
+ .map((entry) => {
10
94
  let nullsPlacement = "";
11
- switch (v.nullsPlacement) {
95
+ switch (entry.nullsPlacement) {
12
96
  case "first":
13
97
  nullsPlacement = " NULLS FIRST";
14
98
  break;
@@ -16,11 +100,28 @@ function getOrderByPhrase(orderby, alias) {
16
100
  nullsPlacement = " NULLS LAST";
17
101
  break;
18
102
  }
19
- const orderByAlias = v.alias ?? alias;
20
- const col = orderByAlias ? `${orderByAlias}.${v.column}` : v.column;
21
- return `${col} ${v.direction}${nullsPlacement}`;
103
+ const orderByAlias = entry.alias ?? alias;
104
+ let col = orderByAlias ? `${orderByAlias}.${entry.column}` : entry.column;
105
+ if (entry.expression) {
106
+ const rendered = entry.expression.clause(clauseIdx + valuesUsed, orderByAlias);
107
+ const expressionValues = entry.expression.values();
108
+ valuesUsed += expressionValues.length;
109
+ values.push(...expressionValues);
110
+ logValues.push(...entry.expression.logValues());
111
+ col = rendered;
112
+ }
113
+ return `${col} ${entry.direction}${nullsPlacement}`;
22
114
  })
23
115
  .join(", ");
116
+ return {
117
+ phrase,
118
+ valuesUsed,
119
+ values,
120
+ logValues,
121
+ };
122
+ }
123
+ function getOrderByPhrase(orderby, alias) {
124
+ return getOrderByInfo(orderby, alias).phrase;
24
125
  }
25
126
  function reverseOrderBy(orderby) {
26
127
  return orderby.map((o) => {
@@ -31,12 +132,18 @@ function reverseOrderBy(orderby) {
31
132
  }
32
133
  function getJoinInfo(join, clauseIdx = 1) {
33
134
  let valuesUsed = 0;
34
- const str = join
135
+ const values = [];
136
+ const logValues = [];
137
+ const phrase = join
35
138
  .map((join) => {
36
139
  const joinTable = join.alias
37
140
  ? `${join.tableName} ${join.alias}`
38
141
  : join.tableName;
39
- valuesUsed += join.clause.values().length;
142
+ const joinValues = join.clause.values();
143
+ const renderedClause = join.clause.clause(clauseIdx + valuesUsed);
144
+ valuesUsed += joinValues.length;
145
+ values.push(...joinValues);
146
+ logValues.push(...join.clause.logValues());
40
147
  let joinType;
41
148
  switch (join.type) {
42
149
  case "left":
@@ -54,53 +161,52 @@ function getJoinInfo(join, clauseIdx = 1) {
54
161
  default:
55
162
  joinType = "JOIN";
56
163
  }
57
- return `${joinType} ${joinTable} ON ${join.clause.clause(clauseIdx)}`;
164
+ return `${joinType} ${joinTable} ON ${renderedClause}`;
58
165
  })
59
166
  .join(" ");
60
167
  return {
61
- phrase: str,
168
+ phrase,
62
169
  valuesUsed,
170
+ values,
171
+ logValues,
63
172
  };
64
173
  }
65
- function buildQuery(options) {
174
+ function buildQueryData(options) {
66
175
  const fieldsAlias = options.fieldsAlias ?? options.alias;
67
- const fields = options.fields
68
- .map((f) => {
69
- if (typeof f === "object") {
70
- if (!options.disableFieldsAlias) {
71
- return `${f.alias}.${f.column}`;
72
- }
73
- return f.column;
74
- }
75
- if (fieldsAlias && !options.disableFieldsAlias) {
76
- return `${fieldsAlias}.${f}`;
77
- }
78
- return f;
79
- })
80
- .join(", ");
81
- // always start at 1
176
+ const fieldInfo = getFieldsInfo(options.fields, fieldsAlias, options.disableFieldsAlias, 1);
177
+ const values = [...fieldInfo.values];
178
+ const logValues = [...fieldInfo.logValues];
179
+ let clauseIdx = 1 + fieldInfo.valuesUsed;
82
180
  const parts = [];
83
181
  const tableName = options.alias
84
182
  ? `${options.tableName} AS ${options.alias}`
85
183
  : options.tableName;
86
184
  if (options.distinct) {
87
- parts.push(`SELECT DISTINCT ${fields} FROM ${tableName}`);
185
+ parts.push(`SELECT DISTINCT ${fieldInfo.phrase} FROM ${tableName}`);
88
186
  }
89
187
  else {
90
- parts.push(`SELECT ${fields} FROM ${tableName}`);
188
+ parts.push(`SELECT ${fieldInfo.phrase} FROM ${tableName}`);
91
189
  }
92
- let whereStart = 1;
93
190
  if (options.join) {
94
- const { phrase, valuesUsed } = getJoinInfo(options.join);
95
- parts.push(phrase);
96
- whereStart += valuesUsed;
191
+ const joinInfo = getJoinInfo(options.join, clauseIdx);
192
+ parts.push(joinInfo.phrase);
193
+ values.push(...joinInfo.values);
194
+ logValues.push(...joinInfo.logValues);
195
+ clauseIdx += joinInfo.valuesUsed;
97
196
  }
98
- parts.push(`WHERE ${options.clause.clause(whereStart, options.alias)}`);
197
+ parts.push(`WHERE ${options.clause.clause(clauseIdx, options.alias)}`);
198
+ values.push(...options.clause.values());
199
+ logValues.push(...options.clause.logValues());
200
+ clauseIdx += options.clause.values().length;
99
201
  if (options.groupby) {
100
202
  parts.push(`GROUP BY ${options.groupby}`);
101
203
  }
102
204
  if (options.orderby) {
103
- parts.push(`ORDER BY ${getOrderByPhrase(options.orderby, options.disableDefaultOrderByAlias ? undefined : fieldsAlias)}`);
205
+ const orderByInfo = getOrderByInfo(options.orderby, options.disableDefaultOrderByAlias ? undefined : fieldsAlias, clauseIdx);
206
+ parts.push(`ORDER BY ${orderByInfo.phrase}`);
207
+ values.push(...orderByInfo.values);
208
+ logValues.push(...orderByInfo.logValues);
209
+ clauseIdx += orderByInfo.valuesUsed;
104
210
  }
105
211
  if (options.limit !== undefined) {
106
212
  parts.push(`LIMIT ${options.limit}`);
@@ -108,5 +214,12 @@ function buildQuery(options) {
108
214
  if (options.offset !== undefined) {
109
215
  parts.push(`OFFSET ${options.offset}`);
110
216
  }
111
- return parts.join(" ");
217
+ return {
218
+ query: parts.join(" "),
219
+ values,
220
+ logValues,
221
+ };
222
+ }
223
+ function buildQuery(options) {
224
+ return buildQueryData(options).query;
112
225
  }
package/index.d.ts CHANGED
@@ -2,15 +2,17 @@ export * from "./core/base";
2
2
  export { loadEnt, loadCustomData, loadCustomEnts, loadCustomCount, loadEntX, loadEnts, CustomQuery, loadDerivedEnt, loadDerivedEntX, loadEntViaKey, loadEntXViaKey, performRawQuery, loadRowX, loadRow, loadRows, AssocEdge, AssocEdgeData, loadEdgeData, loadEdgeDatas, loadEdges, loadUniqueEdge, loadUniqueNode, loadRawEdgeCountX, loadEdgeForID2, loadNodesByEdge, getEdgeTypeInGroup, setEntLoaderPrivacyConcurrencyLimit, getEntLoaderPrivacyConcurrencyLimit, } from "./core/ent";
3
3
  export { DataOperation, EditNodeOptions, EditNodeOperation, RawQueryOperation, EdgeOperation, DeleteNodeOperation, AssocEdgeInputOptions, AssocEdgeInput, } from "./action/operations";
4
4
  export { setGlobalSchema } from "./core/global_schema";
5
+ export { registerExtensionRuntime } from "./core/extensions";
5
6
  import DB from "./core/db";
6
7
  export * from "./core/loaders";
7
8
  export { DB };
8
9
  export { EntPrivacyError, AlwaysAllowRule, AlwaysDenyRule, DenyIfLoggedInRule, DenyIfLoggedOutRule, AllowIfHasIdentity, AllowIfViewerRule, AllowIfFuncRule, AllowIfViewerIsRule, AllowIfViewerIsEntPropertyRule, AllowIfEntPropertyIsRule, DenyIfEntPropertyIsRule, AllowIfViewerEqualsRule, DenyIfViewerEqualsRule, AllowIfEdgeExistsRule, AllowIfViewerInboundEdgeExistsRule, AllowIfViewerOutboundEdgeExistsRule, DenyIfEdgeExistsRule, DenyIfViewerInboundEdgeExistsRule, DenyIfViewerOutboundEdgeExistsRule, DenyIfEdgeDoesNotExistRule, DenyIfViewerInboundEdgeDoesNotExistRule, DenyIfViewerOutboundEdgeDoesNotExistRule, AllowIfEntIsVisibleRule, AllowIfEntIsNotVisibleRule, DenyIfEntIsVisibleRule, DenyIfEntIsNotVisibleRule, AllowIfEntIsVisiblePolicy, DenyIfEntIsVisiblePolicy, DelayedResultRule, applyPrivacyPolicy, applyPrivacyPolicyX, AlwaysAllowPrivacyPolicy, AlwaysDenyPrivacyPolicy, AllowIfConditionAppliesRule, AllowIfSubPolicyAllowsRule, AllowIfViewerPrivacyPolicy, AllowIfViewerHasIdentityPrivacyPolicy, } from "./core/privacy";
9
10
  export * from "./core/query";
10
11
  export * from "./core/query_impl";
12
+ export type { QueryExpression } from "./core/query_expression";
11
13
  export * from "./schema/";
12
14
  import * as q from "./core/clause";
13
- export { Clause } from "./core/clause";
15
+ export { Clause, Expression, ParameterizedExpression } from "./core/clause";
14
16
  declare const query: {
15
17
  Eq: typeof q.Eq;
16
18
  NotEq: typeof q.NotEq;
@@ -50,6 +52,8 @@ declare const query: {
50
52
  TsVectorPlainToTsQuery: typeof q.TsVectorPlainToTsQuery;
51
53
  TsVectorPhraseToTsQuery: typeof q.TsVectorPhraseToTsQuery;
52
54
  TsVectorWebsearchToTsQuery: typeof q.TsVectorWebsearchToTsQuery;
55
+ Expression: typeof q.Expression;
56
+ ParameterizedExpression: typeof q.ParameterizedExpression;
53
57
  };
54
58
  export { query };
55
59
  export { RequestContext, ContextCache } from "./core/context";
package/index.js CHANGED
@@ -39,8 +39,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
39
39
  return (mod && mod.__esModule) ? mod : { "default": mod };
40
40
  };
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.AllowIfViewerOutboundEdgeExistsRule = exports.AllowIfViewerInboundEdgeExistsRule = exports.AllowIfEdgeExistsRule = exports.DenyIfViewerEqualsRule = exports.AllowIfViewerEqualsRule = exports.DenyIfEntPropertyIsRule = exports.AllowIfEntPropertyIsRule = exports.AllowIfViewerIsEntPropertyRule = exports.AllowIfViewerIsRule = exports.AllowIfFuncRule = exports.AllowIfViewerRule = exports.AllowIfHasIdentity = exports.DenyIfLoggedOutRule = exports.DenyIfLoggedInRule = exports.AlwaysDenyRule = exports.AlwaysAllowRule = exports.EntPrivacyError = exports.DB = exports.setGlobalSchema = exports.DeleteNodeOperation = exports.EdgeOperation = exports.RawQueryOperation = exports.EditNodeOperation = exports.getEntLoaderPrivacyConcurrencyLimit = exports.setEntLoaderPrivacyConcurrencyLimit = exports.getEdgeTypeInGroup = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadEdges = exports.loadEdgeDatas = exports.loadEdgeData = exports.AssocEdgeData = exports.AssocEdge = exports.loadRows = exports.loadRow = exports.loadRowX = exports.performRawQuery = exports.loadEntXViaKey = exports.loadEntViaKey = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadEnts = exports.loadEntX = exports.loadCustomCount = exports.loadCustomEnts = exports.loadCustomData = exports.loadEnt = void 0;
43
- exports.setLogLevels = exports.loadConfig = exports.LoggedOutViewer = exports.IDViewer = exports.ContextCache = exports.query = exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AllowIfSubPolicyAllowsRule = exports.AllowIfConditionAppliesRule = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = exports.applyPrivacyPolicyX = exports.applyPrivacyPolicy = exports.DelayedResultRule = exports.DenyIfEntIsVisiblePolicy = exports.AllowIfEntIsVisiblePolicy = exports.DenyIfEntIsNotVisibleRule = exports.DenyIfEntIsVisibleRule = exports.AllowIfEntIsNotVisibleRule = exports.AllowIfEntIsVisibleRule = exports.DenyIfViewerOutboundEdgeDoesNotExistRule = exports.DenyIfViewerInboundEdgeDoesNotExistRule = exports.DenyIfEdgeDoesNotExistRule = exports.DenyIfViewerOutboundEdgeExistsRule = exports.DenyIfViewerInboundEdgeExistsRule = exports.DenyIfEdgeExistsRule = void 0;
42
+ exports.AllowIfViewerInboundEdgeExistsRule = exports.AllowIfEdgeExistsRule = exports.DenyIfViewerEqualsRule = exports.AllowIfViewerEqualsRule = exports.DenyIfEntPropertyIsRule = exports.AllowIfEntPropertyIsRule = exports.AllowIfViewerIsEntPropertyRule = exports.AllowIfViewerIsRule = exports.AllowIfFuncRule = exports.AllowIfViewerRule = exports.AllowIfHasIdentity = exports.DenyIfLoggedOutRule = exports.DenyIfLoggedInRule = exports.AlwaysDenyRule = exports.AlwaysAllowRule = exports.EntPrivacyError = exports.DB = exports.registerExtensionRuntime = exports.setGlobalSchema = exports.DeleteNodeOperation = exports.EdgeOperation = exports.RawQueryOperation = exports.EditNodeOperation = exports.getEntLoaderPrivacyConcurrencyLimit = exports.setEntLoaderPrivacyConcurrencyLimit = exports.getEdgeTypeInGroup = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadEdges = exports.loadEdgeDatas = exports.loadEdgeData = exports.AssocEdgeData = exports.AssocEdge = exports.loadRows = exports.loadRow = exports.loadRowX = exports.performRawQuery = exports.loadEntXViaKey = exports.loadEntViaKey = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadEnts = exports.loadEntX = exports.loadCustomCount = exports.loadCustomEnts = exports.loadCustomData = exports.loadEnt = void 0;
43
+ exports.setLogLevels = exports.loadConfig = exports.LoggedOutViewer = exports.IDViewer = exports.ContextCache = exports.query = exports.ParameterizedExpression = exports.Expression = exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AllowIfSubPolicyAllowsRule = exports.AllowIfConditionAppliesRule = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = exports.applyPrivacyPolicyX = exports.applyPrivacyPolicy = exports.DelayedResultRule = exports.DenyIfEntIsVisiblePolicy = exports.AllowIfEntIsVisiblePolicy = exports.DenyIfEntIsNotVisibleRule = exports.DenyIfEntIsVisibleRule = exports.AllowIfEntIsNotVisibleRule = exports.AllowIfEntIsVisibleRule = exports.DenyIfViewerOutboundEdgeDoesNotExistRule = exports.DenyIfViewerInboundEdgeDoesNotExistRule = exports.DenyIfEdgeDoesNotExistRule = exports.DenyIfViewerOutboundEdgeExistsRule = exports.DenyIfViewerInboundEdgeExistsRule = exports.DenyIfEdgeExistsRule = exports.AllowIfViewerOutboundEdgeExistsRule = void 0;
44
44
  __exportStar(require("./core/base"), exports);
45
45
  var ent_1 = require("./core/ent");
46
46
  Object.defineProperty(exports, "loadEnt", { enumerable: true, get: function () { return ent_1.loadEnt; } });
@@ -79,6 +79,8 @@ Object.defineProperty(exports, "EdgeOperation", { enumerable: true, get: functio
79
79
  Object.defineProperty(exports, "DeleteNodeOperation", { enumerable: true, get: function () { return operations_1.DeleteNodeOperation; } });
80
80
  var global_schema_1 = require("./core/global_schema");
81
81
  Object.defineProperty(exports, "setGlobalSchema", { enumerable: true, get: function () { return global_schema_1.setGlobalSchema; } });
82
+ var extensions_1 = require("./core/extensions");
83
+ Object.defineProperty(exports, "registerExtensionRuntime", { enumerable: true, get: function () { return extensions_1.registerExtensionRuntime; } });
82
84
  const db_1 = __importDefault(require("./core/db"));
83
85
  exports.DB = db_1.default;
84
86
  __exportStar(require("./core/loaders"), exports);
@@ -126,6 +128,9 @@ __exportStar(require("./core/query"), exports);
126
128
  __exportStar(require("./core/query_impl"), exports);
127
129
  __exportStar(require("./schema/"), exports);
128
130
  const q = __importStar(require("./core/clause"));
131
+ var clause_1 = require("./core/clause");
132
+ Object.defineProperty(exports, "Expression", { enumerable: true, get: function () { return clause_1.Expression; } });
133
+ Object.defineProperty(exports, "ParameterizedExpression", { enumerable: true, get: function () { return clause_1.ParameterizedExpression; } });
129
134
  const query = {
130
135
  Eq: q.Eq,
131
136
  NotEq: q.NotEq,
@@ -165,6 +170,8 @@ const query = {
165
170
  TsVectorPlainToTsQuery: q.TsVectorPlainToTsQuery,
166
171
  TsVectorPhraseToTsQuery: q.TsVectorPhraseToTsQuery,
167
172
  TsVectorWebsearchToTsQuery: q.TsVectorWebsearchToTsQuery,
173
+ Expression: q.Expression,
174
+ ParameterizedExpression: q.ParameterizedExpression,
168
175
  };
169
176
  exports.query = query;
170
177
  var context_1 = require("./core/context");