@snowtop/ent 0.0.11 → 0.0.12
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/config.d.ts +3 -0
- package/core/query/assoc_query.d.ts +3 -1
- package/core/query/assoc_query.js +33 -1
- package/core/query/shared_assoc_test.js +140 -0
- package/package.json +4 -1
- package/parse_schema/parse.d.ts +41 -0
- package/parse_schema/parse.js +139 -0
- package/schema/base_schema.d.ts +2 -0
- package/schema/base_schema.js +10 -0
- package/schema/schema.d.ts +4 -0
- package/scripts/read_schema.js +3 -105
- package/testutils/db/test_db.js +0 -2
- package/testutils/fake_data/const.d.ts +5 -1
- package/testutils/fake_data/const.js +19 -1
- package/testutils/fake_data/fake_user.js +2 -0
- package/testutils/fake_data/user_query.d.ts +5 -1
- package/testutils/fake_data/user_query.js +11 -1
package/core/config.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ interface CodegenConfig {
|
|
|
12
12
|
defaultEntPolicy?: PrivacyConfig;
|
|
13
13
|
defaultActionPolicy?: PrivacyConfig;
|
|
14
14
|
prettier?: PrettierConfig;
|
|
15
|
+
relativeImports?: boolean;
|
|
16
|
+
disableGraphQLRoot?: boolean;
|
|
17
|
+
generatedHeader?: string;
|
|
15
18
|
}
|
|
16
19
|
interface PrettierConfig {
|
|
17
20
|
custom?: boolean;
|
|
@@ -4,6 +4,7 @@ import { AssocEdgeCountLoaderFactory } from "../loaders/assoc_count_loader";
|
|
|
4
4
|
import { AssocEdgeLoaderFactory } from "../loaders/assoc_edge_loader";
|
|
5
5
|
import { EdgeQuery, BaseEdgeQuery } from "./query";
|
|
6
6
|
export declare type EdgeQuerySource<T extends Ent> = T | T[] | ID | ID[] | EdgeQuery<T, AssocEdge>;
|
|
7
|
+
declare type loaderOptionsFunc = (type: string) => LoadEntOptions<Ent>;
|
|
7
8
|
export declare class AssocEdgeQueryBase<TSource extends Ent, TDest extends Ent, TEdge extends AssocEdge> extends BaseEdgeQuery<TDest, TEdge> {
|
|
8
9
|
viewer: Viewer;
|
|
9
10
|
src: EdgeQuerySource<TSource>;
|
|
@@ -12,7 +13,7 @@ export declare class AssocEdgeQueryBase<TSource extends Ent, TDest extends Ent,
|
|
|
12
13
|
private options;
|
|
13
14
|
private idsResolved;
|
|
14
15
|
private resolvedIDs;
|
|
15
|
-
constructor(viewer: Viewer, src: EdgeQuerySource<TSource>, countLoaderFactory: AssocEdgeCountLoaderFactory, dataLoaderFactory: AssocEdgeLoaderFactory<TEdge>, options: LoadEntOptions<TDest>);
|
|
16
|
+
constructor(viewer: Viewer, src: EdgeQuerySource<TSource>, countLoaderFactory: AssocEdgeCountLoaderFactory, dataLoaderFactory: AssocEdgeLoaderFactory<TEdge>, options: LoadEntOptions<TDest> | loaderOptionsFunc);
|
|
16
17
|
private resolveIDs;
|
|
17
18
|
private isEdgeQuery;
|
|
18
19
|
private addID;
|
|
@@ -28,3 +29,4 @@ export declare class AssocEdgeQueryBase<TSource extends Ent, TDest extends Ent,
|
|
|
28
29
|
export interface EdgeQueryCtr<T extends Ent, TEdge extends AssocEdge> {
|
|
29
30
|
new (viewer: Viewer, src: EdgeQuerySource<T>): EdgeQuery<T, TEdge>;
|
|
30
31
|
}
|
|
32
|
+
export {};
|
|
@@ -4,7 +4,10 @@ exports.AssocEdgeQueryBase = void 0;
|
|
|
4
4
|
const ent_1 = require("../ent");
|
|
5
5
|
const query_1 = require("./query");
|
|
6
6
|
class AssocEdgeQueryBase extends query_1.BaseEdgeQuery {
|
|
7
|
-
constructor(viewer, src, countLoaderFactory, dataLoaderFactory,
|
|
7
|
+
constructor(viewer, src, countLoaderFactory, dataLoaderFactory,
|
|
8
|
+
// if function, it's a polymorphic edge and need to provide
|
|
9
|
+
// a function that goes from edgeType to LoadEntOptions
|
|
10
|
+
options) {
|
|
8
11
|
super(viewer, "time");
|
|
9
12
|
this.viewer = viewer;
|
|
10
13
|
this.src = src;
|
|
@@ -70,6 +73,35 @@ class AssocEdgeQueryBase extends query_1.BaseEdgeQuery {
|
|
|
70
73
|
return results;
|
|
71
74
|
}
|
|
72
75
|
async loadEntsFromEdges(id, edges) {
|
|
76
|
+
if (typeof this.options === "function") {
|
|
77
|
+
const m = new Map();
|
|
78
|
+
for (const edge of edges) {
|
|
79
|
+
const nodeType = edge.id2Type;
|
|
80
|
+
let data = m.get(nodeType);
|
|
81
|
+
if (data === undefined) {
|
|
82
|
+
const opts = this.options(nodeType);
|
|
83
|
+
if (opts === undefined) {
|
|
84
|
+
throw new Error(`getLoaderOptions returned undefined for type ${nodeType}`);
|
|
85
|
+
}
|
|
86
|
+
data = {
|
|
87
|
+
ids: [],
|
|
88
|
+
options: opts,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
data.ids.push(edge.id2);
|
|
92
|
+
m.set(nodeType, data);
|
|
93
|
+
}
|
|
94
|
+
let promises = [];
|
|
95
|
+
for (const [_, value] of m) {
|
|
96
|
+
promises.push((0, ent_1.loadEnts)(this.viewer, value.options, ...value.ids));
|
|
97
|
+
}
|
|
98
|
+
const entss = await Promise.all(promises);
|
|
99
|
+
const r = [];
|
|
100
|
+
for (const ents of entss) {
|
|
101
|
+
r.push(...ents);
|
|
102
|
+
}
|
|
103
|
+
return r;
|
|
104
|
+
}
|
|
73
105
|
const ids = edges.map((edge) => edge.id2);
|
|
74
106
|
return await (0, ent_1.loadEnts)(this.viewer, this.options, ...ids);
|
|
75
107
|
}
|
|
@@ -425,5 +425,145 @@ function assocTests() {
|
|
|
425
425
|
await filter.testEnts();
|
|
426
426
|
});
|
|
427
427
|
});
|
|
428
|
+
class PolymorphicID2sTestQueryFilter {
|
|
429
|
+
constructor(filter, ents, limit) {
|
|
430
|
+
this.filter = filter;
|
|
431
|
+
this.ents = ents;
|
|
432
|
+
this.limit = limit;
|
|
433
|
+
this.users = [];
|
|
434
|
+
this.events = [];
|
|
435
|
+
}
|
|
436
|
+
async beforeEach() {
|
|
437
|
+
this.users = [];
|
|
438
|
+
this.events = [];
|
|
439
|
+
this.user = await (0, test_helpers_1.createTestUser)();
|
|
440
|
+
for (let i = 0; i < 5; i++) {
|
|
441
|
+
(0, jest_date_mock_1.advanceBy)(100);
|
|
442
|
+
const builder = (0, index_1.getUserBuilder)(this.user.viewer, (0, test_helpers_1.getUserInput)());
|
|
443
|
+
builder.orchestrator.addOutboundEdge(this.user.id, index_1.EdgeType.ObjectToFollowedUsers, index_1.NodeType.FakeUser);
|
|
444
|
+
await builder.saveX();
|
|
445
|
+
const user2 = await builder.editedEntX();
|
|
446
|
+
this.users.push(user2);
|
|
447
|
+
}
|
|
448
|
+
for (let i = 0; i < 5; i++) {
|
|
449
|
+
(0, jest_date_mock_1.advanceBy)(100);
|
|
450
|
+
const builder = (0, index_1.getEventBuilder)(this.user.viewer, (0, test_helpers_1.getEventInput)(this.user));
|
|
451
|
+
builder.orchestrator.addOutboundEdge(this.user.id, index_1.EdgeType.ObjectToFollowedUsers, index_1.NodeType.FakeUser);
|
|
452
|
+
await builder.saveX();
|
|
453
|
+
const event = await builder.editedEntX();
|
|
454
|
+
this.events.push(event);
|
|
455
|
+
}
|
|
456
|
+
//order is users, then events
|
|
457
|
+
this.expCount = this.ents([...this.users, ...this.events]).length;
|
|
458
|
+
db_mock_1.QueryRecorder.clearQueries();
|
|
459
|
+
}
|
|
460
|
+
getQuery(viewer) {
|
|
461
|
+
return this.filter(index_1.UserToFollowingQuery.query(viewer || new viewer_1.IDViewer(this.user.id), this.user));
|
|
462
|
+
}
|
|
463
|
+
async testIDs() {
|
|
464
|
+
const ids = await this.getQuery().queryIDs();
|
|
465
|
+
expect(ids.length).toBe(this.expCount);
|
|
466
|
+
const expIDs = this.users
|
|
467
|
+
.map((user) => user.id)
|
|
468
|
+
.concat(this.events.map((event) => event.id))
|
|
469
|
+
.reverse();
|
|
470
|
+
expect(expIDs).toEqual(ids);
|
|
471
|
+
verifyQuery({
|
|
472
|
+
length: 1,
|
|
473
|
+
numQueries: 1,
|
|
474
|
+
limit: this.limit || ent_1.DefaultLimit,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
// rawCount isn't affected by filters...
|
|
478
|
+
async testRawCount() {
|
|
479
|
+
const count = await this.getQuery().queryRawCount();
|
|
480
|
+
expect(count).toBe(this.expCount);
|
|
481
|
+
verifyCountQuery({ numQueries: 1, length: 1 });
|
|
482
|
+
}
|
|
483
|
+
async testCount() {
|
|
484
|
+
const count = await this.getQuery().queryCount();
|
|
485
|
+
expect(count).toBe(this.expCount);
|
|
486
|
+
verifyQuery({
|
|
487
|
+
length: 1,
|
|
488
|
+
numQueries: 1,
|
|
489
|
+
limit: this.limit || ent_1.DefaultLimit,
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
async testEdges() {
|
|
493
|
+
const edges = await this.getQuery().queryEdges();
|
|
494
|
+
expect(edges.length).toBe(this.expCount);
|
|
495
|
+
let userCount = 0;
|
|
496
|
+
let eventCount = 0;
|
|
497
|
+
edges.forEach((edge) => {
|
|
498
|
+
if (edge.id2Type === index_1.NodeType.FakeEvent) {
|
|
499
|
+
eventCount++;
|
|
500
|
+
}
|
|
501
|
+
if (edge.id2Type === index_1.NodeType.FakeUser) {
|
|
502
|
+
userCount++;
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
expect(userCount).toBe(this.expCount / 2);
|
|
506
|
+
expect(eventCount).toBe(this.expCount / 2);
|
|
507
|
+
verifyQuery({
|
|
508
|
+
length: 1,
|
|
509
|
+
numQueries: 1,
|
|
510
|
+
limit: this.limit || ent_1.DefaultLimit,
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
async testEnts() {
|
|
514
|
+
// privacy...
|
|
515
|
+
const ents = await this.getQuery().queryEnts();
|
|
516
|
+
expect(ents.length).toBe(this.expCount);
|
|
517
|
+
let userCount = 0;
|
|
518
|
+
let eventCount = 0;
|
|
519
|
+
ents.forEach((ent) => {
|
|
520
|
+
if (ent instanceof index_1.FakeEvent) {
|
|
521
|
+
eventCount++;
|
|
522
|
+
}
|
|
523
|
+
if (ent instanceof index_1.FakeUser) {
|
|
524
|
+
userCount++;
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
expect(userCount).toBe(this.expCount / 2);
|
|
528
|
+
expect(eventCount).toBe(this.expCount / 2);
|
|
529
|
+
// when doing privacy checks, hard to say what will be fetched
|
|
530
|
+
// verifyQuery({
|
|
531
|
+
// // 1 for edges, 1 for users, 1 for events
|
|
532
|
+
// length: 3,
|
|
533
|
+
// numQueries: 3,
|
|
534
|
+
// limit: this.limit || DefaultLimit,
|
|
535
|
+
// });
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
describe("polymorphic id2s", () => {
|
|
539
|
+
const filter = new PolymorphicID2sTestQueryFilter((q) => {
|
|
540
|
+
// no filters
|
|
541
|
+
return q;
|
|
542
|
+
}, (ents) => {
|
|
543
|
+
// nothing to do here
|
|
544
|
+
// reverse because edges are most recent first
|
|
545
|
+
return ents.reverse();
|
|
546
|
+
});
|
|
547
|
+
// TODO not working when it's a beforeAll
|
|
548
|
+
// working with beforeEach but we should only need to create this data once
|
|
549
|
+
beforeEach(async () => {
|
|
550
|
+
await filter.beforeEach();
|
|
551
|
+
});
|
|
552
|
+
test("ids", async () => {
|
|
553
|
+
await filter.testIDs();
|
|
554
|
+
});
|
|
555
|
+
test("rawCount", async () => {
|
|
556
|
+
await filter.testRawCount();
|
|
557
|
+
});
|
|
558
|
+
test("count", async () => {
|
|
559
|
+
await filter.testCount();
|
|
560
|
+
});
|
|
561
|
+
test("edges", async () => {
|
|
562
|
+
await filter.testEdges();
|
|
563
|
+
});
|
|
564
|
+
test("ents", async () => {
|
|
565
|
+
await filter.testEnts();
|
|
566
|
+
});
|
|
567
|
+
});
|
|
428
568
|
}
|
|
429
569
|
exports.assocTests = assocTests;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snowtop/ent",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "snowtop ent framework",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
"optional": true
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": "^16.1.0"
|
|
42
|
+
},
|
|
40
43
|
"devDependencies": {},
|
|
41
44
|
"scripts": {},
|
|
42
45
|
"bin": {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Schema, AssocEdge, AssocEdgeGroup, Action } from "../schema";
|
|
2
|
+
import { ActionField } from "../schema/schema";
|
|
3
|
+
declare enum NullableResult {
|
|
4
|
+
CONTENTS = "contents",
|
|
5
|
+
CONTENTS_AND_LIST = "contentsAndList",
|
|
6
|
+
ITEM = "true"
|
|
7
|
+
}
|
|
8
|
+
declare type ProcessedActionField = Omit<ActionField, "nullable"> & {
|
|
9
|
+
nullable?: NullableResult;
|
|
10
|
+
};
|
|
11
|
+
declare type ProcessedAssocEdge = Omit<AssocEdge, "actionOnlyFields" | "edgeActions"> & {
|
|
12
|
+
patternName?: string;
|
|
13
|
+
edgeActions?: OutputAction[];
|
|
14
|
+
};
|
|
15
|
+
declare type ProcessedSchema = Omit<Schema, "edges" | "actions" | "edgeGroups"> & {
|
|
16
|
+
actions: OutputAction[];
|
|
17
|
+
assocEdges: ProcessedAssocEdge[];
|
|
18
|
+
assocEdgeGroups: ProcessedAssocEdgeGroup[];
|
|
19
|
+
};
|
|
20
|
+
declare type ProcessedAssocEdgeGroup = Omit<AssocEdgeGroup, "edgeAction"> & {
|
|
21
|
+
edgeAction?: OutputAction;
|
|
22
|
+
};
|
|
23
|
+
declare type OutputAction = Omit<Action, "actionOnlyFields"> & {
|
|
24
|
+
actionOnlyFields?: ProcessedActionField[];
|
|
25
|
+
};
|
|
26
|
+
interface schemasDict {
|
|
27
|
+
[key: string]: ProcessedSchema;
|
|
28
|
+
}
|
|
29
|
+
interface ProcessedPattern {
|
|
30
|
+
name: string;
|
|
31
|
+
assocEdges: ProcessedAssocEdge[];
|
|
32
|
+
}
|
|
33
|
+
interface patternsDict {
|
|
34
|
+
[key: string]: ProcessedPattern;
|
|
35
|
+
}
|
|
36
|
+
interface Result {
|
|
37
|
+
schemas: schemasDict;
|
|
38
|
+
patterns: patternsDict;
|
|
39
|
+
}
|
|
40
|
+
export declare function parseSchema(potentialSchemas: {}): Result;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseSchema = void 0;
|
|
4
|
+
function processFields(processedSchema, src) {
|
|
5
|
+
for (const field of src) {
|
|
6
|
+
let f = { ...field };
|
|
7
|
+
f["hasDefaultValueOnCreate"] = field.defaultValueOnCreate != undefined;
|
|
8
|
+
f["hasDefaultValueOnEdit"] = field.defaultValueOnEdit != undefined;
|
|
9
|
+
if (field.polymorphic) {
|
|
10
|
+
// convert boolean into object
|
|
11
|
+
// we keep boolean as an option to keep API simple
|
|
12
|
+
if (typeof field.polymorphic === "boolean") {
|
|
13
|
+
f["polymorphic"] = {};
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
f["polymorphic"] = field.polymorphic;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
processedSchema.fields.push(f);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function processEdges(dst, src, patternName) {
|
|
23
|
+
for (const edge of src) {
|
|
24
|
+
let edge2 = { ...edge };
|
|
25
|
+
edge2.edgeActions = edge.edgeActions?.map((action) => processAction(action));
|
|
26
|
+
edge2.patternName = patternName;
|
|
27
|
+
dst.push(edge2);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function processEdgeGroups(processedSchema, edgeGroups) {
|
|
31
|
+
// array-ify this
|
|
32
|
+
for (const group of edgeGroups) {
|
|
33
|
+
if (group.nullStates && !Array.isArray(group.nullStates)) {
|
|
34
|
+
group.nullStates = [group.nullStates];
|
|
35
|
+
}
|
|
36
|
+
let group2 = { ...group };
|
|
37
|
+
if (group.edgeAction) {
|
|
38
|
+
group2.edgeAction = processAction(group.edgeAction);
|
|
39
|
+
}
|
|
40
|
+
processedSchema.assocEdgeGroups.push(group2);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function processPattern(patterns, pattern, processedSchema) {
|
|
44
|
+
// TODO kill
|
|
45
|
+
let name = pattern.name || "node";
|
|
46
|
+
if (patterns[name] === undefined) {
|
|
47
|
+
const edges = [];
|
|
48
|
+
if (pattern.edges) {
|
|
49
|
+
processEdges(edges, pattern.edges);
|
|
50
|
+
}
|
|
51
|
+
patterns[name] = {
|
|
52
|
+
name: pattern.name,
|
|
53
|
+
assocEdges: edges,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// TODO ideally we want to make sure that different patterns don't have the same name
|
|
58
|
+
// can't do a deepEqual check because function calls and therefore different instances in fields
|
|
59
|
+
}
|
|
60
|
+
processFields(processedSchema, pattern.fields);
|
|
61
|
+
if (pattern.edges) {
|
|
62
|
+
processEdges(processedSchema.assocEdges, pattern.edges, pattern.name);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
var NullableResult;
|
|
66
|
+
(function (NullableResult) {
|
|
67
|
+
NullableResult["CONTENTS"] = "contents";
|
|
68
|
+
NullableResult["CONTENTS_AND_LIST"] = "contentsAndList";
|
|
69
|
+
NullableResult["ITEM"] = "true";
|
|
70
|
+
})(NullableResult || (NullableResult = {}));
|
|
71
|
+
function processAction(action) {
|
|
72
|
+
if (!action.actionOnlyFields) {
|
|
73
|
+
return { ...action };
|
|
74
|
+
}
|
|
75
|
+
let ret = { ...action };
|
|
76
|
+
let actionOnlyFields = action.actionOnlyFields.map((f) => {
|
|
77
|
+
let f2 = f;
|
|
78
|
+
if (!f.nullable) {
|
|
79
|
+
return f2;
|
|
80
|
+
}
|
|
81
|
+
if (typeof f.nullable === "boolean") {
|
|
82
|
+
f2.nullable = NullableResult.ITEM;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
if (f.nullable === "contentsAndList") {
|
|
86
|
+
f2.nullable = NullableResult.CONTENTS_AND_LIST;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
f2.nullable = NullableResult.CONTENTS;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return f2;
|
|
93
|
+
});
|
|
94
|
+
ret.actionOnlyFields = actionOnlyFields;
|
|
95
|
+
return ret;
|
|
96
|
+
}
|
|
97
|
+
function parseSchema(potentialSchemas) {
|
|
98
|
+
let schemas = {};
|
|
99
|
+
let patterns = {};
|
|
100
|
+
for (const key in potentialSchemas) {
|
|
101
|
+
const value = potentialSchemas[key];
|
|
102
|
+
let schema;
|
|
103
|
+
if (value.constructor == Object) {
|
|
104
|
+
schema = value;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
schema = new value();
|
|
108
|
+
}
|
|
109
|
+
let processedSchema = {
|
|
110
|
+
fields: [],
|
|
111
|
+
tableName: schema.tableName,
|
|
112
|
+
enumTable: schema.enumTable,
|
|
113
|
+
dbRows: schema.dbRows,
|
|
114
|
+
constraints: schema.constraints,
|
|
115
|
+
indices: schema.indices,
|
|
116
|
+
hideFromGraphQL: schema.hideFromGraphQL,
|
|
117
|
+
actions: schema.actions?.map((action) => processAction(action)) || [],
|
|
118
|
+
assocEdges: [],
|
|
119
|
+
assocEdgeGroups: [],
|
|
120
|
+
};
|
|
121
|
+
// let's put patterns first just so we have id, created_at, updated_at first
|
|
122
|
+
// ¯\_(ツ)_/¯
|
|
123
|
+
if (schema.patterns) {
|
|
124
|
+
for (const pattern of schema.patterns) {
|
|
125
|
+
processPattern(patterns, pattern, processedSchema);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
processFields(processedSchema, schema.fields);
|
|
129
|
+
if (schema.edges) {
|
|
130
|
+
processEdges(processedSchema.assocEdges, schema.edges);
|
|
131
|
+
}
|
|
132
|
+
if (schema.edgeGroups) {
|
|
133
|
+
processEdgeGroups(processedSchema, schema.edgeGroups);
|
|
134
|
+
}
|
|
135
|
+
schemas[key] = processedSchema;
|
|
136
|
+
}
|
|
137
|
+
return { schemas, patterns };
|
|
138
|
+
}
|
|
139
|
+
exports.parseSchema = parseSchema;
|
package/schema/base_schema.d.ts
CHANGED
|
@@ -2,8 +2,10 @@ import { Pattern } from "./schema";
|
|
|
2
2
|
export declare const Timestamps: Pattern;
|
|
3
3
|
export declare const Node: Pattern;
|
|
4
4
|
export declare abstract class BaseEntSchema {
|
|
5
|
+
addPatterns(...patterns: Pattern[]): void;
|
|
5
6
|
patterns: Pattern[];
|
|
6
7
|
}
|
|
7
8
|
export declare abstract class BaseEntSchemaWithTZ {
|
|
9
|
+
addPatterns(...patterns: Pattern[]): void;
|
|
8
10
|
patterns: Pattern[];
|
|
9
11
|
}
|
package/schema/base_schema.js
CHANGED
|
@@ -26,6 +26,7 @@ let tsFields = [
|
|
|
26
26
|
];
|
|
27
27
|
// Timestamps is a Pattern that adds a createdAt and updatedAt timestamp fields to the ent
|
|
28
28
|
exports.Timestamps = {
|
|
29
|
+
name: "timestamps",
|
|
29
30
|
fields: tsFields,
|
|
30
31
|
};
|
|
31
32
|
let nodeField = (0, field_1.UUIDType)({
|
|
@@ -63,6 +64,7 @@ let nodeFieldsWithTZ = [
|
|
|
63
64
|
];
|
|
64
65
|
// Node is a Pattern that adds 3 fields to the ent: (id, createdAt, and updatedAt timestamps)
|
|
65
66
|
exports.Node = {
|
|
67
|
+
name: "node",
|
|
66
68
|
fields: nodeFields,
|
|
67
69
|
};
|
|
68
70
|
// Base ent schema. has Node Pattern by default.
|
|
@@ -71,15 +73,23 @@ class BaseEntSchema {
|
|
|
71
73
|
constructor() {
|
|
72
74
|
this.patterns = [exports.Node];
|
|
73
75
|
}
|
|
76
|
+
addPatterns(...patterns) {
|
|
77
|
+
this.patterns.push(...patterns);
|
|
78
|
+
}
|
|
74
79
|
}
|
|
75
80
|
exports.BaseEntSchema = BaseEntSchema;
|
|
76
81
|
class BaseEntSchemaWithTZ {
|
|
77
82
|
constructor() {
|
|
78
83
|
this.patterns = [
|
|
79
84
|
{
|
|
85
|
+
// default schema added
|
|
86
|
+
name: "nodeWithTZ",
|
|
80
87
|
fields: nodeFieldsWithTZ,
|
|
81
88
|
},
|
|
82
89
|
];
|
|
83
90
|
}
|
|
91
|
+
addPatterns(...patterns) {
|
|
92
|
+
this.patterns.push(...patterns);
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
95
|
exports.BaseEntSchemaWithTZ = BaseEntSchemaWithTZ;
|
package/schema/schema.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface AssocEdge {
|
|
|
24
24
|
tableName?: string;
|
|
25
25
|
edgeActions?: EdgeAction[];
|
|
26
26
|
hideFromGraphQL?: boolean;
|
|
27
|
+
edgeConstName?: string;
|
|
27
28
|
}
|
|
28
29
|
export interface EdgeAction {
|
|
29
30
|
operation: ActionOperation;
|
|
@@ -34,6 +35,7 @@ export interface EdgeAction {
|
|
|
34
35
|
}
|
|
35
36
|
export interface InverseAssocEdge {
|
|
36
37
|
name: string;
|
|
38
|
+
edgeConstName?: string;
|
|
37
39
|
}
|
|
38
40
|
export interface EdgeGroupAction {
|
|
39
41
|
operation: ActionOperation.EdgeGroup;
|
|
@@ -54,7 +56,9 @@ export interface AssocEdgeGroup {
|
|
|
54
56
|
}
|
|
55
57
|
export declare type Edge = AssocEdge;
|
|
56
58
|
export interface Pattern {
|
|
59
|
+
name: string;
|
|
57
60
|
fields: Field[];
|
|
61
|
+
edges?: Edge[];
|
|
58
62
|
}
|
|
59
63
|
export declare enum DBType {
|
|
60
64
|
UUID = "UUID",
|
package/scripts/read_schema.js
CHANGED
|
@@ -27,56 +27,7 @@ const path = __importStar(require("path"));
|
|
|
27
27
|
const pascal_case_1 = require("pascal-case");
|
|
28
28
|
const minimist_1 = __importDefault(require("minimist"));
|
|
29
29
|
const process_1 = require("process");
|
|
30
|
-
|
|
31
|
-
for (const field of src) {
|
|
32
|
-
let f = {};
|
|
33
|
-
f = field;
|
|
34
|
-
f["hasDefaultValueOnCreate"] = field.defaultValueOnCreate != undefined;
|
|
35
|
-
f["hasDefaultValueOnEdit"] = field.defaultValueOnEdit != undefined;
|
|
36
|
-
if (field.polymorphic) {
|
|
37
|
-
// convert boolean into object
|
|
38
|
-
// we keep boolean as an option to keep API simple
|
|
39
|
-
if (typeof field.polymorphic === "boolean") {
|
|
40
|
-
f["polymorphic"] = {};
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
f["polymorphic"] = field.polymorphic;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
dst.push(f);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
var NullableResult;
|
|
50
|
-
(function (NullableResult) {
|
|
51
|
-
NullableResult["CONTENTS"] = "contents";
|
|
52
|
-
NullableResult["CONTENTS_AND_LIST"] = "contentsAndList";
|
|
53
|
-
NullableResult["ITEM"] = "true";
|
|
54
|
-
})(NullableResult || (NullableResult = {}));
|
|
55
|
-
function processAction(action) {
|
|
56
|
-
if (!action.actionOnlyFields) {
|
|
57
|
-
return action;
|
|
58
|
-
}
|
|
59
|
-
let ret = action;
|
|
60
|
-
ret.actionOnlyFields = action.actionOnlyFields.map((f) => {
|
|
61
|
-
let f2 = f;
|
|
62
|
-
if (!f.nullable) {
|
|
63
|
-
return f2;
|
|
64
|
-
}
|
|
65
|
-
if (typeof f.nullable === "boolean") {
|
|
66
|
-
f2.nullable = NullableResult.ITEM;
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
if (f.nullable === "contentsAndList") {
|
|
70
|
-
f2.nullable = NullableResult.CONTENTS_AND_LIST;
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
f2.nullable = NullableResult.CONTENTS;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return f2;
|
|
77
|
-
});
|
|
78
|
-
return ret;
|
|
79
|
-
}
|
|
30
|
+
const parse_1 = require("../parse_schema/parse");
|
|
80
31
|
function main() {
|
|
81
32
|
const options = (0, minimist_1.default)(process.argv.slice(2));
|
|
82
33
|
if (!options.path) {
|
|
@@ -96,61 +47,8 @@ function main() {
|
|
|
96
47
|
potentialSchemas[(0, pascal_case_1.pascalCase)(match[1])] = require(p).default;
|
|
97
48
|
}
|
|
98
49
|
// console.log(potentialSchemas);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const value = potentialSchemas[key];
|
|
102
|
-
let schema;
|
|
103
|
-
if (value.constructor == Object) {
|
|
104
|
-
schema = value;
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
schema = new value();
|
|
108
|
-
}
|
|
109
|
-
// let's put patterns first just so we have id, created_at, updated_at first
|
|
110
|
-
// ¯\_(ツ)_/¯
|
|
111
|
-
let fields = [];
|
|
112
|
-
if (schema.patterns) {
|
|
113
|
-
for (const pattern of schema.patterns) {
|
|
114
|
-
processFields(fields, pattern.fields);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
processFields(fields, schema.fields);
|
|
118
|
-
let assocEdges = [];
|
|
119
|
-
let assocEdgeGroups = [];
|
|
120
|
-
if (schema.edges) {
|
|
121
|
-
for (const edge of schema.edges) {
|
|
122
|
-
let edge2 = edge;
|
|
123
|
-
edge2.edgeActions = edge.edgeActions?.map((action) => processAction(action));
|
|
124
|
-
assocEdges.push(edge2);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
if (schema.edgeGroups) {
|
|
128
|
-
// array-ify this
|
|
129
|
-
for (const group of schema.edgeGroups) {
|
|
130
|
-
if (group.nullStates && !Array.isArray(group.nullStates)) {
|
|
131
|
-
group.nullStates = [group.nullStates];
|
|
132
|
-
}
|
|
133
|
-
let group2 = group;
|
|
134
|
-
if (group.edgeAction) {
|
|
135
|
-
group2.edgeAction = processAction(group.edgeAction);
|
|
136
|
-
}
|
|
137
|
-
assocEdgeGroups.push(group2);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
schemas[key] = {
|
|
141
|
-
tableName: schema.tableName,
|
|
142
|
-
fields: fields,
|
|
143
|
-
assocEdges: assocEdges,
|
|
144
|
-
assocEdgeGroups: assocEdgeGroups,
|
|
145
|
-
actions: schema.actions?.map((action) => processAction(action)),
|
|
146
|
-
enumTable: schema.enumTable,
|
|
147
|
-
dbRows: schema.dbRows,
|
|
148
|
-
constraints: schema.constraints,
|
|
149
|
-
indices: schema.indices,
|
|
150
|
-
hideFromGraphQL: schema.hideFromGraphQL,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
console.log(JSON.stringify(schemas));
|
|
50
|
+
const result = (0, parse_1.parseSchema)(potentialSchemas);
|
|
51
|
+
console.log(JSON.stringify(result));
|
|
154
52
|
}
|
|
155
53
|
try {
|
|
156
54
|
main();
|
package/testutils/db/test_db.js
CHANGED
|
@@ -354,11 +354,9 @@ class TempDB {
|
|
|
354
354
|
await this.dbClient.query(table.create());
|
|
355
355
|
}
|
|
356
356
|
else {
|
|
357
|
-
// console.log(table.create());
|
|
358
357
|
this.sqlite.exec(table.create());
|
|
359
358
|
}
|
|
360
359
|
}
|
|
361
|
-
// await this.sqlite.exec("nonsense");
|
|
362
360
|
}
|
|
363
361
|
getSqliteClient() {
|
|
364
362
|
return this.sqlite;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Ent, LoadEntOptions } from "../../core/base";
|
|
1
2
|
export declare enum EdgeType {
|
|
2
3
|
UserToContacts = "userToContacts",
|
|
3
4
|
UserToFriends = "userToFriends",
|
|
@@ -10,7 +11,9 @@ export declare enum EdgeType {
|
|
|
10
11
|
EventToHosts = "eventToHosts",
|
|
11
12
|
UserToHostedEvents = "userToHostedEvents",
|
|
12
13
|
UserToFriendRequests = "userToFriendRequests",
|
|
13
|
-
UserToIncomingFriendRequests = "userToIncomingFriendRequests"
|
|
14
|
+
UserToIncomingFriendRequests = "userToIncomingFriendRequests",
|
|
15
|
+
UserToFollowing = "userToFollowing",
|
|
16
|
+
ObjectToFollowedUsers = "objectToFollowedUsers"
|
|
14
17
|
}
|
|
15
18
|
export declare enum NodeType {
|
|
16
19
|
FakeUser = "user",
|
|
@@ -19,3 +22,4 @@ export declare enum NodeType {
|
|
|
19
22
|
}
|
|
20
23
|
export declare const SymmetricEdges: Set<string>;
|
|
21
24
|
export declare const InverseEdges: Map<EdgeType, EdgeType>;
|
|
25
|
+
export declare function getLoaderOptions(type: NodeType): LoadEntOptions<Ent>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InverseEdges = exports.SymmetricEdges = exports.NodeType = exports.EdgeType = void 0;
|
|
3
|
+
exports.getLoaderOptions = exports.InverseEdges = exports.SymmetricEdges = exports.NodeType = exports.EdgeType = void 0;
|
|
4
|
+
const internal_1 = require("./internal");
|
|
4
5
|
var EdgeType;
|
|
5
6
|
(function (EdgeType) {
|
|
6
7
|
EdgeType["UserToContacts"] = "userToContacts";
|
|
@@ -16,6 +17,10 @@ var EdgeType;
|
|
|
16
17
|
EdgeType["UserToHostedEvents"] = "userToHostedEvents";
|
|
17
18
|
EdgeType["UserToFriendRequests"] = "userToFriendRequests";
|
|
18
19
|
EdgeType["UserToIncomingFriendRequests"] = "userToIncomingFriendRequests";
|
|
20
|
+
// can follow users or events...
|
|
21
|
+
// so a polymorphic edge
|
|
22
|
+
EdgeType["UserToFollowing"] = "userToFollowing";
|
|
23
|
+
EdgeType["ObjectToFollowedUsers"] = "objectToFollowedUsers";
|
|
19
24
|
})(EdgeType = exports.EdgeType || (exports.EdgeType = {}));
|
|
20
25
|
var NodeType;
|
|
21
26
|
(function (NodeType) {
|
|
@@ -32,4 +37,17 @@ exports.InverseEdges = new Map([
|
|
|
32
37
|
[EdgeType.EventToHosts, EdgeType.UserToHostedEvents],
|
|
33
38
|
[EdgeType.UserToFriendRequests, EdgeType.UserToIncomingFriendRequests],
|
|
34
39
|
[EdgeType.UserToIncomingFriendRequests, EdgeType.UserToFriendRequests],
|
|
40
|
+
[EdgeType.UserToFollowing, EdgeType.ObjectToFollowedUsers],
|
|
41
|
+
[EdgeType.ObjectToFollowedUsers, EdgeType.UserToFollowing],
|
|
35
42
|
]);
|
|
43
|
+
function getLoaderOptions(type) {
|
|
44
|
+
switch (type) {
|
|
45
|
+
case NodeType.FakeContact:
|
|
46
|
+
return internal_1.FakeContact.loaderOptions();
|
|
47
|
+
case NodeType.FakeUser:
|
|
48
|
+
return internal_1.FakeUser.loaderOptions();
|
|
49
|
+
case NodeType.FakeEvent:
|
|
50
|
+
return internal_1.FakeEvent.loaderOptions();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.getLoaderOptions = getLoaderOptions;
|
|
@@ -31,6 +31,8 @@ class FakeUser {
|
|
|
31
31
|
privacy_1.AllowIfViewerRule,
|
|
32
32
|
//can view user if friends
|
|
33
33
|
new privacy_1.AllowIfViewerInboundEdgeExistsRule(internal_1.EdgeType.UserToFriends),
|
|
34
|
+
//can view user if following
|
|
35
|
+
new privacy_1.AllowIfViewerInboundEdgeExistsRule(internal_1.EdgeType.UserToFollowing),
|
|
34
36
|
new privacy_1.AllowIfConditionAppliesRule((viewer, ent) => {
|
|
35
37
|
if (!(viewer instanceof ViewerWithAccessToken)) {
|
|
36
38
|
return false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ID, Viewer } from "../../core/base";
|
|
1
|
+
import { Ent, ID, Viewer } from "../../core/base";
|
|
2
2
|
import { CustomEdgeQueryBase } from "../../core/query/custom_query";
|
|
3
3
|
import { AssocEdge } from "../../core/ent";
|
|
4
4
|
import * as clause from "../../core/clause";
|
|
@@ -81,3 +81,7 @@ export declare class UserToEventsInNextWeekQuery extends CustomEdgeQueryBase<Fak
|
|
|
81
81
|
constructor(viewer: Viewer, src: ID | FakeUser);
|
|
82
82
|
static query(viewer: Viewer, src: FakeUser | ID): UserToEventsInNextWeekQuery;
|
|
83
83
|
}
|
|
84
|
+
export declare class UserToFollowingQuery extends AssocEdgeQueryBase<FakeUser, Ent, AssocEdge> {
|
|
85
|
+
constructor(viewer: Viewer, src: EdgeQuerySource<FakeUser>);
|
|
86
|
+
static query(viewer: Viewer, src: EdgeQuerySource<FakeUser>): UserToFollowingQuery;
|
|
87
|
+
}
|
|
@@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.UserToEventsInNextWeekQuery = exports.userToEventsInNextWeekDataLoaderFactory = exports.userToEventsInNextWeekCountLoaderFactory = exports.getCompleteClause = exports.getNextWeekClause = exports.UserToHostedEventsQuery = exports.UserToEventsAttendingQuery = exports.UserToIncomingFriendRequestsQuery = exports.UserToFriendRequestsQuery = exports.UserToCustomEdgeQuery = exports.CustomEdge = exports.UserToFriendsQuery = exports.UserToContactsFkeyQuery = exports.userToContactsDataLoaderFactory = exports.userToContactsCountLoaderFactory = exports.UserToContactsQuery = void 0;
|
|
22
|
+
exports.UserToFollowingQuery = exports.UserToEventsInNextWeekQuery = exports.userToEventsInNextWeekDataLoaderFactory = exports.userToEventsInNextWeekCountLoaderFactory = exports.getCompleteClause = exports.getNextWeekClause = exports.UserToHostedEventsQuery = exports.UserToEventsAttendingQuery = exports.UserToIncomingFriendRequestsQuery = exports.UserToFriendRequestsQuery = exports.UserToCustomEdgeQuery = exports.CustomEdge = exports.UserToFriendsQuery = exports.UserToContactsFkeyQuery = exports.userToContactsDataLoaderFactory = exports.userToContactsCountLoaderFactory = exports.UserToContactsQuery = void 0;
|
|
23
23
|
const custom_query_1 = require("../../core/query/custom_query");
|
|
24
24
|
const ent_1 = require("../../core/ent");
|
|
25
25
|
const clause = __importStar(require("../../core/clause"));
|
|
@@ -34,6 +34,7 @@ const jest_date_mock_1 = require("jest-date-mock");
|
|
|
34
34
|
const luxon_1 = require("luxon");
|
|
35
35
|
const query_loader_1 = require("../../core/loaders/query_loader");
|
|
36
36
|
const mock_date_1 = require("./../mock_date");
|
|
37
|
+
const _1 = require(".");
|
|
37
38
|
class UserToContactsQuery extends assoc_query_1.AssocEdgeQueryBase {
|
|
38
39
|
constructor(viewer, src) {
|
|
39
40
|
super(viewer, src, new assoc_count_loader_1.AssocEdgeCountLoaderFactory(internal_1.EdgeType.UserToContacts), new assoc_edge_loader_1.AssocEdgeLoaderFactory(internal_1.EdgeType.UserToContacts, ent_1.AssocEdge), internal_1.FakeContact.loaderOptions());
|
|
@@ -257,3 +258,12 @@ class UserToEventsInNextWeekQuery extends custom_query_1.CustomEdgeQueryBase {
|
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
260
|
exports.UserToEventsInNextWeekQuery = UserToEventsInNextWeekQuery;
|
|
261
|
+
class UserToFollowingQuery extends assoc_query_1.AssocEdgeQueryBase {
|
|
262
|
+
constructor(viewer, src) {
|
|
263
|
+
super(viewer, src, new assoc_count_loader_1.AssocEdgeCountLoaderFactory(internal_1.EdgeType.UserToFollowing), new assoc_edge_loader_1.AssocEdgeLoaderFactory(internal_1.EdgeType.UserToFollowing, ent_1.AssocEdge), _1.getLoaderOptions);
|
|
264
|
+
}
|
|
265
|
+
static query(viewer, src) {
|
|
266
|
+
return new UserToFollowingQuery(viewer, src);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
exports.UserToFollowingQuery = UserToFollowingQuery;
|