@snowtop/ent 0.2.6 → 0.2.8

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 (73) 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/async_utils.d.ts +1 -0
  7. package/core/async_utils.js +29 -0
  8. package/core/base.d.ts +12 -5
  9. package/core/clause.d.ts +3 -5
  10. package/core/clause.js +32 -0
  11. package/core/config.d.ts +28 -2
  12. package/core/config.js +14 -1
  13. package/core/context.d.ts +3 -1
  14. package/core/context.js +90 -26
  15. package/core/db.d.ts +12 -2
  16. package/core/db.js +102 -7
  17. package/core/dev_schema.d.ts +9 -0
  18. package/core/dev_schema.js +306 -0
  19. package/core/ent.d.ts +5 -7
  20. package/core/ent.js +33 -48
  21. package/core/extensions.d.ts +25 -0
  22. package/core/extensions.js +220 -0
  23. package/core/loaders/assoc_count_loader.js +3 -6
  24. package/core/loaders/assoc_edge_loader.d.ts +3 -0
  25. package/core/loaders/assoc_edge_loader.js +48 -19
  26. package/core/loaders/index.d.ts +2 -1
  27. package/core/loaders/index.js +5 -1
  28. package/core/loaders/loader.d.ts +31 -0
  29. package/core/loaders/loader.js +141 -2
  30. package/core/loaders/object_loader.d.ts +2 -2
  31. package/core/loaders/object_loader.js +39 -57
  32. package/core/loaders/query_loader.d.ts +2 -5
  33. package/core/loaders/query_loader.js +45 -24
  34. package/core/loaders/raw_count_loader.d.ts +2 -2
  35. package/core/loaders/raw_count_loader.js +12 -14
  36. package/core/memoize.d.ts +1 -0
  37. package/core/memoize.js +15 -0
  38. package/core/metrics.d.ts +22 -0
  39. package/core/metrics.js +31 -0
  40. package/core/query/custom_clause_query.js +5 -1
  41. package/core/query/query.d.ts +1 -1
  42. package/core/query/query.js +10 -7
  43. package/core/query_expression.d.ts +6 -0
  44. package/core/query_expression.js +2 -0
  45. package/core/query_impl.d.ts +19 -3
  46. package/core/query_impl.js +148 -35
  47. package/index.d.ts +7 -2
  48. package/index.js +12 -2
  49. package/package.json +1 -7
  50. package/parse_schema/parse.d.ts +2 -12
  51. package/parse_schema/parse.js +22 -41
  52. package/schema/index.d.ts +1 -1
  53. package/schema/schema.d.ts +20 -1
  54. package/scripts/custom_graphql.js +12 -5
  55. package/scripts/fix_action_exports.js +1 -1
  56. package/scripts/migrate_v0.1.js +2 -5
  57. package/scripts/move_types.js +1 -1
  58. package/scripts/read_schema.js +2 -5
  59. package/testutils/builder.js +1 -2
  60. package/testutils/parse_sql.js +1 -1
  61. package/tsc/compilerOptions.d.ts +2 -2
  62. package/tsc/compilerOptions.js +12 -18
  63. package/tsc/move_generated.js +2 -2
  64. package/tsc/transform.d.ts +1 -1
  65. package/tsc/transform.js +16 -2
  66. package/tsc/transform_action.d.ts +1 -1
  67. package/tsc/transform_action.js +1 -1
  68. package/tsc/transform_ent.d.ts +1 -1
  69. package/tsc/transform_ent.js +1 -1
  70. package/tsc/transform_schema.d.ts +1 -1
  71. package/tsc/transform_schema.js +2 -2
  72. /package/core/{loaders/cache_utils.d.ts → cache_utils.d.ts} +0 -0
  73. /package/core/{loaders/cache_utils.js → cache_utils.js} +0 -0
@@ -32,16 +32,11 @@ 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.RawCountLoaderFactory = exports.RawCountLoader = void 0;
40
37
  exports.createCountDataLoader = createCountDataLoader;
41
- const dataloader_1 = __importDefault(require("dataloader"));
42
38
  const ent_1 = require("../ent");
43
39
  const clause = __importStar(require("../clause"));
44
- const logger_1 = require("../logger");
45
40
  const loader_1 = require("./loader");
46
41
  async function simpleCase(options, key, context) {
47
42
  let cls;
@@ -66,21 +61,23 @@ async function simpleCase(options, key, context) {
66
61
  });
67
62
  return [parseInt(row?.count, 10) || 0];
68
63
  }
