@snowtop/ent 0.1.0-alpha56 → 0.1.0-alpha58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/action/orchestrator.js +21 -0
- package/core/base.d.ts +1 -1
- package/core/clause.d.ts +6 -3
- package/core/clause.js +39 -14
- package/core/config.d.ts +5 -2
- package/core/ent.d.ts +16 -3
- package/core/ent.js +147 -35
- package/core/loaders/assoc_count_loader.js +6 -1
- package/core/query/shared_assoc_test.d.ts +1 -1
- package/core/query/shared_assoc_test.js +17 -5
- package/core/query/shared_test.d.ts +3 -0
- package/core/query/shared_test.js +95 -17
- package/index.d.ts +1 -1
- package/index.js +3 -2
- package/package.json +1 -1
- package/parse_schema/parse.d.ts +8 -2
- package/parse_schema/parse.js +22 -2
- package/schema/index.d.ts +1 -1
- package/schema/schema.d.ts +15 -0
- package/scripts/custom_graphql.js +1 -1
- package/scripts/read_schema.js +10 -1
- package/testutils/db/{test_db.d.ts → temp_db.d.ts} +4 -2
- package/testutils/db/{test_db.js → temp_db.js} +16 -5
- package/testutils/fake_data/fake_contact.d.ts +1 -1
- package/testutils/fake_data/fake_contact.js +2 -2
- package/testutils/fake_data/fake_event.d.ts +1 -1
- package/testutils/fake_data/fake_event.js +3 -3
- package/testutils/fake_data/fake_user.d.ts +1 -1
- package/testutils/fake_data/fake_user.js +2 -2
- package/testutils/fake_data/test_helpers.d.ts +2 -2
- package/testutils/fake_data/test_helpers.js +5 -5
- package/testutils/parse_sql.js +4 -0
- package/testutils/test_edge_global_schema.d.ts +15 -0
- package/testutils/test_edge_global_schema.js +58 -0
- package/testutils/write.d.ts +2 -2
- package/testutils/write.js +3 -3
- package/tsc/ast.d.ts +1 -0
- package/tsc/ast.js +3 -0
|
@@ -41,10 +41,15 @@ class AssocEdgeCountLoader {
|
|
|
41
41
|
if (!edgeData) {
|
|
42
42
|
throw new Error(`error loading edge data for ${this.edgeType}`);
|
|
43
43
|
}
|
|
44
|
+
const { cls } = (0, ent_1.getEdgeClauseAndFields)(clause.Eq("edge_type", this.edgeType), {
|
|
45
|
+
// don't need this..
|
|
46
|
+
id1: "1",
|
|
47
|
+
edgeType: this.edgeType,
|
|
48
|
+
});
|
|
44
49
|
this.loader = (0, raw_count_loader_1.createCountDataLoader)({
|
|
45
50
|
tableName: edgeData.edgeTable,
|
|
46
51
|
groupCol: "id1",
|
|
47
|
-
clause:
|
|
52
|
+
clause: cls,
|
|
48
53
|
});
|
|
49
54
|
return this.loader;
|
|
50
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function assocTests(): void;
|
|
1
|
+
export declare function assocTests(global?: boolean): void;
|
|
@@ -27,7 +27,7 @@ const jest_date_mock_1 = require("jest-date-mock");
|
|
|
27
27
|
const index_1 = require("../../testutils/fake_data/index");
|
|
28
28
|
const test_helpers_1 = require("../../testutils/fake_data/test_helpers");
|
|
29
29
|
const db_1 = __importStar(require("../db"));
|
|
30
|
-
function assocTests() {
|
|
30
|
+
function assocTests(global = false) {
|
|
31
31
|
describe("custom edge", () => {
|
|
32
32
|
let user1, user2;
|
|
33
33
|
beforeEach(async () => {
|
|
@@ -76,9 +76,16 @@ function assocTests() {
|
|
|
76
76
|
for (let i = 0; i < numQueries; i++) {
|
|
77
77
|
const query = queries[i];
|
|
78
78
|
let expLimit = disablePaginationBump ? limit : limit + 1;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
if (global) {
|
|
80
|
+
expect(query.qs?.whereClause, `${i}`).toBe(
|
|
81
|
+
// default limit
|
|
82
|
+
`id1 = $1 AND edge_type = $2 AND deleted_at IS NULL ORDER BY time DESC LIMIT ${expLimit}`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
expect(query.qs?.whereClause, `${i}`).toBe(
|
|
86
|
+
// default limit
|
|
87
|
+
`id1 = $1 AND edge_type = $2 ORDER BY time DESC LIMIT ${expLimit}`);
|
|
88
|
+
}
|
|
82
89
|
}
|
|
83
90
|
}
|
|
84
91
|
function verifyCountQuery({ length = 1, numQueries = 1 }) {
|
|
@@ -89,7 +96,12 @@ function assocTests() {
|
|
|
89
96
|
expect(queries.length).toBe(length);
|
|
90
97
|
for (let i = 0; i < numQueries; i++) {
|
|
91
98
|
const query = queries[i];
|
|
92
|
-
|
|
99
|
+
if (global) {
|
|
100
|
+
expect(query.qs?.whereClause).toBe(`id1 = $1 AND edge_type = $2 AND deleted_at IS NULL`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
expect(query.qs?.whereClause).toBe(`id1 = $1 AND edge_type = $2`);
|
|
104
|
+
}
|
|
93
105
|
}
|
|
94
106
|
}
|
|
95
107
|
// TODO need to test multi-ids with id1s that aren't visible...
|
|
@@ -4,11 +4,14 @@ import { EdgeQuery } from "./query";
|
|
|
4
4
|
interface options<TData extends Data> {
|
|
5
5
|
newQuery: (v: Viewer, user: FakeUser) => EdgeQuery<FakeUser, FakeContact, TData>;
|
|
6
6
|
tableName: string;
|
|
7
|
+
uniqKey: string;
|
|
7
8
|
entsLength?: number;
|
|
8
9
|
where: string;
|
|
9
10
|
sortCol: string;
|
|
10
11
|
livePostgresDB?: boolean;
|
|
11
12
|
sqlite?: boolean;
|
|
13
|
+
globalSchema?: boolean;
|
|
14
|
+
rawDataVerify?(user: FakeUser): Promise<void>;
|
|
12
15
|
}
|
|
13
16
|
export declare const commonTests: <TData extends Data>(opts: options<TData>) => void;
|
|
14
17
|
export {};
|
|
@@ -6,9 +6,12 @@ const ent_1 = require("../ent");
|
|
|
6
6
|
const viewer_1 = require("../viewer");
|
|
7
7
|
const index_1 = require("../../testutils/fake_data/index");
|
|
8
8
|
const test_helpers_1 = require("../../testutils/fake_data/test_helpers");
|
|
9
|
-
const
|
|
9
|
+
const temp_db_1 = require("../../testutils/db/temp_db");
|
|
10
10
|
const test_context_1 = require("../../testutils/context/test_context");
|
|
11
11
|
const logger_1 = require("../logger");
|
|
12
|
+
const test_edge_global_schema_1 = require("../../testutils/test_edge_global_schema");
|
|
13
|
+
const builder_1 = require("../../testutils/builder");
|
|
14
|
+
const action_1 = require("../../action");
|
|
12
15
|
class TestQueryFilter {
|
|
13
16
|
constructor(filter, newQuery, ents, defaultViewer) {
|
|
14
17
|
this.filter = filter;
|
|
@@ -37,19 +40,19 @@ class TestQueryFilter {
|
|
|
37
40
|
expect(ids).toEqual(this.filteredContacts.map((contact) => contact.id));
|
|
38
41
|
}
|
|
39
42
|
// rawCount isn't affected by filters...
|
|
40
|
-
async testRawCount() {
|
|
43
|
+
async testRawCount(expectedCount) {
|
|
41
44
|
const count = await this.getQuery().queryRawCount();
|
|
42
|
-
this.verifyRawCount(count);
|
|
45
|
+
this.verifyRawCount(count, expectedCount);
|
|
43
46
|
}
|
|
44
|
-
verifyRawCount(count) {
|
|
45
|
-
expect(count).toBe(test_helpers_1.inputs.length);
|
|
47
|
+
verifyRawCount(count, expectedCount) {
|
|
48
|
+
expect(count).toBe(expectedCount ?? test_helpers_1.inputs.length);
|
|
46
49
|
}
|
|
47
|
-
async testCount() {
|
|
50
|
+
async testCount(expectedCount) {
|
|
48
51
|
const count = await this.getQuery().queryCount();
|
|
49
|
-
this.verifyCount(count);
|
|
52
|
+
this.verifyCount(count, expectedCount);
|
|
50
53
|
}
|
|
51
|
-
verifyCount(count) {
|
|
52
|
-
expect(count).toBe(this.filteredContacts.length);
|
|
54
|
+
verifyCount(count, expectedCount) {
|
|
55
|
+
expect(count).toBe(expectedCount ?? this.filteredContacts.length);
|
|
53
56
|
}
|
|
54
57
|
async testEdges() {
|
|
55
58
|
const edges = await this.getQuery().queryEdges();
|
|
@@ -72,7 +75,7 @@ class TestQueryFilter {
|
|
|
72
75
|
verifyEnts(ents) {
|
|
73
76
|
(0, test_helpers_1.verifyUserToContacts)(this.user, ents, this.filteredContacts);
|
|
74
77
|
}
|
|
75
|
-
async testAll() {
|
|
78
|
+
async testAll(expectedCount) {
|
|
76
79
|
const query = this.getQuery(new viewer_1.IDViewer(this.user.id));
|
|
77
80
|
const [edges, count, ids, rawCount, ents] = await Promise.all([
|
|
78
81
|
query.queryEdges(),
|
|
@@ -81,10 +84,10 @@ class TestQueryFilter {
|
|
|
81
84
|
query.queryRawCount(),
|
|
82
85
|
query.queryEnts(),
|
|
83
86
|
]);
|
|
84
|
-
this.verifyCount(count);
|
|
87
|
+
this.verifyCount(count, expectedCount);
|
|
85
88
|
this.verifyEdges(edges);
|
|
86
89
|
this.verifyIDs(ids);
|
|
87
|
-
this.verifyRawCount(rawCount);
|
|
90
|
+
this.verifyRawCount(rawCount, expectedCount);
|
|
88
91
|
this.verifyEnts(ents);
|
|
89
92
|
}
|
|
90
93
|
}
|
|
@@ -125,7 +128,19 @@ const commonTests = (opts) => {
|
|
|
125
128
|
expect(queries.length).toBe(length);
|
|
126
129
|
const query = queries[0];
|
|
127
130
|
const result = [...opts.where.matchAll(preparedVar)];
|
|
128
|
-
|
|
131
|
+
let parts = opts.where.split(" AND ");
|
|
132
|
+
if (parts[parts.length - 1] === "deleted_at IS NULL") {
|
|
133
|
+
parts = parts
|
|
134
|
+
.slice(0, parts.length - 1)
|
|
135
|
+
.concat([
|
|
136
|
+
`${opts.sortCol} < $${result.length + 1}`,
|
|
137
|
+
"deleted_at IS NULL",
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
parts.push(`${opts.sortCol} < $${result.length + 1}`);
|
|
142
|
+
}
|
|
143
|
+
expect(query.qs?.whereClause).toBe(`${parts.join(" AND ")} ORDER BY ${opts.sortCol} DESC LIMIT 4`);
|
|
129
144
|
}
|
|
130
145
|
function verifyLastBeforeCursorQuery(length = 1) {
|
|
131
146
|
if (opts.livePostgresDB || opts.sqlite) {
|
|
@@ -135,9 +150,21 @@ const commonTests = (opts) => {
|
|
|
135
150
|
expect(queries.length).toBe(length);
|
|
136
151
|
const query = queries[0];
|
|
137
152
|
const result = [...opts.where.matchAll(preparedVar)];
|
|
153
|
+
let parts = opts.where.split(" AND ");
|
|
154
|
+
if (parts[parts.length - 1] === "deleted_at IS NULL") {
|
|
155
|
+
parts = parts
|
|
156
|
+
.slice(0, parts.length - 1)
|
|
157
|
+
.concat([
|
|
158
|
+
`${opts.sortCol} > $${result.length + 1}`,
|
|
159
|
+
"deleted_at IS NULL",
|
|
160
|
+
]);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
parts.push(`${opts.sortCol} > $${result.length + 1}`);
|
|
164
|
+
}
|
|
138
165
|
expect(query.qs?.whereClause).toBe(
|
|
139
166
|
// extra fetched for pagination
|
|
140
|
-
`${
|
|
167
|
+
`${parts.join(" AND ")} ORDER BY ${opts.sortCol} ASC LIMIT 4`);
|
|
141
168
|
}
|
|
142
169
|
function getViewer() {
|
|
143
170
|
// live db, let's do context because we're testing complicated paths
|
|
@@ -171,10 +198,12 @@ const commonTests = (opts) => {
|
|
|
171
198
|
cursorKey: opts.sortCol,
|
|
172
199
|
});
|
|
173
200
|
}
|
|
201
|
+
if (opts.globalSchema) {
|
|
202
|
+
(0, ent_1.setGlobalSchema)(test_edge_global_schema_1.testEdgeGlobalSchema);
|
|
203
|
+
}
|
|
174
204
|
let tdb;
|
|
175
205
|
if (opts.sqlite) {
|
|
176
|
-
|
|
177
|
-
(0, test_db_1.setupSqlite)(`sqlite:///shared_test+${opts.tableName}.db`, test_helpers_1.tempDBTables);
|
|
206
|
+
(0, temp_db_1.setupSqlite)(`sqlite:///shared_test+${opts.uniqKey}.db`, () => (0, test_helpers_1.tempDBTables)(opts.globalSchema));
|
|
178
207
|
}
|
|
179
208
|
beforeAll(async () => {
|
|
180
209
|
// want error on by default in tests?
|
|
@@ -196,7 +225,7 @@ const commonTests = (opts) => {
|
|
|
196
225
|
});
|
|
197
226
|
describe("simple queries", () => {
|
|
198
227
|
const filter = new TestQueryFilter((q) => {
|
|
199
|
-
// no
|
|
228
|
+
// no filters
|
|
200
229
|
return q;
|
|
201
230
|
}, opts.newQuery, (contacts) => {
|
|
202
231
|
// nothing to do here
|
|
@@ -230,6 +259,55 @@ const commonTests = (opts) => {
|
|
|
230
259
|
await filter.testAll();
|
|
231
260
|
});
|
|
232
261
|
});
|
|
262
|
+
describe("after delete", () => {
|
|
263
|
+
const filter = new TestQueryFilter((q) => {
|
|
264
|
+
// no filters
|
|
265
|
+
return q;
|
|
266
|
+
}, opts.newQuery, (contacts) => {
|
|
267
|
+
// nothing expected since deleted
|
|
268
|
+
return [];
|
|
269
|
+
}, getViewer());
|
|
270
|
+
beforeEach(async () => {
|
|
271
|
+
await filter.beforeEach();
|
|
272
|
+
const action = new builder_1.SimpleAction(filter.user.viewer, index_1.FakeUserSchema, new Map(), action_1.WriteOperation.Edit, filter.user);
|
|
273
|
+
await Promise.all(filter.allContacts.map(async (contact) => {
|
|
274
|
+
action.builder.orchestrator.removeOutboundEdge(contact.id, index_1.EdgeType.UserToContacts);
|
|
275
|
+
const action2 = new builder_1.SimpleAction(filter.user.viewer, index_1.FakeContactSchema, new Map(), action_1.WriteOperation.Delete, contact);
|
|
276
|
+
await action2.save();
|
|
277
|
+
}));
|
|
278
|
+
await action.save();
|
|
279
|
+
db_mock_1.QueryRecorder.clearQueries();
|
|
280
|
+
});
|
|
281
|
+
test("ids", async () => {
|
|
282
|
+
await filter.testIDs();
|
|
283
|
+
verifyQuery({});
|
|
284
|
+
});
|
|
285
|
+
test("rawCount", async () => {
|
|
286
|
+
await filter.testRawCount(0);
|
|
287
|
+
verifyCountQuery({});
|
|
288
|
+
});
|
|
289
|
+
test("count", async () => {
|
|
290
|
+
await filter.testCount(0);
|
|
291
|
+
verifyQuery({});
|
|
292
|
+
});
|
|
293
|
+
test("edges", async () => {
|
|
294
|
+
await filter.testEdges();
|
|
295
|
+
verifyQuery({});
|
|
296
|
+
});
|
|
297
|
+
test("ents", async () => {
|
|
298
|
+
await filter.testEnts();
|
|
299
|
+
// no ents so no subsequent query. just the edge query
|
|
300
|
+
verifyQuery({ length: 1 });
|
|
301
|
+
});
|
|
302
|
+
test("all", async () => {
|
|
303
|
+
await filter.testAll(0);
|
|
304
|
+
});
|
|
305
|
+
test("raw_data", async () => {
|
|
306
|
+
if (opts.rawDataVerify) {
|
|
307
|
+
await opts.rawDataVerify(filter.user);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
});
|
|
233
311
|
describe("first. no cursor", () => {
|
|
234
312
|
const N = 2;
|
|
235
313
|
const filter = new TestQueryFilter((q) => {
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from "./core/base";
|
|
2
|
-
export { loadEnt, loadCustomData, loadCustomEnts, loadEntX, loadEnts, CustomQuery, loadDerivedEnt, loadDerivedEntX, loadEntViaKey, loadEntXViaKey, performRawQuery, loadRowX, loadRow, loadRows, DataOperation, EditNodeOptions, EditNodeOperation, EdgeOperation, DeleteNodeOperation, AssocEdge, AssocEdgeInputOptions, AssocEdgeInput, AssocEdgeData, loadEdgeData, loadEdgeDatas, loadEdges, loadUniqueEdge, loadUniqueNode, loadRawEdgeCountX, loadEdgeForID2, loadNodesByEdge, getEdgeTypeInGroup, } from "./core/ent";
|
|
2
|
+
export { loadEnt, loadCustomData, loadCustomEnts, loadEntX, loadEnts, CustomQuery, loadDerivedEnt, loadDerivedEntX, loadEntViaKey, loadEntXViaKey, performRawQuery, loadRowX, loadRow, loadRows, DataOperation, EditNodeOptions, EditNodeOperation, EdgeOperation, DeleteNodeOperation, AssocEdge, AssocEdgeInputOptions, AssocEdgeInput, AssocEdgeData, loadEdgeData, loadEdgeDatas, loadEdges, loadUniqueEdge, loadUniqueNode, loadRawEdgeCountX, loadEdgeForID2, loadNodesByEdge, getEdgeTypeInGroup, setGlobalSchema, } from "./core/ent";
|
|
3
3
|
import DB from "./core/db";
|
|
4
4
|
export * from "./core/loaders";
|
|
5
5
|
export { DB };
|
package/index.js
CHANGED
|
@@ -25,8 +25,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
25
25
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
26
26
|
};
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.
|
|
29
|
-
exports.setLogLevels = exports.loadConfig = exports.LoggedOutViewer = exports.IDViewer = exports.ContextCache = exports.query = exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AllowIfSubPolicyAllowsRule = exports.AllowIfConditionAppliesRule = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = exports.applyPrivacyPolicyX = exports.applyPrivacyPolicy = exports.DelayedResultRule = exports.DenyIfEntIsVisiblePolicy = exports.AllowIfEntIsVisiblePolicy = exports.DenyIfEntIsNotVisibleRule = exports.DenyIfEntIsVisibleRule = exports.AllowIfEntIsNotVisibleRule = exports.AllowIfEntIsVisibleRule = exports.DenyIfViewerOutboundEdgeDoesNotExistRule = void 0;
|
|
28
|
+
exports.DenyIfEdgeDoesNotExistRule = exports.DenyIfViewerOutboundEdgeExistsRule = exports.DenyIfViewerInboundEdgeExistsRule = exports.DenyIfEdgeExistsRule = exports.AllowIfViewerOutboundEdgeExistsRule = exports.AllowIfViewerInboundEdgeExistsRule = exports.AllowIfEdgeExistsRule = exports.DenyIfViewerEqualsRule = exports.AllowIfViewerEqualsRule = exports.DenyIfEntPropertyIsRule = exports.AllowIfEntPropertyIsRule = exports.AllowIfViewerIsEntPropertyRule = exports.AllowIfViewerIsRule = exports.AllowIfFuncRule = exports.AllowIfViewerRule = exports.AllowIfHasIdentity = exports.DenyIfLoggedOutRule = exports.DenyIfLoggedInRule = exports.AlwaysDenyRule = exports.AlwaysAllowRule = exports.EntPrivacyError = exports.DB = exports.setGlobalSchema = exports.getEdgeTypeInGroup = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadEdges = exports.loadEdgeDatas = exports.loadEdgeData = exports.AssocEdgeData = exports.AssocEdge = exports.DeleteNodeOperation = exports.EdgeOperation = exports.EditNodeOperation = exports.loadRows = exports.loadRow = exports.loadRowX = exports.performRawQuery = exports.loadEntXViaKey = exports.loadEntViaKey = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadEnts = exports.loadEntX = exports.loadCustomEnts = exports.loadCustomData = exports.loadEnt = void 0;
|
|
29
|
+
exports.setLogLevels = exports.loadConfig = exports.LoggedOutViewer = exports.IDViewer = exports.ContextCache = exports.query = exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AllowIfSubPolicyAllowsRule = exports.AllowIfConditionAppliesRule = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = exports.applyPrivacyPolicyX = exports.applyPrivacyPolicy = exports.DelayedResultRule = exports.DenyIfEntIsVisiblePolicy = exports.AllowIfEntIsVisiblePolicy = exports.DenyIfEntIsNotVisibleRule = exports.DenyIfEntIsVisibleRule = exports.AllowIfEntIsNotVisibleRule = exports.AllowIfEntIsVisibleRule = exports.DenyIfViewerOutboundEdgeDoesNotExistRule = exports.DenyIfViewerInboundEdgeDoesNotExistRule = void 0;
|
|
30
30
|
__exportStar(require("./core/base"), exports);
|
|
31
31
|
var ent_1 = require("./core/ent");
|
|
32
32
|
Object.defineProperty(exports, "loadEnt", { enumerable: true, get: function () { return ent_1.loadEnt; } });
|
|
@@ -57,6 +57,7 @@ Object.defineProperty(exports, "loadRawEdgeCountX", { enumerable: true, get: fun
|
|
|
57
57
|
Object.defineProperty(exports, "loadEdgeForID2", { enumerable: true, get: function () { return ent_1.loadEdgeForID2; } });
|
|
58
58
|
Object.defineProperty(exports, "loadNodesByEdge", { enumerable: true, get: function () { return ent_1.loadNodesByEdge; } });
|
|
59
59
|
Object.defineProperty(exports, "getEdgeTypeInGroup", { enumerable: true, get: function () { return ent_1.getEdgeTypeInGroup; } });
|
|
60
|
+
Object.defineProperty(exports, "setGlobalSchema", { enumerable: true, get: function () { return ent_1.setGlobalSchema; } });
|
|
60
61
|
const db_1 = __importDefault(require("./core/db"));
|
|
61
62
|
exports.DB = db_1.default;
|
|
62
63
|
__exportStar(require("./core/loaders"), exports);
|
package/package.json
CHANGED
package/parse_schema/parse.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Schema, Field, AssocEdge, AssocEdgeGroup, Action } from "../schema";
|
|
2
|
-
import { ActionField, Type } from "../schema/schema";
|
|
2
|
+
import { ActionField, Type, GlobalSchema } from "../schema/schema";
|
|
3
3
|
declare enum NullableResult {
|
|
4
4
|
CONTENTS = "contents",
|
|
5
5
|
CONTENTS_AND_LIST = "contentsAndList",
|
|
@@ -61,9 +61,15 @@ interface patternsDict {
|
|
|
61
61
|
interface Result {
|
|
62
62
|
schemas: schemasDict;
|
|
63
63
|
patterns: patternsDict;
|
|
64
|
+
globalSchema?: ProcessedGlobalSchema;
|
|
64
65
|
}
|
|
65
66
|
declare type PotentialSchemas = {
|
|
66
67
|
[key: string]: any;
|
|
67
68
|
};
|
|
68
|
-
export declare function parseSchema(potentialSchemas: PotentialSchemas): Result;
|
|
69
|
+
export declare function parseSchema(potentialSchemas: PotentialSchemas, globalSchema?: GlobalSchema): Result;
|
|
70
|
+
interface ProcessedGlobalSchema {
|
|
71
|
+
globalEdges: ProcessedAssocEdge[];
|
|
72
|
+
extraEdgeFields: ProcessedField[];
|
|
73
|
+
initForEdges?: boolean;
|
|
74
|
+
}
|
|
69
75
|
export {};
|
package/parse_schema/parse.js
CHANGED
|
@@ -172,9 +172,13 @@ function processAction(action) {
|
|
|
172
172
|
ret.actionOnlyFields = actionOnlyFields;
|
|
173
173
|
return ret;
|
|
174
174
|
}
|
|
175
|
-
function parseSchema(potentialSchemas) {
|
|
175
|
+
function parseSchema(potentialSchemas, globalSchema) {
|
|
176
176
|
let schemas = {};
|
|
177
177
|
let patterns = {};
|
|
178
|
+
let parsedGlobalSchema;
|
|
179
|
+
if (globalSchema) {
|
|
180
|
+
parsedGlobalSchema = parseGlobalSchema(globalSchema);
|
|
181
|
+
}
|
|
178
182
|
for (const key in potentialSchemas) {
|
|
179
183
|
const value = potentialSchemas[key];
|
|
180
184
|
let schema;
|
|
@@ -234,6 +238,22 @@ function parseSchema(potentialSchemas) {
|
|
|
234
238
|
}
|
|
235
239
|
schemas[key] = processedSchema;
|
|
236
240
|
}
|
|
237
|
-
return { schemas, patterns };
|
|
241
|
+
return { schemas, patterns, globalSchema: parsedGlobalSchema };
|
|
238
242
|
}
|
|
239
243
|
exports.parseSchema = parseSchema;
|
|
244
|
+
function parseGlobalSchema(s) {
|
|
245
|
+
const ret = {
|
|
246
|
+
globalEdges: [],
|
|
247
|
+
extraEdgeFields: [],
|
|
248
|
+
initForEdges: !!s.extraEdgeFields ||
|
|
249
|
+
s.transformEdgeRead !== undefined ||
|
|
250
|
+
s.transformEdgeWrite !== undefined,
|
|
251
|
+
};
|
|
252
|
+
if (s.extraEdgeFields) {
|
|
253
|
+
ret.extraEdgeFields = processFields(s.extraEdgeFields);
|
|
254
|
+
}
|
|
255
|
+
if (s.edges) {
|
|
256
|
+
ret.globalEdges = processEdges(s.edges);
|
|
257
|
+
}
|
|
258
|
+
return ret;
|
|
259
|
+
}
|
package/schema/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Schema from "./schema";
|
|
2
2
|
export { Schema };
|
|
3
|
-
export { Field, AssocEdge, AssocEdgeGroup, InverseAssocEdge, Edge, Pattern, DBType, Type, FieldOptions, SchemaConstructor, SchemaInputType, getFields, getFieldsWithPrivacy, getStorageKey, ActionOperation, Action, EdgeAction, NoFields, FieldMap, Constraint, Index, ConstraintType, ForeignKeyInfo, requiredField, optionalField, UpdateOperation, TransformedUpdateOperation, SQLStatementOperation, getTransformedReadClause, getObjectLoaderProperties, } from "./schema";
|
|
3
|
+
export { Field, AssocEdge, AssocEdgeGroup, InverseAssocEdge, Edge, Pattern, DBType, Type, FieldOptions, SchemaConstructor, SchemaInputType, getFields, getFieldsWithPrivacy, getStorageKey, ActionOperation, Action, EdgeAction, NoFields, FieldMap, Constraint, Index, ConstraintType, ForeignKeyInfo, requiredField, optionalField, UpdateOperation, TransformedUpdateOperation, SQLStatementOperation, EdgeUpdateOperation, TransformedEdgeUpdateOperation, getTransformedReadClause, getObjectLoaderProperties, GlobalSchema, } from "./schema";
|
|
4
4
|
export { Timestamps, Node, BaseEntSchema, BaseEntSchemaWithTZ, EntSchema, EntSchemaWithTZ, SchemaConfig, } from "./base_schema";
|
|
5
5
|
export * from "./field";
|
|
6
6
|
export * from "./json_field";
|
package/schema/schema.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Data, Ent, LoaderInfo, PrivacyPolicy, Viewer } from "../core/base";
|
|
2
2
|
import { Builder } from "../action/action";
|
|
3
3
|
import { Clause } from "../core/clause";
|
|
4
|
+
import { AssocEdgeInput } from "../core/ent";
|
|
4
5
|
export declare type FieldMap = {
|
|
5
6
|
[key: string]: Field;
|
|
6
7
|
};
|
|
@@ -11,6 +12,12 @@ interface FieldInfo {
|
|
|
11
12
|
export declare type FieldInfoMap = {
|
|
12
13
|
[key: string]: FieldInfo;
|
|
13
14
|
};
|
|
15
|
+
export interface GlobalSchema {
|
|
16
|
+
edges?: Edge[];
|
|
17
|
+
extraEdgeFields?: FieldMap;
|
|
18
|
+
transformEdgeRead?: () => Clause;
|
|
19
|
+
transformEdgeWrite?: (stmt: EdgeUpdateOperation) => TransformedEdgeUpdateOperation | null;
|
|
20
|
+
}
|
|
14
21
|
export default interface Schema {
|
|
15
22
|
fields: FieldMap | Field[];
|
|
16
23
|
tableName?: string;
|
|
@@ -82,6 +89,14 @@ export declare enum SQLStatementOperation {
|
|
|
82
89
|
Update = "update",
|
|
83
90
|
Delete = "delete"
|
|
84
91
|
}
|
|
92
|
+
export interface EdgeUpdateOperation {
|
|
93
|
+
op: SQLStatementOperation;
|
|
94
|
+
edge: AssocEdgeInput;
|
|
95
|
+
}
|
|
96
|
+
export interface TransformedEdgeUpdateOperation {
|
|
97
|
+
op: SQLStatementOperation;
|
|
98
|
+
data?: Data;
|
|
99
|
+
}
|
|
85
100
|
export interface UpdateOperation<TEnt extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
|
|
86
101
|
op: SQLStatementOperation;
|
|
87
102
|
builder: Builder<TEnt, TViewer>;
|
|
@@ -239,7 +239,7 @@ async function main() {
|
|
|
239
239
|
// for go tests...
|
|
240
240
|
// TODO need a flag that only does this for go tests
|
|
241
241
|
// breaks when running locally sometimes...
|
|
242
|
-
|
|
242
|
+
secondaryImportPath: "../graphql/scalars/time",
|
|
243
243
|
type: "GraphQLTime",
|
|
244
244
|
});
|
|
245
245
|
(0, graphql_1.addCustomType)({
|
package/scripts/read_schema.js
CHANGED
|
@@ -28,18 +28,27 @@ const pascal_case_1 = require("pascal-case");
|
|
|
28
28
|
const minimist_1 = __importDefault(require("minimist"));
|
|
29
29
|
const process_1 = require("process");
|
|
30
30
|
const parse_1 = require("../parse_schema/parse");
|
|
31
|
+
const ast_1 = require("../tsc/ast");
|
|
31
32
|
function main() {
|
|
32
33
|
const options = (0, minimist_1.default)(process.argv.slice(2));
|
|
33
34
|
if (!options.path) {
|
|
34
35
|
throw new Error("path required");
|
|
35
36
|
}
|
|
37
|
+
const customInfo = (0, ast_1.getCustomInfo)();
|
|
38
|
+
const globalSchemaPath = customInfo.globalSchemaPath || "__global__schema.ts";
|
|
39
|
+
let globalSchema;
|
|
36
40
|
const r = /(\w+).ts/;
|
|
41
|
+
// do we still even need this...
|
|
37
42
|
const paths = glob_1.default.sync(path.join(options.path, "*.ts"), {
|
|
38
43
|
ignore: [`\d+_read_schema.ts`],
|
|
39
44
|
});
|
|
40
45
|
let potentialSchemas = {};
|
|
41
46
|
for (const p of paths) {
|
|
42
47
|
const basename = path.basename(p);
|
|
48
|
+
if (basename === globalSchemaPath) {
|
|
49
|
+
globalSchema = require(p).default;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
43
52
|
const match = r.exec(basename);
|
|
44
53
|
if (!match) {
|
|
45
54
|
throw new Error(`non-typescript file ${p} returned by glob`);
|
|
@@ -61,7 +70,7 @@ function main() {
|
|
|
61
70
|
potentialSchemas[(0, pascal_case_1.pascalCase)(schema)] = s;
|
|
62
71
|
}
|
|
63
72
|
// console.log(potentialSchemas);
|
|
64
|
-
const result = (0, parse_1.parseSchema)(potentialSchemas);
|
|
73
|
+
const result = (0, parse_1.parseSchema)(potentialSchemas, globalSchema);
|
|
65
74
|
console.log(JSON.stringify(result));
|
|
66
75
|
}
|
|
67
76
|
try {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Client as PGClient } from "pg";
|
|
2
2
|
import { Dialect } from "../../core/db";
|
|
3
3
|
import { Database as SqliteDatabase } from "better-sqlite3";
|
|
4
|
+
import { Field } from "../../schema";
|
|
4
5
|
import { BuilderSchema } from "../builder";
|
|
5
6
|
import { Ent } from "../../core/base";
|
|
6
7
|
interface SchemaItem {
|
|
@@ -91,10 +92,11 @@ export declare class TempDB {
|
|
|
91
92
|
create(...tables: CoreConcept[]): Promise<void>;
|
|
92
93
|
}
|
|
93
94
|
export declare function assoc_edge_config_table(): Table;
|
|
94
|
-
export declare function assoc_edge_table(name: string): Table;
|
|
95
|
+
export declare function assoc_edge_table(name: string, global?: boolean): Table;
|
|
95
96
|
interface sqliteSetupOptions {
|
|
96
97
|
disableDeleteAfterEachTest?: boolean;
|
|
97
98
|
}
|
|
98
|
-
export declare function setupSqlite(connString: string, tables: () => Table[], opts?: sqliteSetupOptions):
|
|
99
|
+
export declare function setupSqlite(connString: string, tables: () => Table[], opts?: sqliteSetupOptions): TempDB;
|
|
99
100
|
export declare function getSchemaTable(schema: BuilderSchema<Ent>, dialect: Dialect): Table;
|
|
101
|
+
export declare function getColumnFromField(fieldName: string, f: Field, dialect: Dialect): Column;
|
|
100
102
|
export {};
|
|
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.getSchemaTable = exports.setupSqlite = exports.assoc_edge_table = exports.assoc_edge_config_table = exports.TempDB = exports.enumType = exports.table = exports.boolList = exports.dateList = exports.timetzList = exports.timeList = exports.timestamptzList = exports.timestampList = exports.uuidList = exports.integerList = exports.textList = exports.jsonb = exports.json = exports.float = exports.integer = exports.bool = exports.date = exports.timetz = exports.time = exports.timestamptz = exports.timestamp = exports.enumCol = exports.text = exports.uuid = exports.uniqueIndex = exports.index = exports.foreignKey = exports.primaryKey = void 0;
|
|
25
|
+
exports.getColumnFromField = exports.getSchemaTable = exports.setupSqlite = exports.assoc_edge_table = exports.assoc_edge_config_table = exports.TempDB = exports.enumType = exports.table = exports.boolList = exports.dateList = exports.timetzList = exports.timeList = exports.timestamptzList = exports.timestampList = exports.uuidList = exports.integerList = exports.textList = exports.jsonb = exports.json = exports.float = exports.integer = exports.bool = exports.date = exports.timetz = exports.time = exports.timestamptz = exports.timestamp = exports.enumCol = exports.text = exports.uuid = exports.uniqueIndex = exports.index = exports.foreignKey = exports.primaryKey = void 0;
|
|
26
26
|
const pg_1 = require("pg");
|
|
27
27
|
const db_1 = __importStar(require("../../core/db"));
|
|
28
28
|
// this should only be used in tests so we expect to be able to import without shenanigans
|
|
@@ -32,6 +32,7 @@ const fs = __importStar(require("fs"));
|
|
|
32
32
|
const schema_1 = require("../../schema");
|
|
33
33
|
const snake_case_1 = require("snake-case");
|
|
34
34
|
const builder_1 = require("../builder");
|
|
35
|
+
const test_edge_global_schema_1 = require("../test_edge_global_schema");
|
|
35
36
|
function primaryKey(name, cols) {
|
|
36
37
|
return {
|
|
37
38
|
name: name,
|
|
@@ -484,18 +485,26 @@ function assoc_edge_config_table() {
|
|
|
484
485
|
text("edge_type", { primaryKey: true }), text("edge_name"), bool("symmetric_edge", { default: "FALSE" }), text("inverse_edge_type", { nullable: true }), text("edge_table"), timestamptz("created_at"), timestamptz("updated_at"));
|
|
485
486
|
}
|
|
486
487
|
exports.assoc_edge_config_table = assoc_edge_config_table;
|
|
487
|
-
|
|
488
|
-
|
|
488
|
+
// if global flag is true, add any column from testEdgeGlobalSchema
|
|
489
|
+
// up to caller to set/clear that as needed
|
|
490
|
+
function assoc_edge_table(name, global) {
|
|
491
|
+
const t = table(name, uuid("id1"), text("id1_type"),
|
|
489
492
|
// same as in assoc_edge_config_table
|
|
490
493
|
text("edge_type"), uuid("id2"), text("id2_type"), timestamptz("time"), text("data", { nullable: true }), primaryKey(`${name}_pkey`, ["id1", "id2", "edge_type"]));
|
|
494
|
+
if (global) {
|
|
495
|
+
for (const k in test_edge_global_schema_1.testEdgeGlobalSchema.extraEdgeFields) {
|
|
496
|
+
const col = getColumnFromField(k, test_edge_global_schema_1.testEdgeGlobalSchema.extraEdgeFields[k], db_1.Dialect.Postgres);
|
|
497
|
+
t.columns.push(col);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return t;
|
|
491
501
|
}
|
|
492
502
|
exports.assoc_edge_table = assoc_edge_table;
|
|
493
503
|
function setupSqlite(connString, tables, opts) {
|
|
494
|
-
let tdb;
|
|
504
|
+
let tdb = new TempDB(db_1.Dialect.SQLite, tables());
|
|
495
505
|
beforeAll(async () => {
|
|
496
506
|
process.env.DB_CONNECTION_STRING = connString;
|
|
497
507
|
(0, config_1.loadConfig)();
|
|
498
|
-
tdb = new TempDB(db_1.Dialect.SQLite, tables());
|
|
499
508
|
await tdb.beforeAll();
|
|
500
509
|
const conn = db_1.default.getInstance().getConnection();
|
|
501
510
|
expect(conn.db.memory).toBe(false);
|
|
@@ -519,6 +528,7 @@ function setupSqlite(connString, tables, opts) {
|
|
|
519
528
|
await tdb.afterAll();
|
|
520
529
|
fs.rmSync(tdb.getSqliteClient().name);
|
|
521
530
|
});
|
|
531
|
+
return tdb;
|
|
522
532
|
}
|
|
523
533
|
exports.setupSqlite = setupSqlite;
|
|
524
534
|
function getSchemaTable(schema, dialect) {
|
|
@@ -585,6 +595,7 @@ function getColumnFromField(fieldName, f, dialect) {
|
|
|
585
595
|
return getColumn(fieldName, f, fn);
|
|
586
596
|
}
|
|
587
597
|
}
|
|
598
|
+
exports.getColumnFromField = getColumnFromField;
|
|
588
599
|
function getColumn(fieldName, f, col) {
|
|
589
600
|
return col(storageKey(fieldName, f), buildOpts(f));
|
|
590
601
|
}
|
|
@@ -16,7 +16,7 @@ export declare class FakeContact implements Ent {
|
|
|
16
16
|
getPrivacyPolicy(): PrivacyPolicy<this>;
|
|
17
17
|
constructor(viewer: Viewer, data: Data);
|
|
18
18
|
static getFields(): string[];
|
|
19
|
-
static getTestTable(): import("../db/
|
|
19
|
+
static getTestTable(): import("../db/temp_db").Table;
|
|
20
20
|
static loaderOptions(): LoadEntOptions<FakeContact>;
|
|
21
21
|
static load(v: Viewer, id: ID): Promise<FakeContact | null>;
|
|
22
22
|
static loadX(v: Viewer, id: ID): Promise<FakeContact>;
|
|
@@ -6,7 +6,7 @@ const privacy_1 = require("../../core/privacy");
|
|
|
6
6
|
const builder_1 = require("../builder");
|
|
7
7
|
const schema_1 = require("../../schema");
|
|
8
8
|
const const_1 = require("./const");
|
|
9
|
-
const
|
|
9
|
+
const temp_db_1 = require("../db/temp_db");
|
|
10
10
|
const loaders_1 = require("../../core/loaders");
|
|
11
11
|
const convert_1 = require("../../core/convert");
|
|
12
12
|
const action_1 = require("../../action");
|
|
@@ -40,7 +40,7 @@ class FakeContact {
|
|
|
40
40
|
];
|
|
41
41
|
}
|
|
42
42
|
static getTestTable() {
|
|
43
|
-
return (0,
|
|
43
|
+
return (0, temp_db_1.table)("fake_contacts", (0, temp_db_1.uuid)("id", { primaryKey: true }), (0, temp_db_1.timestamptz)("created_at"), (0, temp_db_1.timestamptz)("updated_at"), (0, temp_db_1.text)("first_name"), (0, temp_db_1.text)("last_name"), (0, temp_db_1.text)("email_address"), (0, temp_db_1.uuid)("user_id"));
|
|
44
44
|
}
|
|
45
45
|
static loaderOptions() {
|
|
46
46
|
return {
|
|
@@ -17,7 +17,7 @@ export declare class FakeEvent implements Ent {
|
|
|
17
17
|
getPrivacyPolicy(): PrivacyPolicy<this>;
|
|
18
18
|
constructor(viewer: Viewer, data: Data);
|
|
19
19
|
private static getFields;
|
|
20
|
-
static getTestTable(): import("../db/
|
|
20
|
+
static getTestTable(): import("../db/temp_db").Table;
|
|
21
21
|
static loaderOptions(): LoadEntOptions<FakeEvent>;
|
|
22
22
|
static load(v: Viewer, id: ID): Promise<FakeEvent | null>;
|
|
23
23
|
static loadX(v: Viewer, id: ID): Promise<FakeEvent>;
|
|
@@ -6,7 +6,7 @@ const privacy_1 = require("../../core/privacy");
|
|
|
6
6
|
const builder_1 = require("../builder");
|
|
7
7
|
const schema_1 = require("../../schema");
|
|
8
8
|
const const_1 = require("./const");
|
|
9
|
-
const
|
|
9
|
+
const temp_db_1 = require("../db/temp_db");
|
|
10
10
|
const loaders_1 = require("../../core/loaders");
|
|
11
11
|
const convert_1 = require("../../core/convert");
|
|
12
12
|
const action_1 = require("../../action");
|
|
@@ -42,9 +42,9 @@ class FakeEvent {
|
|
|
42
42
|
];
|
|
43
43
|
}
|
|
44
44
|
static getTestTable() {
|
|
45
|
-
return (0,
|
|
45
|
+
return (0, temp_db_1.table)("fake_events", (0, temp_db_1.uuid)("id", { primaryKey: true }), (0, temp_db_1.timestamptz)("created_at"), (0, temp_db_1.timestamptz)("updated_at"),
|
|
46
46
|
// TODO index:true
|
|
47
|
-
(0,
|
|
47
|
+
(0, temp_db_1.timestamptz)("start_time"), (0, temp_db_1.timestamptz)("end_time", { nullable: true }), (0, temp_db_1.text)("location"), (0, temp_db_1.text)("title"), (0, temp_db_1.text)("description", { nullable: true }), (0, temp_db_1.uuid)("user_id"));
|
|
48
48
|
}
|
|
49
49
|
static loaderOptions() {
|
|
50
50
|
return {
|
|
@@ -26,7 +26,7 @@ export declare class FakeUser implements Ent {
|
|
|
26
26
|
getPrivacyPolicy(): PrivacyPolicy<this>;
|
|
27
27
|
constructor(viewer: Viewer, data: Data);
|
|
28
28
|
static getFields(): string[];
|
|
29
|
-
static getTestTable(): import("../db/
|
|
29
|
+
static getTestTable(): import("../db/temp_db").Table;
|
|
30
30
|
static loaderOptions(): LoadEntOptions<FakeUser>;
|
|
31
31
|
static load(v: Viewer, id: ID): Promise<FakeUser | null>;
|
|
32
32
|
static loadX(v: Viewer, id: ID): Promise<FakeUser>;
|
|
@@ -8,7 +8,7 @@ const schema_1 = require("../../schema");
|
|
|
8
8
|
const internal_1 = require("./internal");
|
|
9
9
|
const const_1 = require("./const");
|
|
10
10
|
const viewer_1 = require("../../core/viewer");
|
|
11
|
-
const
|
|
11
|
+
const temp_db_1 = require("../db/temp_db");
|
|
12
12
|
const loaders_1 = require("../../core/loaders");
|
|
13
13
|
const convert_1 = require("../../core/convert");
|
|
14
14
|
const action_1 = require("../../action");
|
|
@@ -74,7 +74,7 @@ class FakeUser {
|
|
|
74
74
|
];
|
|
75
75
|
}
|
|
76
76
|
static getTestTable() {
|
|
77
|
-
return (0,
|
|
77
|
+
return (0, temp_db_1.table)("fake_users", (0, temp_db_1.uuid)("id", { primaryKey: true }), (0, temp_db_1.timestamptz)("created_at"), (0, temp_db_1.timestamptz)("updated_at"), (0, temp_db_1.text)("first_name"), (0, temp_db_1.text)("last_name"), (0, temp_db_1.text)("email_address"), (0, temp_db_1.text)("phone_number"), (0, temp_db_1.text)("password"));
|
|
78
78
|
}
|
|
79
79
|
static loaderOptions() {
|
|
80
80
|
return {
|