@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.
- package/action/executor.js +4 -4
- package/action/operations.js +3 -0
- package/action/orchestrator.js +10 -12
- package/action/topological_sort.d.ts +9 -0
- package/action/topological_sort.js +46 -0
- package/core/async_utils.d.ts +1 -0
- package/core/async_utils.js +29 -0
- package/core/base.d.ts +12 -5
- package/core/clause.d.ts +3 -5
- package/core/clause.js +32 -0
- package/core/config.d.ts +28 -2
- package/core/config.js +14 -1
- package/core/context.d.ts +3 -1
- package/core/context.js +90 -26
- package/core/db.d.ts +12 -2
- package/core/db.js +102 -7
- package/core/dev_schema.d.ts +9 -0
- package/core/dev_schema.js +306 -0
- package/core/ent.d.ts +5 -7
- package/core/ent.js +33 -48
- package/core/extensions.d.ts +25 -0
- package/core/extensions.js +220 -0
- package/core/loaders/assoc_count_loader.js +3 -6
- package/core/loaders/assoc_edge_loader.d.ts +3 -0
- package/core/loaders/assoc_edge_loader.js +48 -19
- package/core/loaders/index.d.ts +2 -1
- package/core/loaders/index.js +5 -1
- package/core/loaders/loader.d.ts +31 -0
- package/core/loaders/loader.js +141 -2
- package/core/loaders/object_loader.d.ts +2 -2
- package/core/loaders/object_loader.js +39 -57
- package/core/loaders/query_loader.d.ts +2 -5
- package/core/loaders/query_loader.js +45 -24
- package/core/loaders/raw_count_loader.d.ts +2 -2
- package/core/loaders/raw_count_loader.js +12 -14
- package/core/memoize.d.ts +1 -0
- package/core/memoize.js +15 -0
- package/core/metrics.d.ts +22 -0
- package/core/metrics.js +31 -0
- package/core/query/custom_clause_query.js +5 -1
- package/core/query/query.d.ts +1 -1
- package/core/query/query.js +10 -7
- package/core/query_expression.d.ts +6 -0
- package/core/query_expression.js +2 -0
- package/core/query_impl.d.ts +19 -3
- package/core/query_impl.js +148 -35
- package/index.d.ts +7 -2
- package/index.js +12 -2
- package/package.json +1 -7
- package/parse_schema/parse.d.ts +2 -12
- package/parse_schema/parse.js +22 -41
- package/schema/index.d.ts +1 -1
- package/schema/schema.d.ts +20 -1
- package/scripts/custom_graphql.js +12 -5
- package/scripts/fix_action_exports.js +1 -1
- package/scripts/migrate_v0.1.js +2 -5
- package/scripts/move_types.js +1 -1
- package/scripts/read_schema.js +2 -5
- package/testutils/builder.js +1 -2
- package/testutils/parse_sql.js +1 -1
- package/tsc/compilerOptions.d.ts +2 -2
- package/tsc/compilerOptions.js +12 -18
- package/tsc/move_generated.js +2 -2
- package/tsc/transform.d.ts +1 -1
- package/tsc/transform.js +16 -2
- package/tsc/transform_action.d.ts +1 -1
- package/tsc/transform_action.js +1 -1
- package/tsc/transform_ent.d.ts +1 -1
- package/tsc/transform_ent.js +1 -1
- package/tsc/transform_schema.d.ts +1 -1
- package/tsc/transform_schema.js +2 -2
- /package/core/{loaders/cache_utils.d.ts → cache_utils.d.ts} +0 -0
- /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
|
-
|
|
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;
|
package/core/memoize.js
ADDED
|
@@ -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;
|
package/core/metrics.js
ADDED
|
@@ -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
|
-
?
|
|
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;
|
package/core/query/query.d.ts
CHANGED
|
@@ -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, "
|
|
87
|
+
protected getDefaultEdgeQueryOptions(): Partial<Pick<QueryableDataOptions, "limit" | "orderby" | "clause" | "disableTransformations">> | undefined;
|
|
88
88
|
private loadEdges;
|
|
89
89
|
getCursor(row: TEdge): string;
|
|
90
90
|
}
|
package/core/query/query.js
CHANGED
|
@@ -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 =
|
|
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,
|
|
320
|
-
this.genIDInfosToFetch = (0,
|
|
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;
|
package/core/query_impl.d.ts
CHANGED
|
@@ -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
|
-
|
|
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 {};
|
package/core/query_impl.js
CHANGED
|
@@ -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
|
-
|
|
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((
|
|
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 (
|
|
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 =
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
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
|
-
|
|
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 ${
|
|
164
|
+
return `${joinType} ${joinTable} ON ${renderedClause}`;
|
|
58
165
|
})
|
|
59
166
|
.join(" ");
|
|
60
167
|
return {
|
|
61
|
-
phrase
|
|
168
|
+
phrase,
|
|
62
169
|
valuesUsed,
|
|
170
|
+
values,
|
|
171
|
+
logValues,
|
|
63
172
|
};
|
|
64
173
|
}
|
|
65
|
-
function
|
|
174
|
+
function buildQueryData(options) {
|
|
66
175
|
const fieldsAlias = options.fieldsAlias ?? options.alias;
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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 ${
|
|
185
|
+
parts.push(`SELECT DISTINCT ${fieldInfo.phrase} FROM ${tableName}`);
|
|
88
186
|
}
|
|
89
187
|
else {
|
|
90
|
-
parts.push(`SELECT ${
|
|
188
|
+
parts.push(`SELECT ${fieldInfo.phrase} FROM ${tableName}`);
|
|
91
189
|
}
|
|
92
|
-
let whereStart = 1;
|
|
93
190
|
if (options.join) {
|
|
94
|
-
const
|
|
95
|
-
parts.push(phrase);
|
|
96
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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",
|