69
- function createCountDataLoader(options) {
64
+ function createCountDataLoader(options, context) {
65
+ const loaderName = options.groupCol
66
+ ? `rawCountLoader:${options.tableName}:${options.groupCol}`
67
+ : options.clause
68
+ ? `rawCountLoader:${options.tableName}:${options.clause.instanceKey()}`
69
+ : `rawCountLoader:${options.tableName}`;
70
70
  const loaderOptions = {
71
71
  maxBatchSize: (0, loader_1.getLoaderMaxBatchSize)(),
72
+ cacheMap: (0, loader_1.createLoaderCacheMap)(options),
72
73
  };
73
- // if query logging is enabled, we should log what's happening with loader
74
- if ((0, logger_1.logEnabled)("query")) {
75
- loaderOptions.cacheMap = new loader_1.CacheMap(options);
76
- }
77
- return new dataloader_1.default(async (keys) => {
74
+ return new loader_1.InstrumentedDataLoader(loaderName, async (keys) => {
78
75
  if (!keys.length) {
79
76
  return [];
80
77
  }
81
78
  // keep query simple if we're only fetching for one id
82
79
  if (keys.length == 1 || !options.groupCol) {
83
- return simpleCase(options, keys[0]);
80
+ return simpleCase(options, keys[0], context);
84
81
  }
85
82
  let typ = options.groupColType || "uuid";
86
83
  let cls = clause.DBTypeIn(options.groupCol, keys, typ);
@@ -99,6 +96,7 @@ function createCountDataLoader(options) {
99
96
  fields: ["count(1) as count", options.groupCol],
100
97
  groupby: options.groupCol,
101
98
  clause: cls,
99
+ context,
102
100
  };
103
101
  const rows = await (0, ent_1.loadRows)(rowOptions);
104
102
  for (const row of rows) {
@@ -110,7 +108,7 @@ function createCountDataLoader(options) {
110
108
  result[idx] = parseInt(row.count, 10);
111
109
  }
112
110
  return result;
113
- }, loaderOptions);
111
+ }, loaderOptions, options.tableName);
114
112
  }
115
113
  // for now this only works for single column counts
116
114
  // e.g. foreign key count
@@ -120,7 +118,7 @@ class RawCountLoader {
120
118
  this.options = options;
121
119
  this.context = context;
122
120
  if (context && options.groupCol) {
123
- this.loader = createCountDataLoader(options);
121
+ this.loader = createCountDataLoader(options, context);
124
122
  }
125
123
  }
126
124
  async load(id) {
@@ -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
+ }
@@ -0,0 +1,22 @@
1
+ export type DataLoaderBatchMetrics = {
2
+ loaderName: string;
3
+ batchSize: number;
4
+ };
5
+ export type DataLoaderCacheHitMetrics = {
6
+ tableName: string;
7
+ key: unknown;
8
+ };
9
+ export type QueryCacheHitMetrics = {
10
+ tableName: string;
11
+ key: string;
12
+ };
13
+ export type MetricsHook = {
14
+ onDataLoaderBatch?: (info: DataLoaderBatchMetrics) => void;
15
+ onDataLoaderCacheHit?: (info: DataLoaderCacheHitMetrics) => void;
16
+ onQueryCacheHit?: (info: QueryCacheHitMetrics) => void;
17
+ };
18
+ export declare function setMetricsHook(hooks?: MetricsHook | null): void;
19
+ export declare function getMetricsHook(): MetricsHook;
20
+ export declare function getOnDataLoaderBatch(): ((info: DataLoaderBatchMetrics) => void) | undefined;
21
+ export declare function getOnDataLoaderCacheHit(): ((info: DataLoaderCacheHitMetrics) => void) | undefined;
22
+ export declare function getOnQueryCacheHit(): ((info: QueryCacheHitMetrics) => void) | undefined;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setMetricsHook = setMetricsHook;
4
+ exports.getMetricsHook = getMetricsHook;
5
+ exports.getOnDataLoaderBatch = getOnDataLoaderBatch;
6
+ exports.getOnDataLoaderCacheHit = getOnDataLoaderCacheHit;
7
+ exports.getOnQueryCacheHit = getOnQueryCacheHit;
8
+ let onDataLoaderBatch;
9
+ let onDataLoaderCacheHit;
10
+ let onQueryCacheHit;
11
+ function setMetricsHook(hooks) {
12
+ onDataLoaderBatch = hooks?.onDataLoaderBatch;
13
+ onDataLoaderCacheHit = hooks?.onDataLoaderCacheHit;
14
+ onQueryCacheHit = hooks?.onQueryCacheHit;
15
+ }
16
+ function getMetricsHook() {
17
+ return {
18
+ onDataLoaderBatch,
19
+ onDataLoaderCacheHit,
20
+ onQueryCacheHit,
21
+ };
22
+ }
23
+ function getOnDataLoaderBatch() {
24
+ return onDataLoaderBatch;
25
+ }
26
+ function getOnDataLoaderCacheHit() {
27
+ return onDataLoaderCacheHit;
28
+ }
29
+ function getOnQueryCacheHit() {
30
+ return onQueryCacheHit;
31
+ }
@@ -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
@@ -1,16 +1,18 @@
1
1
  export * from "./core/base";
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, } from "./core/ent";
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,10 +52,13 @@ 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";
56
60
  export { IDViewer, LoggedOutViewer, IDViewerOptions } from "./core/viewer";
57
61
  export { loadConfig } from "./core/config";
58
62
  export { setLogLevels } from "./core/logger";
63
+ export * from "./core/metrics";
59
64
  export * from "./core/convert";
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.DenyIfViewerInboundEdgeExistsRule = exports.DenyIfEdgeExistsRule = 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.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 = 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; } });
@@ -69,6 +69,8 @@ Object.defineProperty(exports, "loadRawEdgeCountX", { enumerable: true, get: fun
69
69
  Object.defineProperty(exports, "loadEdgeForID2", { enumerable: true, get: function () { return ent_1.loadEdgeForID2; } });
70
70
  Object.defineProperty(exports, "loadNodesByEdge", { enumerable: true, get: function () { return ent_1.loadNodesByEdge; } });
71
71
  Object.defineProperty(exports, "getEdgeTypeInGroup", { enumerable: true, get: function () { return ent_1.getEdgeTypeInGroup; } });
72
+ Object.defineProperty(exports, "setEntLoaderPrivacyConcurrencyLimit", { enumerable: true, get: function () { return ent_1.setEntLoaderPrivacyConcurrencyLimit; } });
73
+ Object.defineProperty(exports, "getEntLoaderPrivacyConcurrencyLimit", { enumerable: true, get: function () { return ent_1.getEntLoaderPrivacyConcurrencyLimit; } });
72
74
  // TODO should these even be exported from the root?
73
75
  var operations_1 = require("./action/operations");
74
76
  Object.defineProperty(exports, "EditNodeOperation", { enumerable: true, get: function () { return operations_1.EditNodeOperation; } });
@@ -77,6 +79,8 @@ Object.defineProperty(exports, "EdgeOperation", { enumerable: true, get: functio
77
79
  Object.defineProperty(exports, "DeleteNodeOperation", { enumerable: true, get: function () { return operations_1.DeleteNodeOperation; } });
78
80
  var global_schema_1 = require("./core/global_schema");
79
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; } });
80
84
  const db_1 = __importDefault(require("./core/db"));
81
85
  exports.DB = db_1.default;
82
86
  __exportStar(require("./core/loaders"), exports);
@@ -124,6 +128,9 @@ __exportStar(require("./core/query"), exports);
124
128
  __exportStar(require("./core/query_impl"), exports);
125
129
  __exportStar(require("./schema/"), exports);
126
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; } });
127
134
  const query = {
128
135
  Eq: q.Eq,
129
136
  NotEq: q.NotEq,
@@ -163,6 +170,8 @@ const query = {
163
170
  TsVectorPlainToTsQuery: q.TsVectorPlainToTsQuery,
164
171
  TsVectorPhraseToTsQuery: q.TsVectorPhraseToTsQuery,
165
172
  TsVectorWebsearchToTsQuery: q.TsVectorWebsearchToTsQuery,
173
+ Expression: q.Expression,
174
+ ParameterizedExpression: q.ParameterizedExpression,
166
175
  };
167
176
  exports.query = query;
168
177
  var context_1 = require("./core/context");
@@ -174,4 +183,5 @@ var config_1 = require("./core/config");
174
183
  Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
175
184
  var logger_1 = require("./core/logger");
176
185
  Object.defineProperty(exports, "setLogLevels", { enumerable: true, get: function () { return logger_1.setLogLevels; } });
186
+ __exportStar(require("./core/metrics"), exports);
177
187
  __exportStar(require("./core/convert"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -9,17 +9,11 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@types/node": "^25.0.3",
12
- "cosmiconfig": "^9.0.0",
13
12
  "dataloader": "^2.2.3",
14
13
  "glob": "^13.0.0",
15
- "graph-data-structure": "^4.5.0",
16
14
  "js-yaml": "^4.1.1",
17
- "json5": "^2.2.3",
18
15
  "luxon": "^3.7.2",
19
- "memoizee": "^0.4.17",
20
- "minimist": "^1.2.8",
21
16
  "pg": "^8.16.3",
22
- "prettier": "^3.7.4",
23
17
  "ts-node": "^11.0.0-beta.1",
24
18
  "tsconfig-paths": "^4.2.0",
25
19
  "tslib": "^2.8.1",