@snowtop/ent 0.1.0-alpha126 → 0.1.0-alpha128
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/core/base.d.ts +8 -7
- package/core/clause.d.ts +2 -1
- package/core/clause.js +18 -1
- package/core/ent.d.ts +10 -10
- package/core/ent.js +35 -54
- package/core/global_schema.d.ts +7 -0
- package/core/global_schema.js +51 -0
- package/core/loaders/assoc_edge_loader.d.ts +1 -1
- package/core/loaders/object_loader.d.ts +28 -8
- package/core/loaders/object_loader.js +176 -39
- package/core/loaders/query_loader.d.ts +1 -1
- package/core/query/shared_test.js +2 -1
- package/graphql/graphql.d.ts +1 -1
- package/graphql/graphql.js +1 -0
- package/index.d.ts +2 -1
- package/index.js +2 -1
- package/package.json +1 -1
- package/parse_schema/parse.d.ts +2 -1
- package/parse_schema/parse.js +11 -3
- package/schema/field.d.ts +5 -3
- package/schema/field.js +69 -15
- package/schema/schema.d.ts +2 -0
- package/schema/struct_field.d.ts +8 -6
- package/schema/struct_field.js +67 -8
- package/schema/union_field.d.ts +1 -1
package/core/base.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as clause from "./clause";
|
|
2
|
+
import { ObjectLoaderFactory } from "./loaders";
|
|
2
3
|
export interface Loader<K, V> {
|
|
3
4
|
context?: Context;
|
|
4
5
|
load(key: K): Promise<V>;
|
|
@@ -95,21 +96,21 @@ export interface EditRowOptions extends CreateRowOptions {
|
|
|
95
96
|
whereClause: clause.Clause;
|
|
96
97
|
expressions?: Map<string, clause.Clause>;
|
|
97
98
|
}
|
|
98
|
-
interface LoadableEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer> {
|
|
99
|
-
loaderFactory:
|
|
99
|
+
interface LoadableEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer, TData extends Data = Data> {
|
|
100
|
+
loaderFactory: ObjectLoaderFactory<TData>;
|
|
100
101
|
ent: EntConstructor<TEnt, TViewer>;
|
|
101
102
|
}
|
|
102
|
-
export interface LoaderFactoryWithOptions extends LoaderFactoryWithLoaderMany<any,
|
|
103
|
+
export interface LoaderFactoryWithOptions<T extends Data = Data> extends LoaderFactoryWithLoaderMany<any, T | null> {
|
|
103
104
|
options?: SelectDataOptions;
|
|
104
105
|
}
|
|
105
|
-
export interface LoadEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer> extends LoadableEntOptions<TEnt, TViewer>, SelectBaseDataOptions {
|
|
106
|
+
export interface LoadEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer, TData extends Data = Data> extends LoadableEntOptions<TEnt, TViewer, TData>, SelectBaseDataOptions {
|
|
106
107
|
fieldPrivacy?: Map<string, PrivacyPolicy>;
|
|
107
108
|
}
|
|
108
|
-
export interface SelectCustomDataOptions extends SelectBaseDataOptions {
|
|
109
|
-
loaderFactory:
|
|
109
|
+
export interface SelectCustomDataOptions<T extends Data = Data> extends SelectBaseDataOptions {
|
|
110
|
+
loaderFactory: ObjectLoaderFactory<T>;
|
|
110
111
|
prime?: boolean;
|
|
111
112
|
}
|
|
112
|
-
export interface LoadCustomEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer> extends SelectCustomDataOptions {
|
|
113
|
+
export interface LoadCustomEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer, TData extends Data = Data> extends SelectCustomDataOptions<TData> {
|
|
113
114
|
ent: EntConstructor<TEnt, TViewer>;
|
|
114
115
|
fieldPrivacy?: Map<string, PrivacyPolicy>;
|
|
115
116
|
}
|
package/core/clause.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Data } from "./base";
|
|
1
|
+
import { Data, SelectDataOptions } from "./base";
|
|
2
2
|
export interface Clause<T extends Data = Data, K = keyof T> {
|
|
3
3
|
clause(idx: number): string;
|
|
4
4
|
columns(): K[];
|
|
@@ -102,4 +102,5 @@ export declare function Subtract<T extends Data, K = keyof T>(col: K, value: any
|
|
|
102
102
|
export declare function Multiply<T extends Data, K = keyof T>(col: K, value: any): Clause<T, K>;
|
|
103
103
|
export declare function Divide<T extends Data, K = keyof T>(col: K, value: any): Clause<T, K>;
|
|
104
104
|
export declare function Modulo<T extends Data, K = keyof T>(col: K, value: any): Clause<T, K>;
|
|
105
|
+
export declare function getCombinedClause<V extends Data = Data, K = keyof V>(options: Omit<SelectDataOptions, "key">, cls: Clause<V, K>): Clause<V, K>;
|
|
105
106
|
export {};
|
package/core/clause.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.Modulo = exports.Divide = exports.Multiply = exports.Subtract = exports.Add = exports.PaginationMultipleColsSubQuery = exports.JSONPathValuePredicate = exports.JSONObjectFieldKeyAsText = exports.JSONObjectFieldKeyASJSON = exports.sensitiveValue = exports.TsVectorWebsearchToTsQuery = exports.TsVectorPhraseToTsQuery = exports.TsVectorPlainToTsQuery = exports.TsVectorColTsQuery = exports.WebsearchToTsQuery = exports.PhraseToTsQuery = exports.PlainToTsQuery = exports.TsQuery = exports.In = exports.OrOptional = exports.Or = exports.AndOptional = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.NotEq = exports.Eq = exports.ArrayNotEq = exports.ArrayEq = exports.PostgresArrayNotOverlaps = exports.PostgresArrayOverlaps = exports.PostgresArrayNotContains = exports.PostgresArrayNotContainsValue = exports.PostgresArrayContains = exports.PostgresArrayContainsValue = exports.inClause = void 0;
|
|
26
|
+
exports.getCombinedClause = exports.Modulo = exports.Divide = exports.Multiply = exports.Subtract = exports.Add = exports.PaginationMultipleColsSubQuery = exports.JSONPathValuePredicate = exports.JSONObjectFieldKeyAsText = exports.JSONObjectFieldKeyASJSON = exports.sensitiveValue = exports.TsVectorWebsearchToTsQuery = exports.TsVectorPhraseToTsQuery = exports.TsVectorPlainToTsQuery = exports.TsVectorColTsQuery = exports.WebsearchToTsQuery = exports.PhraseToTsQuery = exports.PlainToTsQuery = exports.TsQuery = exports.In = exports.OrOptional = exports.Or = exports.AndOptional = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.NotEq = exports.Eq = exports.ArrayNotEq = exports.ArrayEq = exports.PostgresArrayNotOverlaps = exports.PostgresArrayOverlaps = exports.PostgresArrayNotContains = exports.PostgresArrayNotContainsValue = exports.PostgresArrayContains = exports.PostgresArrayContainsValue = exports.inClause = void 0;
|
|
27
27
|
const db_1 = __importStar(require("./db"));
|
|
28
28
|
function isSensitive(val) {
|
|
29
29
|
return (val !== null &&
|
|
@@ -731,3 +731,20 @@ function Modulo(col, value) {
|
|
|
731
731
|
return new simpleClause(col, value, "%", new isNullClause(col));
|
|
732
732
|
}
|
|
733
733
|
exports.Modulo = Modulo;
|
|
734
|
+
function getCombinedClause(options, cls) {
|
|
735
|
+
if (options.clause) {
|
|
736
|
+
let optionClause;
|
|
737
|
+
if (typeof options.clause === "function") {
|
|
738
|
+
optionClause = options.clause();
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
optionClause = options.clause;
|
|
742
|
+
}
|
|
743
|
+
if (optionClause) {
|
|
744
|
+
// @ts-expect-error different types
|
|
745
|
+
cls = And(cls, optionClause);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return cls;
|
|
749
|
+
}
|
|
750
|
+
exports.getCombinedClause = getCombinedClause;
|
package/core/ent.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { Executor } from "../action/action";
|
|
|
4
4
|
import * as clause from "./clause";
|
|
5
5
|
import { Builder } from "../action";
|
|
6
6
|
import DataLoader from "dataloader";
|
|
7
|
-
import { GlobalSchema } from "../schema/";
|
|
8
7
|
export declare function getEntKey<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, id: ID, options: LoadEntOptions<TEnt, TViewer>): string;
|
|
9
8
|
export declare function loadEnt<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, id: ID, options: LoadEntOptions<TEnt, TViewer>): Promise<TEnt | null>;
|
|
10
9
|
export declare function loadEntViaKey<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, key: any, options: LoadEntOptions<TEnt, TViewer>): Promise<TEnt | null>;
|
|
@@ -24,13 +23,13 @@ export declare function loadEntsList<TEnt extends Ent<TViewer>, TViewer extends
|
|
|
24
23
|
* @deperecated use loadCustomEnts
|
|
25
24
|
*/
|
|
26
25
|
export declare function loadEntsFromClause<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, clause: clause.Clause, options: LoadEntOptions<TEnt, TViewer>): Promise<Map<ID, TEnt>>;
|
|
27
|
-
export declare function loadCustomEnts<TEnt extends Ent<TViewer>, TViewer extends Viewer, TQueryData extends Data = Data, TResultData extends Data = TQueryData, TKey = keyof TQueryData>(viewer: TViewer, options: LoadCustomEntOptions<TEnt, TViewer>, query: CustomQuery<TQueryData, TKey>): Promise<TEnt[]>;
|
|
26
|
+
export declare function loadCustomEnts<TEnt extends Ent<TViewer>, TViewer extends Viewer, TQueryData extends Data = Data, TResultData extends Data = TQueryData, TKey = keyof TQueryData>(viewer: TViewer, options: LoadCustomEntOptions<TEnt, TViewer, TResultData>, query: CustomQuery<TQueryData, TKey>): Promise<TEnt[]>;
|
|
28
27
|
interface parameterizedQueryOptions {
|
|
29
28
|
query: string;
|
|
30
29
|
values?: any[];
|
|
31
30
|
logValues?: any[];
|
|
32
31
|
}
|
|
33
|
-
export type CustomQuery<T extends Data = Data, K = keyof T> = string | parameterizedQueryOptions | clause.Clause<T, K> | QueryDataOptions
|
|
32
|
+
export type CustomQuery<T extends Data = Data, K = keyof T> = string | parameterizedQueryOptions | clause.Clause<T, K> | QueryDataOptions<T, K>;
|
|
34
33
|
/**
|
|
35
34
|
* Note that if there's default read transformations (e.g. soft delete) and a clause is passed in
|
|
36
35
|
* either as Clause or QueryDataOptions without {disableTransformations: true}, the default transformation
|
|
@@ -54,11 +53,15 @@ export type CustomQuery<T extends Data = Data, K = keyof T> = string | parameter
|
|
|
54
53
|
* orderby: 'time',
|
|
55
54
|
* disableTransformations: false
|
|
56
55
|
* }) // doesn't change the query
|
|
56
|
+
*
|
|
57
|
+
* For queries that pass in a clause, we batch them with an underlying dataloader so that multiple queries with the same clause
|
|
58
|
+
* or parallel queries with the same clause are batched together.
|
|
59
|
+
*
|
|
60
|
+
* If a raw or parameterized query is passed in, we don't attempt to batch them together and they're executed as is.
|
|
61
|
+
* If you end up with a scenario where you may need to coalesce or batch (non-clause) queries here, you should use some kind of memoization here.
|
|
57
62
|
*/
|
|
58
|
-
export declare function loadCustomData<TQueryData extends Data = Data, TResultData extends Data = TQueryData, K = keyof TQueryData>(options: SelectCustomDataOptions
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
export declare function loadCustomCount<T extends Data = Data, K = keyof T>(options: CustomCountOptions, query: CustomQuery<T, K>, context: Context | undefined): Promise<number>;
|
|
63
|
+
export declare function loadCustomData<TQueryData extends Data = Data, TResultData extends Data = TQueryData, K = keyof TQueryData>(options: SelectCustomDataOptions<TResultData>, query: CustomQuery<TQueryData, K>, context: Context | undefined): Promise<TResultData[]>;
|
|
64
|
+
export declare function loadCustomCount<T extends Data = Data, K = keyof T>(options: SelectCustomDataOptions<T>, query: CustomQuery<T, K>, context: Context | undefined): Promise<number>;
|
|
62
65
|
export declare function loadDerivedEnt<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, data: Data, loader: new (viewer: TViewer, data: Data) => TEnt): Promise<TEnt | null>;
|
|
63
66
|
export declare function loadDerivedEntX<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, data: Data, loader: new (viewer: TViewer, data: Data) => TEnt): Promise<TEnt>;
|
|
64
67
|
export declare function logQuery(query: string, logValues: any[]): void;
|
|
@@ -114,9 +117,6 @@ export declare class EditNodeOperation<T extends Ent> implements DataOperation {
|
|
|
114
117
|
returnedRow(): Data | null;
|
|
115
118
|
createdEnt(viewer: Viewer): T | null;
|
|
116
119
|
}
|
|
117
|
-
export declare function setGlobalSchema(val: GlobalSchema): void;
|
|
118
|
-
export declare function clearGlobalSchema(): void;
|
|
119
|
-
export declare function __hasGlobalSchema(): boolean;
|
|
120
120
|
export declare class EdgeOperation implements DataOperation {
|
|
121
121
|
private builder;
|
|
122
122
|
edgeInput: AssocEdgeInput;
|
package/core/ent.js
CHANGED
|
@@ -26,15 +26,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadCustomEdges = exports.getEdgeClauseAndFields = exports.loadEdges = exports.DefaultLimit = exports.loadEdgeDatas = exports.loadEdgeData = exports.assocEdgeLoader = exports.AssocEdgeData = exports.getCursor = exports.AssocEdge = exports.DeleteNodeOperation = exports.deleteRowsSync = exports.deleteRows = exports.editRowSync = exports.editRow = exports.buildUpdateQuery = exports.createRowSync = exports.createRow = exports.buildInsertQuery = exports.EdgeOperation = exports.
|
|
30
|
-
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows = exports.applyPrivacyPolicyForRow =
|
|
29
|
+
exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadCustomEdges = exports.getEdgeClauseAndFields = exports.loadEdges = exports.DefaultLimit = exports.loadEdgeDatas = exports.loadEdgeData = exports.assocEdgeLoader = exports.AssocEdgeData = exports.getCursor = exports.AssocEdge = exports.DeleteNodeOperation = exports.deleteRowsSync = exports.deleteRows = exports.editRowSync = exports.editRow = exports.buildUpdateQuery = exports.createRowSync = exports.createRow = exports.buildInsertQuery = exports.EdgeOperation = exports.EditNodeOperation = exports.RawQueryOperation = exports.buildGroupQuery = exports.buildQuery = exports.loadRows = exports.performRawQuery = exports.___setLogQueryErrorWithError = exports.loadRow = exports.loadRowX = exports.logQuery = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadCustomCount = exports.loadCustomData = exports.loadCustomEnts = exports.loadEntsFromClause = exports.loadEntsList = exports.loadEnts = exports.loadEntXFromClause = exports.loadEntFromClause = exports.loadEntXViaKey = exports.loadEntX = exports.loadEntViaKey = exports.loadEnt = exports.getEntKey = void 0;
|
|
30
|
+
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows = exports.applyPrivacyPolicyForRow = void 0;
|
|
31
31
|
const db_1 = __importStar(require("./db"));
|
|
32
32
|
const privacy_1 = require("./privacy");
|
|
33
33
|
const clause = __importStar(require("./clause"));
|
|
34
34
|
const action_1 = require("../action");
|
|
35
35
|
const logger_1 = require("./logger");
|
|
36
36
|
const dataloader_1 = __importDefault(require("dataloader"));
|
|
37
|
-
const schema_1 = require("../schema/");
|
|
37
|
+
const schema_1 = require("../schema/schema");
|
|
38
|
+
const global_schema_1 = require("./global_schema");
|
|
38
39
|
// TODO kill this and createDataLoader
|
|
39
40
|
class cacheMap {
|
|
40
41
|
constructor(options) {
|
|
@@ -396,6 +397,12 @@ function isParameterizedQuery(opts) {
|
|
|
396
397
|
* orderby: 'time',
|
|
397
398
|
* disableTransformations: false
|
|
398
399
|
* }) // doesn't change the query
|
|
400
|
+
*
|
|
401
|
+
* For queries that pass in a clause, we batch them with an underlying dataloader so that multiple queries with the same clause
|
|
402
|
+
* or parallel queries with the same clause are batched together.
|
|
403
|
+
*
|
|
404
|
+
* If a raw or parameterized query is passed in, we don't attempt to batch them together and they're executed as is.
|
|
405
|
+
* If you end up with a scenario where you may need to coalesce or batch (non-clause) queries here, you should use some kind of memoization here.
|
|
399
406
|
*/
|
|
400
407
|
async function loadCustomData(options, query, context) {
|
|
401
408
|
const rows = await loadCustomDataImpl(options, query, context);
|
|
@@ -414,7 +421,10 @@ exports.loadCustomData = loadCustomData;
|
|
|
414
421
|
// NOTE: if you use a raw query or paramterized query with this,
|
|
415
422
|
// you should use `SELECT count(*) as count...`
|
|
416
423
|
async function loadCustomCount(options, query, context) {
|
|
417
|
-
//
|
|
424
|
+
// if clause, we'll use the loader and strong typing/coalescing it provides
|
|
425
|
+
if (typeof query !== "string" && isClause(query)) {
|
|
426
|
+
return options.loaderFactory.createCountLoader(context).load(query);
|
|
427
|
+
}
|
|
418
428
|
const rows = await loadCustomDataImpl({
|
|
419
429
|
...options,
|
|
420
430
|
fields: ["count(1) as count"],
|
|
@@ -429,50 +439,31 @@ function isPrimableLoader(loader) {
|
|
|
429
439
|
return loader != undefined;
|
|
430
440
|
}
|
|
431
441
|
async function loadCustomDataImpl(options, query, context) {
|
|
432
|
-
function getClause(cls) {
|
|
433
|
-
let optClause = options.loaderFactory?.options?.clause;
|
|
434
|
-
if (typeof optClause === "function") {
|
|
435
|
-
optClause = optClause();
|
|
436
|
-
}
|
|
437
|
-
if (!optClause) {
|
|
438
|
-
return cls;
|
|
439
|
-
}
|
|
440
|
-
// @ts-expect-error string|ID mismatch
|
|
441
|
-
return clause.And(cls, optClause);
|
|
442
|
-
}
|
|
443
442
|
if (typeof query === "string") {
|
|
444
443
|
// no caching, perform raw query
|
|
445
444
|
return performRawQuery(query, [], []);
|
|
446
|
-
// @ts-ignore
|
|
447
445
|
}
|
|
448
446
|
else if (isClause(query)) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
// this will have rudimentary caching but nothing crazy
|
|
454
|
-
return loadRows({
|
|
455
|
-
...options,
|
|
456
|
-
// @ts-ignore
|
|
457
|
-
clause: getClause(query),
|
|
458
|
-
context: context,
|
|
459
|
-
});
|
|
447
|
+
const r = await options.loaderFactory
|
|
448
|
+
.createTypedLoader(context)
|
|
449
|
+
.load(query);
|
|
450
|
+
return r;
|
|
460
451
|
}
|
|
461
452
|
else if (isParameterizedQuery(query)) {
|
|
462
453
|
// no caching, perform raw query
|
|
463
454
|
return performRawQuery(query.query, query.values || [], query.logValues);
|
|
464
455
|
}
|
|
465
456
|
else {
|
|
457
|
+
// this will have rudimentary caching but nothing crazy
|
|
466
458
|
let cls = query.clause;
|
|
467
459
|
if (!query.disableTransformations) {
|
|
468
|
-
|
|
469
|
-
cls = getClause(cls);
|
|
460
|
+
cls = clause.getCombinedClause(options.loaderFactory.options, query.clause);
|
|
470
461
|
}
|
|
471
|
-
// this will have rudimentary caching but nothing crazy
|
|
472
462
|
return loadRows({
|
|
473
463
|
...query,
|
|
474
464
|
...options,
|
|
475
465
|
context: context,
|
|
466
|
+
// @ts-expect-error
|
|
476
467
|
clause: cls,
|
|
477
468
|
});
|
|
478
469
|
}
|
|
@@ -609,7 +600,7 @@ async function performRawQuery(query, values, logValues) {
|
|
|
609
600
|
catch (e) {
|
|
610
601
|
if (_logQueryWithError) {
|
|
611
602
|
const msg = e.message;
|
|
612
|
-
throw new Error(`error \`${msg}\` running query: \`${query}\``);
|
|
603
|
+
throw new Error(`error \`${msg}\` running query: \`${query}\` with values: \`${logValues}\``);
|
|
613
604
|
}
|
|
614
605
|
throw e;
|
|
615
606
|
}
|
|
@@ -816,20 +807,6 @@ class EditNodeOperation {
|
|
|
816
807
|
}
|
|
817
808
|
}
|
|
818
809
|
exports.EditNodeOperation = EditNodeOperation;
|
|
819
|
-
let globalSchema;
|
|
820
|
-
function setGlobalSchema(val) {
|
|
821
|
-
globalSchema = val;
|
|
822
|
-
}
|
|
823
|
-
exports.setGlobalSchema = setGlobalSchema;
|
|
824
|
-
function clearGlobalSchema() {
|
|
825
|
-
globalSchema = undefined;
|
|
826
|
-
}
|
|
827
|
-
exports.clearGlobalSchema = clearGlobalSchema;
|
|
828
|
-
// used by tests. no guarantee will always exist
|
|
829
|
-
function __hasGlobalSchema() {
|
|
830
|
-
return globalSchema !== undefined;
|
|
831
|
-
}
|
|
832
|
-
exports.__hasGlobalSchema = __hasGlobalSchema;
|
|
833
810
|
class EdgeOperation {
|
|
834
811
|
constructor(builder, edgeInput, options) {
|
|
835
812
|
this.builder = builder;
|
|
@@ -872,8 +849,9 @@ class EdgeOperation {
|
|
|
872
849
|
let op = schema_1.SQLStatementOperation.Delete;
|
|
873
850
|
let updateData = null;
|
|
874
851
|
// TODO respect disableTransformations
|
|
875
|
-
|
|
876
|
-
|
|
852
|
+
const transformedEdgeWrite = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeWrite;
|
|
853
|
+
if (transformedEdgeWrite) {
|
|
854
|
+
transformed = transformedEdgeWrite({
|
|
877
855
|
op: schema_1.SQLStatementOperation.Delete,
|
|
878
856
|
edge,
|
|
879
857
|
});
|
|
@@ -951,9 +929,10 @@ class EdgeOperation {
|
|
|
951
929
|
fields["time"] = new Date().toISOString();
|
|
952
930
|
}
|
|
953
931
|
const onConflictFields = ["data"];
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
932
|
+
const extraEdgeFields = (0, global_schema_1.__getGlobalSchema)()?.extraEdgeFields;
|
|
933
|
+
if (extraEdgeFields) {
|
|
934
|
+
for (const name in extraEdgeFields) {
|
|
935
|
+
const f = extraEdgeFields[name];
|
|
957
936
|
if (f.defaultValueOnCreate) {
|
|
958
937
|
const storageKey = (0, schema_1.getStorageKey)(f, name);
|
|
959
938
|
fields[storageKey] = f.defaultValueOnCreate(this.builder, {});
|
|
@@ -965,8 +944,9 @@ class EdgeOperation {
|
|
|
965
944
|
}
|
|
966
945
|
// TODO respect disableTransformations
|
|
967
946
|
let transformed = null;
|
|
968
|
-
|
|
969
|
-
|
|
947
|
+
const transformEdgeWrite = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeWrite;
|
|
948
|
+
if (transformEdgeWrite) {
|
|
949
|
+
transformed = transformEdgeWrite({
|
|
970
950
|
op: schema_1.SQLStatementOperation.Insert,
|
|
971
951
|
edge,
|
|
972
952
|
});
|
|
@@ -1483,8 +1463,9 @@ async function loadEdges(options) {
|
|
|
1483
1463
|
exports.loadEdges = loadEdges;
|
|
1484
1464
|
function getEdgeClauseAndFields(cls, options) {
|
|
1485
1465
|
let fields = edgeFields;
|
|
1486
|
-
|
|
1487
|
-
|
|
1466
|
+
const transformEdgeRead = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeRead;
|
|
1467
|
+
if (transformEdgeRead) {
|
|
1468
|
+
const transformClause = transformEdgeRead();
|
|
1488
1469
|
if (!options.disableTransformations) {
|
|
1489
1470
|
cls = clause.And(cls, transformClause);
|
|
1490
1471
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Field, GlobalSchema } from "../schema/schema";
|
|
2
|
+
export declare function setGlobalSchema(val: GlobalSchema): void;
|
|
3
|
+
export declare function clearGlobalSchema(): void;
|
|
4
|
+
export declare function __hasGlobalSchema(): boolean;
|
|
5
|
+
export declare function __getGlobalSchema(): GlobalSchema | undefined;
|
|
6
|
+
export declare function __getGlobalSchemaFields(): Map<string, Field>;
|
|
7
|
+
export declare function __getGlobalSchemaField(type: string): Field | undefined;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__getGlobalSchemaField = exports.__getGlobalSchemaFields = exports.__getGlobalSchema = exports.__hasGlobalSchema = exports.clearGlobalSchema = exports.setGlobalSchema = void 0;
|
|
4
|
+
const schema_1 = require("../schema/schema");
|
|
5
|
+
let globalSchema;
|
|
6
|
+
let globalSchemaFields = new Map();
|
|
7
|
+
function isGlobalSchemaField(f) {
|
|
8
|
+
switch (f.type.dbType) {
|
|
9
|
+
case schema_1.DBType.Enum:
|
|
10
|
+
case schema_1.DBType.StringEnum:
|
|
11
|
+
case schema_1.DBType.IntEnum:
|
|
12
|
+
case schema_1.DBType.JSON:
|
|
13
|
+
case schema_1.DBType.JSONB:
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
function setGlobalSchema(val) {
|
|
19
|
+
globalSchema = val;
|
|
20
|
+
if (val.fields) {
|
|
21
|
+
for (const [k, v] of Object.entries(val.fields)) {
|
|
22
|
+
if (isGlobalSchemaField(v) && v.type.type) {
|
|
23
|
+
globalSchemaFields.set(v.type.type, v);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.setGlobalSchema = setGlobalSchema;
|
|
29
|
+
function clearGlobalSchema() {
|
|
30
|
+
globalSchema = undefined;
|
|
31
|
+
globalSchemaFields.clear();
|
|
32
|
+
}
|
|
33
|
+
exports.clearGlobalSchema = clearGlobalSchema;
|
|
34
|
+
// used by tests. no guarantee will always exist
|
|
35
|
+
function __hasGlobalSchema() {
|
|
36
|
+
return globalSchema !== undefined;
|
|
37
|
+
}
|
|
38
|
+
exports.__hasGlobalSchema = __hasGlobalSchema;
|
|
39
|
+
// used by tests. no guarantee will always exist
|
|
40
|
+
function __getGlobalSchema() {
|
|
41
|
+
return globalSchema;
|
|
42
|
+
}
|
|
43
|
+
exports.__getGlobalSchema = __getGlobalSchema;
|
|
44
|
+
function __getGlobalSchemaFields() {
|
|
45
|
+
return globalSchemaFields;
|
|
46
|
+
}
|
|
47
|
+
exports.__getGlobalSchemaFields = __getGlobalSchemaFields;
|
|
48
|
+
function __getGlobalSchemaField(type) {
|
|
49
|
+
return globalSchemaFields.get(type);
|
|
50
|
+
}
|
|
51
|
+
exports.__getGlobalSchemaField = __getGlobalSchemaField;
|
|
@@ -21,7 +21,7 @@ export declare class AssocDirectEdgeLoader<T extends AssocEdge> implements Loade
|
|
|
21
21
|
private edgeCtr;
|
|
22
22
|
private options?;
|
|
23
23
|
context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
|
|
24
|
-
constructor(edgeType: string, edgeCtr: AssocEdgeConstructor<T>, options?: Partial<Pick<import("../base").QueryableDataOptions, "
|
|
24
|
+
constructor(edgeType: string, edgeCtr: AssocEdgeConstructor<T>, options?: Partial<Pick<import("../base").QueryableDataOptions, "clause" | "limit" | "orderby">> | undefined, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined);
|
|
25
25
|
load(id: ID): Promise<T[]>;
|
|
26
26
|
loadEdgeForID2(id: ID, id2: ID): Promise<T | undefined>;
|
|
27
27
|
clearAll(): void;
|
|
@@ -1,29 +1,49 @@
|
|
|
1
1
|
import { ID, Data, SelectDataOptions, Context, Loader, LoaderFactory } from "../base";
|
|
2
|
-
|
|
2
|
+
import * as clause from "../clause";
|
|
3
|
+
export declare class ObjectLoader<TQueryData extends Data = Data, TResultData extends Data = TQueryData, K = keyof TQueryData> implements Loader<ID, TResultData | null>, Loader<clause.Clause<TQueryData, K>, TResultData[] | null> {
|
|
3
4
|
private options;
|
|
4
5
|
context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
|
|
5
6
|
private toPrime?;
|
|
6
|
-
private
|
|
7
|
+
private idLoader;
|
|
8
|
+
private clauseLoader;
|
|
7
9
|
private primedLoaders;
|
|
8
10
|
private memoizedInitPrime;
|
|
9
|
-
constructor(options: SelectDataOptions, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined, toPrime?: ObjectLoaderFactory<
|
|
11
|
+
constructor(options: SelectDataOptions, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined, toPrime?: ObjectLoaderFactory<TResultData>[] | undefined);
|
|
10
12
|
getOptions(): SelectDataOptions;
|
|
11
13
|
private initPrime;
|
|
12
|
-
load(key: ID): Promise<
|
|
14
|
+
load(key: ID): Promise<TResultData | null>;
|
|
15
|
+
load(key: clause.Clause<TQueryData, K>): Promise<TResultData[] | null>;
|
|
16
|
+
private loadID;
|
|
17
|
+
private loadClause;
|
|
18
|
+
clearAll(): void;
|
|
19
|
+
loadMany(keys: ID[]): Promise<Array<TResultData | null>>;
|
|
20
|
+
loadMany(keys: clause.Clause<TQueryData, K>[]): Promise<Array<TResultData[] | null>>;
|
|
21
|
+
private loadIDMany;
|
|
22
|
+
private loadClauseMany;
|
|
23
|
+
prime(data: TResultData): void;
|
|
24
|
+
primeAll(data: TResultData): void;
|
|
25
|
+
}
|
|
26
|
+
export declare class ObjectCountLoader<V extends Data = Data, K = keyof V> implements Loader<clause.Clause<V, K>, number> {
|
|
27
|
+
private options;
|
|
28
|
+
context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
|
|
29
|
+
private loader;
|
|
30
|
+
constructor(options: SelectDataOptions, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined);
|
|
31
|
+
getOptions(): SelectDataOptions;
|
|
32
|
+
load(key: clause.Clause<V, K>): Promise<number>;
|
|
13
33
|
clearAll(): void;
|
|
14
|
-
loadMany(keys:
|
|
15
|
-
prime(data: V): void;
|
|
16
|
-
primeAll(data: V): void;
|
|
34
|
+
loadMany(keys: clause.Clause<V, K>[]): Promise<Array<number>>;
|
|
17
35
|
}
|
|
18
36
|
interface ObjectLoaderOptions extends SelectDataOptions {
|
|
19
37
|
instanceKey?: string;
|
|
20
38
|
}
|
|
21
|
-
export declare class ObjectLoaderFactory<V = Data> implements LoaderFactory<ID, V | null> {
|
|
39
|
+
export declare class ObjectLoaderFactory<V extends Data = Data> implements LoaderFactory<ID, V | null>, LoaderFactory<clause.Clause<V>, V[] | null> {
|
|
22
40
|
options: ObjectLoaderOptions;
|
|
23
41
|
name: string;
|
|
24
42
|
private toPrime;
|
|
25
43
|
constructor(options: ObjectLoaderOptions);
|
|
26
44
|
createLoader(context?: Context): ObjectLoader<V>;
|
|
45
|
+
createTypedLoader<TQueryData extends Data = Data, TResultData extends Data = Data, K = keyof TQueryData>(context?: Context): ObjectLoader<TQueryData, TResultData, K>;
|
|
46
|
+
createCountLoader<K = keyof V>(context?: Context): ObjectCountLoader<V, K>;
|
|
27
47
|
addToPrime(factory: ObjectLoaderFactory<V>): this;
|
|
28
48
|
}
|
|
29
49
|
export {};
|
|
@@ -26,29 +26,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.ObjectLoaderFactory = exports.ObjectLoader = void 0;
|
|
29
|
+
exports.ObjectLoaderFactory = exports.ObjectCountLoader = exports.ObjectLoader = void 0;
|
|
30
30
|
const dataloader_1 = __importDefault(require("dataloader"));
|
|
31
31
|
const ent_1 = require("../ent");
|
|
32
32
|
const clause = __importStar(require("../clause"));
|
|
33
33
|
const logger_1 = require("../logger");
|
|
34
|
+
const clause_1 = require("../clause");
|
|
34
35
|
const loader_1 = require("./loader");
|
|
35
36
|
const memoizee_1 = __importDefault(require("memoizee"));
|
|
36
|
-
async function
|
|
37
|
+
async function loadRowsForIDLoader(options, ids, context) {
|
|
37
38
|
let col = options.key;
|
|
38
|
-
|
|
39
|
-
if (options.clause) {
|
|
40
|
-
let optionClause;
|
|
41
|
-
if (typeof options.clause === "function") {
|
|
42
|
-
optionClause = options.clause();
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
optionClause = options.clause;
|
|
46
|
-
}
|
|
47
|
-
if (optionClause) {
|
|
48
|
-
// @ts-expect-error id/string mismatch
|
|
49
|
-
cls = clause.And(cls, optionClause);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
39
|
+
const cls = (0, clause_1.getCombinedClause)(options, clause.In(col, ...ids));
|
|
52
40
|
const rowOptions = {
|
|
53
41
|
...options,
|
|
54
42
|
clause: cls,
|
|
@@ -75,6 +63,29 @@ async function loadRowsForLoader(options, ids, context) {
|
|
|
75
63
|
}
|
|
76
64
|
return result;
|
|
77
65
|
}
|
|
66
|
+
async function loadRowsForClauseLoader(options, clause) {
|
|
67
|
+
const rowOptions = {
|
|
68
|
+
...options,
|
|
69
|
+
// @ts-expect-error clause in LoadRowOptions doesn't take templatized version of Clause
|
|
70
|
+
clause: (0, clause_1.getCombinedClause)(options, clause),
|
|
71
|
+
};
|
|
72
|
+
return (await (0, ent_1.loadRows)(rowOptions));
|
|
73
|
+
}
|
|
74
|
+
async function loadCountForClauseLoader(options, clause) {
|
|
75
|
+
const rowOptions = {
|
|
76
|
+
...options,
|
|
77
|
+
// @ts-expect-error clause in LoadRowOptions doesn't take templatized version of Clause
|
|
78
|
+
clause: (0, clause_1.getCombinedClause)(options, clause),
|
|
79
|
+
};
|
|
80
|
+
const row = await (0, ent_1.loadRow)({
|
|
81
|
+
...rowOptions,
|
|
82
|
+
fields: ["count(*) as count"],
|
|
83
|
+
});
|
|
84
|
+
if (!row) {
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
return parseInt(row.count, 10);
|
|
88
|
+
}
|
|
78
89
|
// optional clause...
|
|
79
90
|
// so ObjectLoaderFactory and createDataLoader need to take a new optional field which is a clause that's always added here
|
|
80
91
|
// and we need a disableTransform which skips loader completely and uses loadRow...
|
|
@@ -89,9 +100,66 @@ function createDataLoader(options) {
|
|
|
89
100
|
return [];
|
|
90
101
|
}
|
|
91
102
|
// context not needed because we're creating a loader which has its own cache which is being used here
|
|
92
|
-
return
|
|
103
|
+
return loadRowsForIDLoader(options, ids);
|
|
93
104
|
}, loaderOptions);
|
|
94
105
|
}
|
|
106
|
+
class clauseCacheMap {
|
|
107
|
+
constructor(options, count) {
|
|
108
|
+
this.options = options;
|
|
109
|
+
this.count = count;
|
|
110
|
+
this.m = new Map();
|
|
111
|
+
}
|
|
112
|
+
get(key) {
|
|
113
|
+
const key2 = key.instanceKey();
|
|
114
|
+
const ret = this.m.get(key2);
|
|
115
|
+
if (ret) {
|
|
116
|
+
(0, logger_1.log)("cache", {
|
|
117
|
+
"dataloader-cache-hit": key2 + (this.count ? ":count" : ""),
|
|
118
|
+
"tableName": this.options.tableName,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return ret;
|
|
122
|
+
}
|
|
123
|
+
set(key, value) {
|
|
124
|
+
return this.m.set(key.instanceKey(), value);
|
|
125
|
+
}
|
|
126
|
+
delete(key) {
|
|
127
|
+
return this.m.delete(key.instanceKey());
|
|
128
|
+
}
|
|
129
|
+
clear() {
|
|
130
|
+
return this.m.clear();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function createClauseDataLoder(options) {
|
|
134
|
+
return new dataloader_1.default(async (clauses) => {
|
|
135
|
+
if (!clauses.length) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
const ret = [];
|
|
139
|
+
for await (const clause of clauses) {
|
|
140
|
+
const data = await loadRowsForClauseLoader(options, clause);
|
|
141
|
+
ret.push(data);
|
|
142
|
+
}
|
|
143
|
+
return ret;
|
|
144
|
+
}, {
|
|
145
|
+
cacheMap: new clauseCacheMap(options),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function createClauseCountDataLoader(options) {
|
|
149
|
+
return new dataloader_1.default(async (clauses) => {
|
|
150
|
+
if (!clauses.length) {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const ret = [];
|
|
154
|
+
for await (const clause of clauses) {
|
|
155
|
+
const data = await loadCountForClauseLoader(options, clause);
|
|
156
|
+
ret.push(data);
|
|
157
|
+
}
|
|
158
|
+
return ret;
|
|
159
|
+
}, {
|
|
160
|
+
cacheMap: new clauseCacheMap(options, true),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
95
163
|
class ObjectLoader {
|
|
96
164
|
constructor(options, context, toPrime) {
|
|
97
165
|
this.options = options;
|
|
@@ -101,7 +169,8 @@ class ObjectLoader {
|
|
|
101
169
|
console.trace();
|
|
102
170
|
}
|
|
103
171
|
if (context) {
|
|
104
|
-
this.
|
|
172
|
+
this.idLoader = createDataLoader(options);
|
|
173
|
+
this.clauseLoader = createClauseDataLoder(options);
|
|
105
174
|
}
|
|
106
175
|
this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
|
|
107
176
|
}
|
|
@@ -123,11 +192,17 @@ class ObjectLoader {
|
|
|
123
192
|
this.primedLoaders = primedLoaders;
|
|
124
193
|
}
|
|
125
194
|
async load(key) {
|
|
195
|
+
if (typeof key === "string" || typeof key === "number") {
|
|
196
|
+
return this.loadID(key);
|
|
197
|
+
}
|
|
198
|
+
return this.loadClause(key);
|
|
199
|
+
}
|
|
200
|
+
async loadID(key) {
|
|
126
201
|
// simple case. we get parallelization etc
|
|
127
|
-
if (this.
|
|
202
|
+
if (this.idLoader) {
|
|
128
203
|
this.memoizedInitPrime();
|
|
129
204
|
// prime the result if we got primable loaders
|
|
130
|
-
const result = await this.
|
|
205
|
+
const result = await this.idLoader.load(key);
|
|
131
206
|
if (result && this.primedLoaders) {
|
|
132
207
|
for (const [key, loader] of this.primedLoaders) {
|
|
133
208
|
const value = result[key];
|
|
@@ -138,19 +213,7 @@ class ObjectLoader {
|
|
|
138
213
|
}
|
|
139
214
|
return result;
|
|
140
215
|
}
|
|
141
|
-
|
|
142
|
-
if (this.options.clause) {
|
|
143
|
-
let optionClause;
|
|
144
|
-
if (typeof this.options.clause === "function") {
|
|
145
|
-
optionClause = this.options.clause();
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
optionClause = this.options.clause;
|
|
149
|
-
}
|
|
150
|
-
if (optionClause) {
|
|
151
|
-
cls = clause.And(cls, optionClause);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
216
|
+
const cls = (0, clause_1.getCombinedClause)(this.options, clause.Eq(this.options.key, key));
|
|
154
217
|
const rowOptions = {
|
|
155
218
|
...this.options,
|
|
156
219
|
clause: cls,
|
|
@@ -158,22 +221,50 @@ class ObjectLoader {
|
|
|
158
221
|
};
|
|
159
222
|
return (0, ent_1.loadRow)(rowOptions);
|
|
160
223
|
}
|
|
224
|
+
async loadClause(key) {
|
|
225
|
+
if (this.clauseLoader) {
|
|
226
|
+
return this.clauseLoader.load(key);
|
|
227
|
+
}
|
|
228
|
+
return loadRowsForClauseLoader(this.options, key);
|
|
229
|
+
}
|
|
161
230
|
clearAll() {
|
|
162
|
-
this.
|
|
231
|
+
this.idLoader && this.idLoader.clearAll();
|
|
232
|
+
this.clauseLoader && this.clauseLoader.clearAll();
|
|
163
233
|
}
|
|
164
234
|
async loadMany(keys) {
|
|
165
|
-
if (
|
|
235
|
+
if (!keys.length) {
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
if (typeof keys[0] === "string" || typeof keys[0] === "number") {
|
|
239
|
+
return this.loadIDMany(keys);
|
|
240
|
+
}
|
|
241
|
+
return this.loadClauseMany(keys);
|
|
242
|
+
}
|
|
243
|
+
loadIDMany(keys) {
|
|
244
|
+
if (this.idLoader) {
|
|
166
245
|
// @ts-expect-error TODO?
|
|
167
|
-
return this.
|
|
246
|
+
return this.idLoader.loadMany(keys);
|
|
247
|
+
}
|
|
248
|
+
return loadRowsForIDLoader(this.options, keys, this.context);
|
|
249
|
+
}
|
|
250
|
+
async loadClauseMany(keys) {
|
|
251
|
+
if (this.clauseLoader) {
|
|
252
|
+
// @ts-expect-error TODO?
|
|
253
|
+
return this.clauseLoader.loadMany(keys);
|
|
254
|
+
}
|
|
255
|
+
const res = [];
|
|
256
|
+
for await (const key of keys) {
|
|
257
|
+
const rows = await loadRowsForClauseLoader(this.options, key);
|
|
258
|
+
res.push(rows);
|
|
168
259
|
}
|
|
169
|
-
return
|
|
260
|
+
return res;
|
|
170
261
|
}
|
|
171
262
|
prime(data) {
|
|
172
263
|
// we have this data from somewhere else, prime it in the c
|
|
173
|
-
if (this.
|
|
264
|
+
if (this.idLoader) {
|
|
174
265
|
const col = this.options.key;
|
|
175
266
|
const key = data[col];
|
|
176
|
-
this.
|
|
267
|
+
this.idLoader.prime(key, data);
|
|
177
268
|
}
|
|
178
269
|
}
|
|
179
270
|
// prime this loader and any other loaders it's aware of
|
|
@@ -190,6 +281,43 @@ class ObjectLoader {
|
|
|
190
281
|
}
|
|
191
282
|
}
|
|
192
283
|
exports.ObjectLoader = ObjectLoader;
|
|
284
|
+
class ObjectCountLoader {
|
|
285
|
+
constructor(options, context) {
|
|
286
|
+
this.options = options;
|
|
287
|
+
this.context = context;
|
|
288
|
+
if (context) {
|
|
289
|
+
this.loader = createClauseCountDataLoader(options);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
getOptions() {
|
|
293
|
+
return this.options;
|
|
294
|
+
}
|
|
295
|
+
async load(key) {
|
|
296
|
+
if (this.loader) {
|
|
297
|
+
return this.loader.load(key);
|
|
298
|
+
}
|
|
299
|
+
return loadCountForClauseLoader(this.options, key);
|
|
300
|
+
}
|
|
301
|
+
clearAll() {
|
|
302
|
+
this.loader && this.loader.clearAll();
|
|
303
|
+
}
|
|
304
|
+
async loadMany(keys) {
|
|
305
|
+
if (!keys.length) {
|
|
306
|
+
return [];
|
|
307
|
+
}
|
|
308
|
+
if (this.loader) {
|
|
309
|
+
// @ts-expect-error
|
|
310
|
+
return this.loader.loadMany(keys);
|
|
311
|
+
}
|
|
312
|
+
const res = [];
|
|
313
|
+
for await (const key of keys) {
|
|
314
|
+
const r = await loadCountForClauseLoader(this.options, key);
|
|
315
|
+
res.push(r);
|
|
316
|
+
}
|
|
317
|
+
return res;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
exports.ObjectCountLoader = ObjectCountLoader;
|
|
193
321
|
// NOTE: if not querying for all columns
|
|
194
322
|
// have to query for the id field as one of the fields
|
|
195
323
|
// because it's used to maintain sort order of the queried ids
|
|
@@ -213,6 +341,15 @@ class ObjectLoaderFactory {
|
|
|
213
341
|
return new ObjectLoader(this.options, context, this.toPrime);
|
|
214
342
|
}, context);
|
|
215
343
|
}
|
|
344
|
+
createTypedLoader(context) {
|
|
345
|
+
const loader = this.createLoader(context);
|
|
346
|
+
return loader;
|
|
347
|
+
}
|
|
348
|
+
createCountLoader(context) {
|
|
349
|
+
return (0, loader_1.getCustomLoader)(`${this.name}:count_loader`, () => {
|
|
350
|
+
return new ObjectCountLoader(this.options, context);
|
|
351
|
+
}, context);
|
|
352
|
+
}
|
|
216
353
|
// keep track of loaders to prime. needs to be done not in the constructor
|
|
217
354
|
// because there's usually self references here
|
|
218
355
|
addToPrime(factory) {
|
|
@@ -8,7 +8,7 @@ declare class QueryDirectLoader<K extends any> implements Loader<K, Data[]> {
|
|
|
8
8
|
context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
|
|
9
9
|
private memoizedInitPrime;
|
|
10
10
|
private primedLoaders;
|
|
11
|
-
constructor(options: QueryOptions, queryOptions?: Partial<Pick<import("../base").QueryableDataOptions, "
|
|
11
|
+
constructor(options: QueryOptions, queryOptions?: Partial<Pick<import("../base").QueryableDataOptions, "clause" | "limit" | "orderby">> | undefined, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined);
|
|
12
12
|
private initPrime;
|
|
13
13
|
load(id: K): Promise<Data[]>;
|
|
14
14
|
clearAll(): void;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.commonTests = void 0;
|
|
4
4
|
const ent_1 = require("../ent");
|
|
5
|
+
const global_schema_1 = require("../global_schema");
|
|
5
6
|
const viewer_1 = require("../viewer");
|
|
6
7
|
const index_1 = require("../../testutils/fake_data/index");
|
|
7
8
|
const test_helpers_1 = require("../../testutils/fake_data/test_helpers");
|
|
@@ -289,7 +290,7 @@ const commonTests = (opts) => {
|
|
|
289
290
|
return { verify, getCursor };
|
|
290
291
|
}
|
|
291
292
|
if (opts.globalSchema) {
|
|
292
|
-
(0,
|
|
293
|
+
(0, global_schema_1.setGlobalSchema)(test_edge_global_schema_1.testEdgeGlobalSchema);
|
|
293
294
|
}
|
|
294
295
|
let tdb;
|
|
295
296
|
if (opts.sqlite) {
|
package/graphql/graphql.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export interface gqlObjectOptions {
|
|
|
40
40
|
type gqlMutationOptions = Omit<gqlFieldOptions, "nullable" | "type"> & {
|
|
41
41
|
type?: gqlFieldOptionsBase["type"];
|
|
42
42
|
};
|
|
43
|
-
type gqlQueryOptions =
|
|
43
|
+
type gqlQueryOptions = gqlFieldOptions;
|
|
44
44
|
export declare enum CustomFieldType {
|
|
45
45
|
Accessor = "ACCESSOR",
|
|
46
46
|
Field = "FIELD",
|
package/graphql/graphql.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./core/base";
|
|
2
|
-
export { loadEnt, loadCustomData, loadCustomEnts, loadCustomCount, loadEntX, loadEnts, CustomQuery, loadDerivedEnt, loadDerivedEntX, loadEntViaKey, loadEntXViaKey, performRawQuery, loadRowX, loadRow, loadRows, DataOperation, EditNodeOptions, EditNodeOperation, RawQueryOperation, EdgeOperation, DeleteNodeOperation, AssocEdge, AssocEdgeInputOptions, AssocEdgeInput, AssocEdgeData, loadEdgeData, loadEdgeDatas, loadEdges, loadUniqueEdge, loadUniqueNode, loadRawEdgeCountX, loadEdgeForID2, loadNodesByEdge, getEdgeTypeInGroup,
|
|
2
|
+
export { loadEnt, loadCustomData, loadCustomEnts, loadCustomCount, loadEntX, loadEnts, CustomQuery, loadDerivedEnt, loadDerivedEntX, loadEntViaKey, loadEntXViaKey, performRawQuery, loadRowX, loadRow, loadRows, DataOperation, EditNodeOptions, EditNodeOperation, RawQueryOperation, EdgeOperation, DeleteNodeOperation, AssocEdge, AssocEdgeInputOptions, AssocEdgeInput, AssocEdgeData, loadEdgeData, loadEdgeDatas, loadEdges, loadUniqueEdge, loadUniqueNode, loadRawEdgeCountX, loadEdgeForID2, loadNodesByEdge, getEdgeTypeInGroup, } from "./core/ent";
|
|
3
|
+
export { setGlobalSchema } from "./core/global_schema";
|
|
3
4
|
import DB from "./core/db";
|
|
4
5
|
export * from "./core/loaders";
|
|
5
6
|
export { DB };
|
package/index.js
CHANGED
|
@@ -63,7 +63,8 @@ Object.defineProperty(exports, "loadRawEdgeCountX", { enumerable: true, get: fun
|
|
|
63
63
|
Object.defineProperty(exports, "loadEdgeForID2", { enumerable: true, get: function () { return ent_1.loadEdgeForID2; } });
|
|
64
64
|
Object.defineProperty(exports, "loadNodesByEdge", { enumerable: true, get: function () { return ent_1.loadNodesByEdge; } });
|
|
65
65
|
Object.defineProperty(exports, "getEdgeTypeInGroup", { enumerable: true, get: function () { return ent_1.getEdgeTypeInGroup; } });
|
|
66
|
-
|
|
66
|
+
var global_schema_1 = require("./core/global_schema");
|
|
67
|
+
Object.defineProperty(exports, "setGlobalSchema", { enumerable: true, get: function () { return global_schema_1.setGlobalSchema; } });
|
|
67
68
|
const db_1 = __importDefault(require("./core/db"));
|
|
68
69
|
exports.DB = db_1.default;
|
|
69
70
|
__exportStar(require("./core/loaders"), exports);
|
package/package.json
CHANGED
package/parse_schema/parse.d.ts
CHANGED
package/parse_schema/parse.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseSchema = void 0;
|
|
4
4
|
const cosmiconfig_1 = require("cosmiconfig");
|
|
5
5
|
const const_1 = require("../core/const");
|
|
6
|
+
const global_schema_1 = require("../core/global_schema");
|
|
6
7
|
async function processFields(src, patternName) {
|
|
7
8
|
const ret = [];
|
|
8
9
|
let m = {};
|
|
@@ -21,7 +22,7 @@ async function processFields(src, patternName) {
|
|
|
21
22
|
for (const name in m) {
|
|
22
23
|
const field = m[name];
|
|
23
24
|
//@ts-ignore type and other changed fields with different type in ProcessedField vs Field
|
|
24
|
-
let f = {
|
|
25
|
+
let f = { ...field, name };
|
|
25
26
|
f.hasDefaultValueOnCreate = field.defaultValueOnCreate != undefined;
|
|
26
27
|
f.hasDefaultValueOnEdit = field.defaultValueOnEdit != undefined;
|
|
27
28
|
f.hasFieldPrivacy = field.privacyPolicy !== undefined;
|
|
@@ -236,6 +237,9 @@ async function parseSchema(potentialSchemas, globalSchema) {
|
|
|
236
237
|
let parsedGlobalSchema;
|
|
237
238
|
if (globalSchema) {
|
|
238
239
|
parsedGlobalSchema = await parseGlobalSchema(globalSchema);
|
|
240
|
+
// set this so that we can use it, if we're trying to process server default or anything
|
|
241
|
+
// that ends up parsing,validating and formatting fields
|
|
242
|
+
(0, global_schema_1.setGlobalSchema)(globalSchema);
|
|
239
243
|
}
|
|
240
244
|
for (const key in potentialSchemas) {
|
|
241
245
|
const value = potentialSchemas[key];
|
|
@@ -354,9 +358,10 @@ async function parseGlobalSchema(s) {
|
|
|
354
358
|
const ret = {
|
|
355
359
|
globalEdges: [],
|
|
356
360
|
extraEdgeFields: [],
|
|
357
|
-
|
|
361
|
+
init: !!s.extraEdgeFields ||
|
|
358
362
|
s.transformEdgeRead !== undefined ||
|
|
359
|
-
s.transformEdgeWrite !== undefined
|
|
363
|
+
s.transformEdgeWrite !== undefined ||
|
|
364
|
+
s.fields !== undefined,
|
|
360
365
|
};
|
|
361
366
|
if (s.extraEdgeFields) {
|
|
362
367
|
ret.extraEdgeFields = await processFields(s.extraEdgeFields);
|
|
@@ -364,5 +369,8 @@ async function parseGlobalSchema(s) {
|
|
|
364
369
|
if (s.edges) {
|
|
365
370
|
ret.globalEdges = processEdges(s.edges);
|
|
366
371
|
}
|
|
372
|
+
if (s.fields) {
|
|
373
|
+
ret.globalFields = await processFields(s.fields);
|
|
374
|
+
}
|
|
367
375
|
return ret;
|
|
368
376
|
}
|
package/schema/field.d.ts
CHANGED
|
@@ -149,6 +149,7 @@ export interface EnumOptions extends FieldOptions {
|
|
|
149
149
|
graphQLType?: string;
|
|
150
150
|
createEnumType?: boolean;
|
|
151
151
|
disableUnknownType?: boolean;
|
|
152
|
+
globalType?: string;
|
|
152
153
|
}
|
|
153
154
|
/**
|
|
154
155
|
* @deprecated Use StringEnumField
|
|
@@ -158,7 +159,7 @@ export declare class EnumField extends BaseField implements Field {
|
|
|
158
159
|
private values?;
|
|
159
160
|
private map?;
|
|
160
161
|
constructor(options: StringEnumOptions);
|
|
161
|
-
valid(val: any): boolean
|
|
162
|
+
valid(val: any): Promise<boolean>;
|
|
162
163
|
format(val: any): any;
|
|
163
164
|
}
|
|
164
165
|
export declare class StringEnumField extends EnumField {
|
|
@@ -173,17 +174,18 @@ declare type IntEnumMap = {
|
|
|
173
174
|
[key: string]: number;
|
|
174
175
|
};
|
|
175
176
|
export interface IntegerEnumOptions extends FieldOptions {
|
|
176
|
-
map
|
|
177
|
+
map?: IntEnumMap;
|
|
177
178
|
deprecated?: IntEnumMap;
|
|
178
179
|
tsType?: string;
|
|
179
180
|
graphQLType?: string;
|
|
180
181
|
disableUnknownType?: boolean;
|
|
182
|
+
globalType?: string;
|
|
181
183
|
}
|
|
182
184
|
export declare class IntegerEnumField extends BaseField implements Field {
|
|
183
185
|
type: Type;
|
|
184
186
|
private map;
|
|
185
187
|
constructor(options: IntegerEnumOptions);
|
|
186
|
-
valid(val: any): boolean
|
|
188
|
+
valid(val: any): Promise<boolean>;
|
|
187
189
|
format(val: any): any;
|
|
188
190
|
}
|
|
189
191
|
export declare function IntegerEnumType(options: IntegerEnumOptions): IntegerEnumField;
|
package/schema/field.js
CHANGED
|
@@ -31,6 +31,8 @@ const uuid_1 = require("uuid");
|
|
|
31
31
|
const base_1 = require("../core/base");
|
|
32
32
|
const db_1 = __importStar(require("../core/db"));
|
|
33
33
|
const schema_1 = require("./schema");
|
|
34
|
+
const global_schema_1 = require("../core/global_schema");
|
|
35
|
+
const logger_1 = require("../core/logger");
|
|
34
36
|
class BaseField {
|
|
35
37
|
logValue(val) {
|
|
36
38
|
if (this.sensitive) {
|
|
@@ -525,10 +527,11 @@ class EnumField extends BaseField {
|
|
|
525
527
|
type: options.tsType,
|
|
526
528
|
graphQLType: options.graphQLType,
|
|
527
529
|
disableUnknownType: options.disableUnknownType,
|
|
530
|
+
globalType: options.globalType,
|
|
528
531
|
};
|
|
529
532
|
if (!options.foreignKey) {
|
|
530
|
-
if (!options.values && !options.map) {
|
|
531
|
-
throw new Error("values or
|
|
533
|
+
if (!options.values && !options.map && !options.globalType) {
|
|
534
|
+
throw new Error("values, map or globalType required if not look up table enum. Look-up table enum indicated by foreignKey field");
|
|
532
535
|
}
|
|
533
536
|
if (options.values) {
|
|
534
537
|
if (!options.values.length) {
|
|
@@ -547,8 +550,8 @@ class EnumField extends BaseField {
|
|
|
547
550
|
}
|
|
548
551
|
}
|
|
549
552
|
else {
|
|
550
|
-
if (options.values || options.map) {
|
|
551
|
-
throw new Error("cannot specify values or
|
|
553
|
+
if (options.values || options.map || options.globalType) {
|
|
554
|
+
throw new Error("cannot specify values, map or globalType and foreign key for lookup table enum type");
|
|
552
555
|
}
|
|
553
556
|
if (options.createEnumType) {
|
|
554
557
|
throw new Error("cannot specify createEnumType without specifying values");
|
|
@@ -563,7 +566,20 @@ class EnumField extends BaseField {
|
|
|
563
566
|
this.values = options.values;
|
|
564
567
|
this.map = options.map;
|
|
565
568
|
}
|
|
566
|
-
valid(val) {
|
|
569
|
+
async valid(val) {
|
|
570
|
+
if (this.type.globalType) {
|
|
571
|
+
const f = (0, global_schema_1.__getGlobalSchemaField)(this.type.globalType);
|
|
572
|
+
if (f) {
|
|
573
|
+
if (f.valid) {
|
|
574
|
+
return f.valid(val);
|
|
575
|
+
}
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
(0, logger_1.log)("error", `globalType ${this.type.globalType} not found in global schema`);
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
567
583
|
// lookup table enum and indicated via presence of foreignKey
|
|
568
584
|
if (!this.values && !this.map) {
|
|
569
585
|
return true;
|
|
@@ -581,6 +597,13 @@ class EnumField extends BaseField {
|
|
|
581
597
|
return false;
|
|
582
598
|
}
|
|
583
599
|
format(val) {
|
|
600
|
+
if (this.type.globalType) {
|
|
601
|
+
const f = (0, global_schema_1.__getGlobalSchemaField)(this.type.globalType);
|
|
602
|
+
if (f && f.format) {
|
|
603
|
+
return f.format(val);
|
|
604
|
+
}
|
|
605
|
+
return val;
|
|
606
|
+
}
|
|
584
607
|
return val;
|
|
585
608
|
}
|
|
586
609
|
}
|
|
@@ -603,21 +626,46 @@ class IntegerEnumField extends BaseField {
|
|
|
603
626
|
graphQLType: options.graphQLType,
|
|
604
627
|
deprecatedIntEnumMap: options.deprecated,
|
|
605
628
|
disableUnknownType: options.disableUnknownType,
|
|
629
|
+
globalType: options.globalType,
|
|
606
630
|
};
|
|
607
|
-
let count = 0;
|
|
608
|
-
for (const _ in options.map) {
|
|
609
|
-
count++;
|
|
610
|
-
break;
|
|
611
|
-
}
|
|
612
|
-
if (!count) {
|
|
613
|
-
throw new Error("need at least one entry in enum map");
|
|
614
|
-
}
|
|
615
631
|
if (options.foreignKey) {
|
|
616
632
|
throw new Error(`foreignKey on intEnum not supported`);
|
|
617
633
|
}
|
|
618
|
-
|
|
634
|
+
if (options.globalType) {
|
|
635
|
+
if (options.map) {
|
|
636
|
+
throw new Error(`cannot specify map and globalType`);
|
|
637
|
+
}
|
|
638
|
+
this.map = {};
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
let count = 0;
|
|
642
|
+
for (const _ in options.map) {
|
|
643
|
+
count++;
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
if (!count) {
|
|
647
|
+
throw new Error("need at least one entry in enum map");
|
|
648
|
+
}
|
|
649
|
+
if (!options.map) {
|
|
650
|
+
throw new Error("map required if not globalType");
|
|
651
|
+
}
|
|
652
|
+
this.map = options.map;
|
|
653
|
+
}
|
|
619
654
|
}
|
|
620
|
-
valid(val) {
|
|
655
|
+
async valid(val) {
|
|
656
|
+
if (this.type?.globalType) {
|
|
657
|
+
const f = (0, global_schema_1.__getGlobalSchemaField)(this.type.globalType);
|
|
658
|
+
if (f) {
|
|
659
|
+
if (f.valid) {
|
|
660
|
+
return f.valid(val);
|
|
661
|
+
}
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
(0, logger_1.log)("error", `globalType ${this.type.globalType} not found in global schema`);
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
621
669
|
// lookup table enum and indicated via presence of foreignKey
|
|
622
670
|
for (const k in this.map) {
|
|
623
671
|
const v = this.map[k];
|
|
@@ -628,6 +676,12 @@ class IntegerEnumField extends BaseField {
|
|
|
628
676
|
return false;
|
|
629
677
|
}
|
|
630
678
|
format(val) {
|
|
679
|
+
if (this.type.globalType) {
|
|
680
|
+
const f = (0, global_schema_1.__getGlobalSchemaField)(this.type.globalType);
|
|
681
|
+
if (f && f.format) {
|
|
682
|
+
return f.format(val);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
631
685
|
return parseInt(val);
|
|
632
686
|
}
|
|
633
687
|
}
|
package/schema/schema.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface GlobalSchema {
|
|
|
17
17
|
extraEdgeFields?: FieldMap;
|
|
18
18
|
transformEdgeRead?: () => Clause;
|
|
19
19
|
transformEdgeWrite?: (stmt: EdgeUpdateOperation) => TransformedEdgeUpdateOperation | null;
|
|
20
|
+
fields?: FieldMap;
|
|
20
21
|
}
|
|
21
22
|
type FieldOverride = Pick<FieldOptions, "nullable" | "storageKey" | "serverDefault" | "unique" | "hideFromGraphQL" | "graphqlName" | "index">;
|
|
22
23
|
export type FieldOverrideMap = {
|
|
@@ -171,6 +172,7 @@ export interface Type {
|
|
|
171
172
|
intEnumMap?: IntEnumMap;
|
|
172
173
|
deprecatedIntEnumMap?: IntEnumMap;
|
|
173
174
|
disableUnknownType?: boolean;
|
|
175
|
+
globalType?: string;
|
|
174
176
|
importType?: DeprecatedImportType;
|
|
175
177
|
subFields?: FieldMap;
|
|
176
178
|
unionFields?: FieldMap;
|
package/schema/struct_field.d.ts
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { BaseField, ListField } from "./field";
|
|
2
2
|
import { FieldOptions, Field, Type, FieldMap } from "./schema";
|
|
3
|
-
|
|
3
|
+
interface structFieldOptions extends FieldOptions {
|
|
4
4
|
tsType: string;
|
|
5
5
|
fields: FieldMap;
|
|
6
6
|
graphQLType?: string;
|
|
7
7
|
jsonNotJSONB?: boolean;
|
|
8
8
|
}
|
|
9
|
-
interface
|
|
10
|
-
|
|
9
|
+
interface GlobalStructOptions extends FieldOptions {
|
|
10
|
+
globalType: string;
|
|
11
11
|
}
|
|
12
|
+
export type StructOptions = structFieldOptions | GlobalStructOptions;
|
|
12
13
|
export declare class StructField extends BaseField implements Field {
|
|
13
14
|
private options;
|
|
15
|
+
private jsonAsList?;
|
|
14
16
|
type: Type;
|
|
15
|
-
constructor(options:
|
|
17
|
+
constructor(options: StructOptions, jsonAsList?: boolean | undefined);
|
|
16
18
|
formatImpl(obj: any, nested?: boolean): string | Object;
|
|
17
|
-
format(obj: any, nested?: boolean):
|
|
19
|
+
format(obj: any, nested?: boolean): any;
|
|
18
20
|
private validImpl;
|
|
19
21
|
valid(obj: any): Promise<boolean>;
|
|
20
22
|
}
|
|
@@ -23,5 +25,5 @@ export declare function StructType(options: StructOptions): StructField & Struct
|
|
|
23
25
|
* @deprecated use StructTypeAsList
|
|
24
26
|
*/
|
|
25
27
|
export declare function StructListType(options: StructOptions): ListField;
|
|
26
|
-
export declare function StructTypeAsList(options:
|
|
28
|
+
export declare function StructTypeAsList(options: StructOptions): StructField & StructOptions;
|
|
27
29
|
export {};
|
package/schema/struct_field.js
CHANGED
|
@@ -4,20 +4,24 @@ exports.StructTypeAsList = exports.StructListType = exports.StructType = exports
|
|
|
4
4
|
const camel_case_1 = require("camel-case");
|
|
5
5
|
const field_1 = require("./field");
|
|
6
6
|
const schema_1 = require("./schema");
|
|
7
|
+
const global_schema_1 = require("../core/global_schema");
|
|
8
|
+
const logger_1 = require("../core/logger");
|
|
7
9
|
class StructField extends field_1.BaseField {
|
|
8
|
-
constructor(options) {
|
|
10
|
+
constructor(options, jsonAsList) {
|
|
9
11
|
super();
|
|
10
12
|
this.options = options;
|
|
13
|
+
this.jsonAsList = jsonAsList;
|
|
11
14
|
this.type = {
|
|
12
15
|
dbType: schema_1.DBType.JSONB,
|
|
13
16
|
};
|
|
14
17
|
this.type.subFields = options.fields;
|
|
15
18
|
this.type.type = options.tsType;
|
|
16
19
|
this.type.graphQLType = options.graphQLType || options.tsType;
|
|
20
|
+
this.type.globalType = this.options.globalType;
|
|
17
21
|
if (options.jsonNotJSONB) {
|
|
18
22
|
this.type.dbType = schema_1.DBType.JSON;
|
|
19
23
|
}
|
|
20
|
-
if (
|
|
24
|
+
if (jsonAsList) {
|
|
21
25
|
this.type.listElemType = {
|
|
22
26
|
dbType: schema_1.DBType.JSONB,
|
|
23
27
|
};
|
|
@@ -57,7 +61,37 @@ class StructField extends field_1.BaseField {
|
|
|
57
61
|
return JSON.stringify(ret);
|
|
58
62
|
}
|
|
59
63
|
format(obj, nested) {
|
|
60
|
-
if (
|
|
64
|
+
if (this.type.globalType) {
|
|
65
|
+
const f = (0, global_schema_1.__getGlobalSchemaField)(this.type.globalType);
|
|
66
|
+
if (f && f.format) {
|
|
67
|
+
if (JSON.stringify(this.type.listElemType) !==
|
|
68
|
+
JSON.stringify(f?.type.listElemType)) {
|
|
69
|
+
if (this.jsonAsList) {
|
|
70
|
+
// handle as nested
|
|
71
|
+
// @ts-ignore
|
|
72
|
+
const formatted = obj.map((v) => f.format(v, true));
|
|
73
|
+
if (nested) {
|
|
74
|
+
return formatted;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return JSON.stringify(formatted);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const formatted = f.format([obj], true);
|
|
82
|
+
if (nested) {
|
|
83
|
+
return formatted[0];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
return JSON.stringify(formatted[0]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// TODO handle format code
|
|
91
|
+
return f.format(obj);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (Array.isArray(obj) && this.jsonAsList) {
|
|
61
95
|
const ret = obj.map((v) => this.formatImpl(v, true));
|
|
62
96
|
if (nested) {
|
|
63
97
|
return ret;
|
|
@@ -102,7 +136,35 @@ class StructField extends field_1.BaseField {
|
|
|
102
136
|
return ret.every((v) => v);
|
|
103
137
|
}
|
|
104
138
|
async valid(obj) {
|
|
105
|
-
if (this.
|
|
139
|
+
if (this.type.globalType) {
|
|
140
|
+
const f = (0, global_schema_1.__getGlobalSchemaField)(this.type.globalType);
|
|
141
|
+
// list and global type is not valid.
|
|
142
|
+
if (f) {
|
|
143
|
+
if (f.valid) {
|
|
144
|
+
if (JSON.stringify(this.type.listElemType) !==
|
|
145
|
+
JSON.stringify(f?.type.listElemType)) {
|
|
146
|
+
if (this.jsonAsList) {
|
|
147
|
+
if (!Array.isArray(obj)) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
// @ts-ignore
|
|
151
|
+
const valid = await Promise.all(obj.map((v) => f.valid(v)));
|
|
152
|
+
return valid.every((b) => b);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
return f.valid([obj]);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return f.valid(obj);
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
(0, logger_1.log)("error", `globalType ${this.type.globalType} not found in global schema`);
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (this.jsonAsList) {
|
|
106
168
|
if (!Array.isArray(obj)) {
|
|
107
169
|
return false;
|
|
108
170
|
}
|
|
@@ -129,10 +191,7 @@ function StructListType(options) {
|
|
|
129
191
|
}
|
|
130
192
|
exports.StructListType = StructListType;
|
|
131
193
|
function StructTypeAsList(options) {
|
|
132
|
-
let result = new StructField(
|
|
133
|
-
...options,
|
|
134
|
-
jsonAsList: true,
|
|
135
|
-
});
|
|
194
|
+
let result = new StructField(options, true);
|
|
136
195
|
return Object.assign(result, options);
|
|
137
196
|
}
|
|
138
197
|
exports.StructTypeAsList = StructTypeAsList;
|
package/schema/union_field.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare class UnionField extends BaseField implements FieldOptions {
|
|
|
15
15
|
type: Type;
|
|
16
16
|
m: Map<Object, string>;
|
|
17
17
|
constructor(options: UnionOptions);
|
|
18
|
-
format(obj: any):
|
|
18
|
+
format(obj: any): any;
|
|
19
19
|
private validField;
|
|
20
20
|
valid(obj: any): Promise<boolean>;
|
|
21
21
|
}
|