@snowtop/ent 0.1.0-alpha99 → 0.1.0
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/action.d.ts +8 -1
- package/action/executor.d.ts +16 -3
- package/action/executor.js +83 -27
- package/action/index.d.ts +2 -1
- package/action/operations.d.ts +126 -0
- package/action/operations.js +686 -0
- package/action/orchestrator.d.ts +22 -8
- package/action/orchestrator.js +278 -67
- package/core/base.d.ts +34 -24
- package/core/clause.d.ts +62 -79
- package/core/clause.js +77 -5
- package/core/config.d.ts +5 -1
- package/core/config.js +3 -0
- package/core/const.d.ts +3 -0
- package/core/const.js +6 -0
- package/core/context.d.ts +4 -3
- package/core/context.js +2 -1
- package/core/db.d.ts +1 -0
- package/core/db.js +7 -7
- package/core/ent.d.ts +53 -105
- package/core/ent.js +104 -599
- package/core/global_schema.d.ts +7 -0
- package/core/global_schema.js +51 -0
- package/core/loaders/assoc_count_loader.d.ts +4 -2
- package/core/loaders/assoc_count_loader.js +10 -2
- package/core/loaders/assoc_edge_loader.d.ts +2 -3
- package/core/loaders/assoc_edge_loader.js +16 -7
- package/core/loaders/index.d.ts +0 -1
- package/core/loaders/index.js +1 -3
- package/core/loaders/loader.d.ts +3 -3
- package/core/loaders/loader.js +3 -20
- package/core/loaders/object_loader.d.ts +30 -10
- package/core/loaders/object_loader.js +179 -40
- package/core/loaders/query_loader.d.ts +4 -4
- package/core/loaders/query_loader.js +14 -19
- package/core/loaders/raw_count_loader.d.ts +1 -0
- package/core/loaders/raw_count_loader.js +3 -2
- package/core/privacy.d.ts +19 -10
- package/core/privacy.js +47 -26
- package/core/query/assoc_query.js +1 -1
- package/core/query/custom_clause_query.d.ts +6 -3
- package/core/query/custom_clause_query.js +36 -9
- package/core/query/custom_query.d.ts +3 -1
- package/core/query/custom_query.js +29 -6
- package/core/query/query.d.ts +12 -2
- package/core/query/query.js +67 -38
- package/core/query/shared_assoc_test.js +151 -10
- package/core/query/shared_test.d.ts +2 -2
- package/core/query/shared_test.js +90 -30
- package/core/query_impl.d.ts +8 -0
- package/core/query_impl.js +28 -0
- package/core/viewer.d.ts +2 -0
- package/core/viewer.js +2 -0
- package/graphql/graphql.d.ts +103 -19
- package/graphql/graphql.js +169 -134
- package/graphql/graphql_field_helpers.d.ts +9 -3
- package/graphql/graphql_field_helpers.js +22 -2
- package/graphql/index.d.ts +2 -1
- package/graphql/index.js +5 -2
- package/graphql/scalars/orderby_direction.d.ts +2 -0
- package/graphql/scalars/orderby_direction.js +15 -0
- package/imports/dataz/example1/_auth.js +128 -47
- package/imports/dataz/example1/_viewer.js +87 -39
- package/imports/index.d.ts +1 -1
- package/imports/index.js +2 -2
- package/index.d.ts +12 -1
- package/index.js +18 -6
- package/package.json +20 -17
- package/parse_schema/parse.d.ts +10 -4
- package/parse_schema/parse.js +70 -24
- package/schema/base_schema.d.ts +8 -0
- package/schema/base_schema.js +11 -0
- package/schema/field.d.ts +6 -3
- package/schema/field.js +72 -17
- package/schema/index.d.ts +1 -1
- package/schema/index.js +2 -1
- package/schema/json_field.d.ts +3 -3
- package/schema/json_field.js +4 -1
- package/schema/schema.d.ts +42 -5
- package/schema/schema.js +35 -41
- package/schema/struct_field.d.ts +8 -6
- package/schema/struct_field.js +67 -8
- package/schema/union_field.d.ts +1 -1
- package/scripts/custom_compiler.js +4 -4
- package/scripts/custom_graphql.js +105 -75
- package/scripts/move_types.js +4 -1
- package/scripts/read_schema.js +2 -2
- package/testutils/action/complex_schemas.d.ts +1 -1
- package/testutils/action/complex_schemas.js +10 -3
- package/testutils/builder.d.ts +3 -0
- package/testutils/builder.js +6 -0
- package/testutils/db/temp_db.d.ts +9 -1
- package/testutils/db/temp_db.js +82 -14
- package/testutils/db_mock.js +1 -3
- package/testutils/ent-graphql-tests/index.d.ts +1 -1
- package/testutils/ent-graphql-tests/index.js +30 -19
- package/testutils/fake_comms.js +1 -1
- package/testutils/fake_data/fake_contact.d.ts +1 -1
- package/testutils/fake_data/fake_tag.d.ts +1 -1
- package/testutils/fake_data/fake_user.d.ts +3 -3
- package/testutils/fake_data/fake_user.js +15 -4
- package/testutils/fake_data/tag_query.js +8 -3
- package/testutils/fake_data/test_helpers.d.ts +3 -2
- package/testutils/fake_data/test_helpers.js +4 -4
- package/testutils/fake_data/user_query.d.ts +5 -2
- package/testutils/fake_data/user_query.js +19 -2
- package/testutils/fake_log.js +1 -1
- package/tsc/ast.js +2 -1
- package/tsc/move_generated.js +2 -2
- package/tsc/transform.d.ts +2 -2
- package/tsc/transform.js +4 -3
- package/tsc/transform_ent.js +2 -1
- package/tsc/transform_schema.js +4 -3
- package/core/loaders/index_loader.d.ts +0 -14
- package/core/loaders/index_loader.js +0 -27
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.ConditionalNodeOperation = exports.ConditionalOperation = exports.EdgeOperation = exports.EditNodeOperation = exports.RawQueryOperation = exports.DeleteNodeOperation = void 0;
|
|
27
|
+
const clause = __importStar(require("../core/clause"));
|
|
28
|
+
const action_1 = require("../action");
|
|
29
|
+
const schema_1 = require("../schema/schema");
|
|
30
|
+
const global_schema_1 = require("../core/global_schema");
|
|
31
|
+
const ent_1 = require("../core/ent");
|
|
32
|
+
class DeleteNodeOperation {
|
|
33
|
+
constructor(id, builder, options) {
|
|
34
|
+
this.id = id;
|
|
35
|
+
this.builder = builder;
|
|
36
|
+
this.options = options;
|
|
37
|
+
}
|
|
38
|
+
async performWrite(queryer, context) {
|
|
39
|
+
let options = {
|
|
40
|
+
...this.options,
|
|
41
|
+
context,
|
|
42
|
+
};
|
|
43
|
+
return (0, ent_1.deleteRows)(queryer, options, clause.Eq("id", this.id));
|
|
44
|
+
}
|
|
45
|
+
performWriteSync(queryer, context) {
|
|
46
|
+
let options = {
|
|
47
|
+
...this.options,
|
|
48
|
+
context,
|
|
49
|
+
};
|
|
50
|
+
return (0, ent_1.deleteRowsSync)(queryer, options, clause.Eq("id", this.id));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.DeleteNodeOperation = DeleteNodeOperation;
|
|
54
|
+
class RawQueryOperation {
|
|
55
|
+
constructor(builder, queries) {
|
|
56
|
+
this.builder = builder;
|
|
57
|
+
this.queries = queries;
|
|
58
|
+
}
|
|
59
|
+
async performWrite(queryer, context) {
|
|
60
|
+
for (const q of this.queries) {
|
|
61
|
+
if (typeof q === "string") {
|
|
62
|
+
(0, ent_1.logQuery)(q, []);
|
|
63
|
+
await queryer.query(q);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
(0, ent_1.logQuery)(q.query, q.logValues || []);
|
|
67
|
+
await queryer.query(q.query, q.values);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
performWriteSync(queryer, context) {
|
|
72
|
+
for (const q of this.queries) {
|
|
73
|
+
if (typeof q === "string") {
|
|
74
|
+
(0, ent_1.logQuery)(q, []);
|
|
75
|
+
queryer.execSync(q);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
(0, ent_1.logQuery)(q.query, q.logValues || []);
|
|
79
|
+
queryer.execSync(q.query, q.values);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.RawQueryOperation = RawQueryOperation;
|
|
85
|
+
class EditNodeOperation {
|
|
86
|
+
constructor(options, existingEnt = null) {
|
|
87
|
+
this.options = options;
|
|
88
|
+
this.existingEnt = existingEnt;
|
|
89
|
+
this.row = null;
|
|
90
|
+
this.updatedOp = null;
|
|
91
|
+
this.resolved = false;
|
|
92
|
+
this.builder = options.builder;
|
|
93
|
+
this.placeholderID = options.builder.placeholderID;
|
|
94
|
+
}
|
|
95
|
+
resolve(executor) {
|
|
96
|
+
if (!this.options.fieldsToResolve.length) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (this.resolved) {
|
|
100
|
+
throw new Error(`already resolved ${this.placeholderID}`);
|
|
101
|
+
}
|
|
102
|
+
let fields = this.options.fields;
|
|
103
|
+
this.options.fieldsToResolve.forEach((fieldName) => {
|
|
104
|
+
let value = fields[fieldName];
|
|
105
|
+
if (!value) {
|
|
106
|
+
throw new Error(`trying to resolve field ${fieldName} but not a valid field`);
|
|
107
|
+
}
|
|
108
|
+
let ent = executor.resolveValue(value.placeholderID);
|
|
109
|
+
if (!ent) {
|
|
110
|
+
throw new Error(`couldn't resolve field \`${fieldName}\` with value ${value.placeholderID}`);
|
|
111
|
+
}
|
|
112
|
+
fields[fieldName] = ent.id;
|
|
113
|
+
});
|
|
114
|
+
this.options.fields = fields;
|
|
115
|
+
this.resolved = true;
|
|
116
|
+
}
|
|
117
|
+
hasData(data) {
|
|
118
|
+
for (const _k in data) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
buildOnConflictQuery(options) {
|
|
124
|
+
// assumes onConflict has been checked already...
|
|
125
|
+
const clauses = [];
|
|
126
|
+
for (const col of this.options.onConflict.onConflictCols) {
|
|
127
|
+
clauses.push(clause.Eq(col, options.fields[col]));
|
|
128
|
+
}
|
|
129
|
+
const cls = clause.AndOptional(...clauses);
|
|
130
|
+
const query = this.buildReloadQuery(options, cls);
|
|
131
|
+
return { cls, query };
|
|
132
|
+
}
|
|
133
|
+
async performWrite(queryer, context) {
|
|
134
|
+
let options = {
|
|
135
|
+
...this.options,
|
|
136
|
+
context,
|
|
137
|
+
};
|
|
138
|
+
if (this.existingEnt) {
|
|
139
|
+
if (this.hasData(options.fields)) {
|
|
140
|
+
// even this with returning * may not always work if transformed...
|
|
141
|
+
// we can have a transformed flag to see if it should be returned?
|
|
142
|
+
this.row = await (0, ent_1.editRow)(queryer, options, "RETURNING *");
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// @ts-ignore
|
|
146
|
+
this.row = this.existingEnt["data"];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// TODO: eventually, when we officially support auto-increment ids. need to make sure/test that this works
|
|
151
|
+
// https://github.com/lolopinto/ent/issues/1431
|
|
152
|
+
this.row = await (0, ent_1.createRow)(queryer, options, "RETURNING *");
|
|
153
|
+
const key = this.options.key;
|
|
154
|
+
if (this.row && this.row[key] !== this.options.fields[key]) {
|
|
155
|
+
this.updatedOp = {
|
|
156
|
+
builder: this.options.builder,
|
|
157
|
+
operation: action_1.WriteOperation.Edit,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
if (this.row === null &&
|
|
161
|
+
this.options.onConflict &&
|
|
162
|
+
!this.options.onConflict.updateCols?.length) {
|
|
163
|
+
// no row returned and on conflict, do nothing, have to fetch the conflict row back...
|
|
164
|
+
const { cls, query } = this.buildOnConflictQuery(options);
|
|
165
|
+
(0, ent_1.logQuery)(query, cls.logValues());
|
|
166
|
+
const res = await queryer.query(query, cls.values());
|
|
167
|
+
this.row = res.rows[0];
|
|
168
|
+
this.updatedOp = {
|
|
169
|
+
builder: this.options.builder,
|
|
170
|
+
operation: action_1.WriteOperation.Edit,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
buildReloadQuery(options, cls) {
|
|
176
|
+
// TODO this isn't always an ObjectLoader. should throw or figure out a way to get query
|
|
177
|
+
// and run this on its own...
|
|
178
|
+
const loader = this.options.loadEntOptions.loaderFactory.createLoader(options.context);
|
|
179
|
+
const opts = loader.getOptions();
|
|
180
|
+
if (opts.clause) {
|
|
181
|
+
let optionClause;
|
|
182
|
+
if (typeof opts.clause === "function") {
|
|
183
|
+
optionClause = opts.clause();
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
optionClause = opts.clause;
|
|
187
|
+
}
|
|
188
|
+
if (optionClause) {
|
|
189
|
+
cls = clause.And(cls, optionClause);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const query = (0, ent_1.buildQuery)({
|
|
193
|
+
fields: opts.fields.length ? opts.fields : ["*"],
|
|
194
|
+
tableName: options.tableName,
|
|
195
|
+
clause: cls,
|
|
196
|
+
});
|
|
197
|
+
return query;
|
|
198
|
+
}
|
|
199
|
+
reloadRow(queryer, id, options) {
|
|
200
|
+
const query = this.buildReloadQuery(options, clause.Eq(options.key, id));
|
|
201
|
+
// special case log here because we're not going through any of the normal
|
|
202
|
+
// methods here because those are async and this is sync
|
|
203
|
+
// this is the only place we're doing this so only handling here
|
|
204
|
+
(0, ent_1.logQuery)(query, [id]);
|
|
205
|
+
const r = queryer.querySync(query, [id]);
|
|
206
|
+
if (r.rows.length === 1) {
|
|
207
|
+
this.row = r.rows[0];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
performWriteSync(queryer, context) {
|
|
211
|
+
let options = {
|
|
212
|
+
...this.options,
|
|
213
|
+
context,
|
|
214
|
+
};
|
|
215
|
+
if (this.existingEnt) {
|
|
216
|
+
if (this.hasData(this.options.fields)) {
|
|
217
|
+
(0, ent_1.editRowSync)(queryer, options, "RETURNING *");
|
|
218
|
+
this.reloadRow(queryer, this.existingEnt.id, options);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// @ts-ignore
|
|
222
|
+
this.row = this.existingEnt["data"];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
(0, ent_1.createRowSync)(queryer, options, "RETURNING *");
|
|
227
|
+
const id = options.fields[options.key];
|
|
228
|
+
this.reloadRow(queryer, id, options);
|
|
229
|
+
const key = this.options.key;
|
|
230
|
+
if (this.row && this.row[key] !== this.options.fields[key]) {
|
|
231
|
+
this.updatedOp = {
|
|
232
|
+
builder: this.options.builder,
|
|
233
|
+
operation: action_1.WriteOperation.Edit,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
// if we can't find the id, try and load the on conflict row
|
|
237
|
+
// no returning * with sqlite and have to assume the row was created more often than not
|
|
238
|
+
// there's a world in which we combine into one query if on-conflict
|
|
239
|
+
// seems like it's safer not to and sqlite (only sync client we currently have) is fast enough
|
|
240
|
+
// (single-process) that it's fine to do two queries
|
|
241
|
+
// we wanna do this in both on conflict do nothing or on conflict update
|
|
242
|
+
if (this.row === null && this.options.onConflict) {
|
|
243
|
+
const { cls, query } = this.buildOnConflictQuery(options);
|
|
244
|
+
// special case log here because we're not going through any of the normal
|
|
245
|
+
// methods here because those are async and this is sync
|
|
246
|
+
// this is the only place we're doing this so only handling here
|
|
247
|
+
(0, ent_1.logQuery)(query, cls.logValues());
|
|
248
|
+
const r = queryer.querySync(query, cls.values());
|
|
249
|
+
if (r.rows.length === 1) {
|
|
250
|
+
this.row = r.rows[0];
|
|
251
|
+
}
|
|
252
|
+
this.updatedOp = {
|
|
253
|
+
builder: this.options.builder,
|
|
254
|
+
operation: action_1.WriteOperation.Edit,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
returnedRow() {
|
|
260
|
+
return this.row;
|
|
261
|
+
}
|
|
262
|
+
createdEnt(viewer) {
|
|
263
|
+
if (!this.row) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
return new this.options.loadEntOptions.ent(viewer, this.row);
|
|
267
|
+
}
|
|
268
|
+
updatedOperation() {
|
|
269
|
+
return this.updatedOp;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
exports.EditNodeOperation = EditNodeOperation;
|
|
273
|
+
class EdgeOperation {
|
|
274
|
+
constructor(builder, edgeInput, options) {
|
|
275
|
+
this.builder = builder;
|
|
276
|
+
this.edgeInput = edgeInput;
|
|
277
|
+
this.options = options;
|
|
278
|
+
}
|
|
279
|
+
async preFetch(queryer, context) {
|
|
280
|
+
let edgeData = await (0, ent_1.loadEdgeData)(this.edgeInput.edgeType);
|
|
281
|
+
if (!edgeData) {
|
|
282
|
+
throw new Error(`error loading edge data for ${this.edgeInput.edgeType}`);
|
|
283
|
+
}
|
|
284
|
+
this.edgeData = edgeData;
|
|
285
|
+
}
|
|
286
|
+
async performWrite(queryer, context) {
|
|
287
|
+
if (!this.edgeData) {
|
|
288
|
+
throw new Error(`error fetching edgeData for type ${this.edgeInput.edgeType}`);
|
|
289
|
+
}
|
|
290
|
+
switch (this.options.operation) {
|
|
291
|
+
case action_1.WriteOperation.Delete:
|
|
292
|
+
return this.performDeleteWrite(queryer, this.edgeData, this.edgeInput, context);
|
|
293
|
+
case action_1.WriteOperation.Insert:
|
|
294
|
+
case action_1.WriteOperation.Edit:
|
|
295
|
+
return this.performInsertWrite(queryer, this.edgeData, this.edgeInput, context);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
performWriteSync(queryer, context) {
|
|
299
|
+
if (!this.edgeData) {
|
|
300
|
+
throw new Error(`error fetching edgeData for type ${this.edgeInput.edgeType}`);
|
|
301
|
+
}
|
|
302
|
+
switch (this.options.operation) {
|
|
303
|
+
case action_1.WriteOperation.Delete:
|
|
304
|
+
return this.performDeleteWriteSync(queryer, this.edgeData, this.edgeInput, context);
|
|
305
|
+
case action_1.WriteOperation.Insert:
|
|
306
|
+
case action_1.WriteOperation.Edit:
|
|
307
|
+
return this.performInsertWriteSync(queryer, this.edgeData, this.edgeInput, context);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
getDeleteRowParams(edgeData, edge, context) {
|
|
311
|
+
let transformed = null;
|
|
312
|
+
let op = schema_1.SQLStatementOperation.Delete;
|
|
313
|
+
let updateData = null;
|
|
314
|
+
const transformedEdgeWrite = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeWrite;
|
|
315
|
+
if (transformedEdgeWrite && !edge.disableTransformations) {
|
|
316
|
+
transformed = transformedEdgeWrite({
|
|
317
|
+
op: schema_1.SQLStatementOperation.Delete,
|
|
318
|
+
edge,
|
|
319
|
+
});
|
|
320
|
+
if (transformed) {
|
|
321
|
+
op = transformed.op;
|
|
322
|
+
if (transformed.op === schema_1.SQLStatementOperation.Insert) {
|
|
323
|
+
throw new Error(`cannot currently transform a delete into an insert`);
|
|
324
|
+
}
|
|
325
|
+
if (transformed.op === schema_1.SQLStatementOperation.Update) {
|
|
326
|
+
if (!transformed.data) {
|
|
327
|
+
throw new Error(`cannot transform a delete into an update without providing data`);
|
|
328
|
+
}
|
|
329
|
+
updateData = transformed.data;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
op,
|
|
335
|
+
updateData,
|
|
336
|
+
options: {
|
|
337
|
+
tableName: edgeData.edgeTable,
|
|
338
|
+
context,
|
|
339
|
+
},
|
|
340
|
+
clause: clause.And(clause.Eq("id1", edge.id1), clause.Eq("id2", edge.id2), clause.Eq("edge_type", edge.edgeType)),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
async performDeleteWrite(q, edgeData, edge, context) {
|
|
344
|
+
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
345
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
346
|
+
return (0, ent_1.deleteRows)(q, params.options, params.clause);
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
350
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
351
|
+
}
|
|
352
|
+
await (0, ent_1.editRow)(q, {
|
|
353
|
+
tableName: params.options.tableName,
|
|
354
|
+
whereClause: params.clause,
|
|
355
|
+
fields: params.updateData,
|
|
356
|
+
fieldsToLog: params.updateData,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
performDeleteWriteSync(q, edgeData, edge, context) {
|
|
361
|
+
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
362
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
363
|
+
return (0, ent_1.deleteRowsSync)(q, params.options, params.clause);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
367
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
368
|
+
}
|
|
369
|
+
(0, ent_1.editRowSync)(q, {
|
|
370
|
+
tableName: params.options.tableName,
|
|
371
|
+
whereClause: params.clause,
|
|
372
|
+
fields: params.updateData,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
getInsertRowParams(edgeData, edge, context) {
|
|
377
|
+
const fields = {
|
|
378
|
+
id1: edge.id1,
|
|
379
|
+
id2: edge.id2,
|
|
380
|
+
id1_type: edge.id1Type,
|
|
381
|
+
id2_type: edge.id2Type,
|
|
382
|
+
edge_type: edge.edgeType,
|
|
383
|
+
data: edge.data || null,
|
|
384
|
+
};
|
|
385
|
+
if (edge.time) {
|
|
386
|
+
fields["time"] = edge.time.toISOString();
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
// todo make this a schema field like what we do in generated base files...
|
|
390
|
+
// maybe when actions exist?
|
|
391
|
+
fields["time"] = new Date().toISOString();
|
|
392
|
+
}
|
|
393
|
+
const onConflictFields = ["data"];
|
|
394
|
+
const extraEdgeFields = (0, global_schema_1.__getGlobalSchema)()?.extraEdgeFields;
|
|
395
|
+
if (extraEdgeFields) {
|
|
396
|
+
for (const name in extraEdgeFields) {
|
|
397
|
+
const f = extraEdgeFields[name];
|
|
398
|
+
if (f.defaultValueOnCreate) {
|
|
399
|
+
const storageKey = (0, schema_1.getStorageKey)(f, name);
|
|
400
|
+
fields[storageKey] = f.defaultValueOnCreate(this.builder, {});
|
|
401
|
+
// onconflict make sure we override the default values
|
|
402
|
+
// e.g. setting deleted_at = null for soft delete
|
|
403
|
+
onConflictFields.push(storageKey);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
let transformed = null;
|
|
408
|
+
const transformEdgeWrite = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeWrite;
|
|
409
|
+
if (transformEdgeWrite && !edge.disableTransformations) {
|
|
410
|
+
transformed = transformEdgeWrite({
|
|
411
|
+
op: schema_1.SQLStatementOperation.Insert,
|
|
412
|
+
edge,
|
|
413
|
+
});
|
|
414
|
+
if (transformed) {
|
|
415
|
+
throw new Error(`transforming an insert edge not currently supported`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return [
|
|
419
|
+
{
|
|
420
|
+
tableName: edgeData.edgeTable,
|
|
421
|
+
fields: fields,
|
|
422
|
+
fieldsToLog: fields,
|
|
423
|
+
context,
|
|
424
|
+
},
|
|
425
|
+
`ON CONFLICT(id1, edge_type, id2) DO UPDATE SET ${onConflictFields
|
|
426
|
+
.map((f) => `${f} = EXCLUDED.${f}`)
|
|
427
|
+
.join(", ")}`,
|
|
428
|
+
];
|
|
429
|
+
}
|
|
430
|
+
async performInsertWrite(q, edgeData, edge, context) {
|
|
431
|
+
const [options, suffix] = this.getInsertRowParams(edgeData, edge, context);
|
|
432
|
+
await (0, ent_1.createRow)(q, options, suffix);
|
|
433
|
+
}
|
|
434
|
+
performInsertWriteSync(q, edgeData, edge, context) {
|
|
435
|
+
const [options, suffix] = this.getInsertRowParams(edgeData, edge, context);
|
|
436
|
+
(0, ent_1.createRowSync)(q, options, suffix);
|
|
437
|
+
}
|
|
438
|
+
resolveImpl(executor, placeholder, desc) {
|
|
439
|
+
let ent = executor.resolveValue(placeholder);
|
|
440
|
+
if (!ent) {
|
|
441
|
+
throw new Error(`could not resolve placeholder value ${placeholder} for ${desc} for edge ${this.edgeInput.edgeType}`);
|
|
442
|
+
}
|
|
443
|
+
if (ent.id === undefined) {
|
|
444
|
+
throw new Error(`id of resolved ent is not defined`);
|
|
445
|
+
}
|
|
446
|
+
return [ent.id, ent.nodeType];
|
|
447
|
+
}
|
|
448
|
+
resolve(executor) {
|
|
449
|
+
if (this.options.id1Placeholder) {
|
|
450
|
+
[this.edgeInput.id1, this.edgeInput.id1Type] = this.resolveImpl(executor, this.edgeInput.id1, "id1");
|
|
451
|
+
}
|
|
452
|
+
if (this.options.id2Placeholder) {
|
|
453
|
+
[this.edgeInput.id2, this.edgeInput.id2Type] = this.resolveImpl(executor, this.edgeInput.id2, "id2");
|
|
454
|
+
}
|
|
455
|
+
if (this.options.dataPlaceholder) {
|
|
456
|
+
if (!this.edgeInput.data) {
|
|
457
|
+
throw new Error(`data placeholder set but edgeInput data undefined`);
|
|
458
|
+
}
|
|
459
|
+
let [data, _] = this.resolveImpl(executor, this.edgeInput.data.toString(), "data");
|
|
460
|
+
this.edgeInput.data = data.toString();
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
symmetricEdge() {
|
|
464
|
+
return new EdgeOperation(this.builder, {
|
|
465
|
+
id1: this.edgeInput.id2,
|
|
466
|
+
id1Type: this.edgeInput.id2Type,
|
|
467
|
+
id2: this.edgeInput.id1,
|
|
468
|
+
id2Type: this.edgeInput.id1Type,
|
|
469
|
+
edgeType: this.edgeInput.edgeType,
|
|
470
|
+
time: this.edgeInput.time,
|
|
471
|
+
data: this.edgeInput.data,
|
|
472
|
+
disableTransformations: this.edgeInput.disableTransformations,
|
|
473
|
+
}, {
|
|
474
|
+
operation: this.options.operation,
|
|
475
|
+
id1Placeholder: this.options.id2Placeholder,
|
|
476
|
+
id2Placeholder: this.options.id1Placeholder,
|
|
477
|
+
dataPlaceholder: this.options.dataPlaceholder,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
inverseEdge(edgeData) {
|
|
481
|
+
return new EdgeOperation(this.builder, {
|
|
482
|
+
id1: this.edgeInput.id2,
|
|
483
|
+
id1Type: this.edgeInput.id2Type,
|
|
484
|
+
id2: this.edgeInput.id1,
|
|
485
|
+
id2Type: this.edgeInput.id1Type,
|
|
486
|
+
edgeType: edgeData.inverseEdgeType,
|
|
487
|
+
time: this.edgeInput.time,
|
|
488
|
+
data: this.edgeInput.data,
|
|
489
|
+
disableTransformations: this.edgeInput.disableTransformations,
|
|
490
|
+
}, {
|
|
491
|
+
operation: this.options.operation,
|
|
492
|
+
id1Placeholder: this.options.id2Placeholder,
|
|
493
|
+
id2Placeholder: this.options.id1Placeholder,
|
|
494
|
+
dataPlaceholder: this.options.dataPlaceholder,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
static resolveIDs(srcBuilder, // id1
|
|
498
|
+
destID) {
|
|
499
|
+
let destIDVal;
|
|
500
|
+
let destPlaceholder = false;
|
|
501
|
+
if (this.isBuilder(destID)) {
|
|
502
|
+
destIDVal = destID.placeholderID;
|
|
503
|
+
destPlaceholder = true;
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
destIDVal = destID;
|
|
507
|
+
}
|
|
508
|
+
let srcIDVal;
|
|
509
|
+
let srcType;
|
|
510
|
+
let srcPlaceholder = false;
|
|
511
|
+
if (srcBuilder.existingEnt) {
|
|
512
|
+
srcIDVal = srcBuilder.existingEnt.id;
|
|
513
|
+
srcType = srcBuilder.existingEnt.nodeType;
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
srcPlaceholder = true;
|
|
517
|
+
// get placeholder.
|
|
518
|
+
srcIDVal = srcBuilder.placeholderID;
|
|
519
|
+
// expected to be filled later
|
|
520
|
+
srcType = "";
|
|
521
|
+
}
|
|
522
|
+
return [srcIDVal, srcType, srcPlaceholder, destIDVal, destPlaceholder];
|
|
523
|
+
}
|
|
524
|
+
static isBuilder(val) {
|
|
525
|
+
return val.placeholderID !== undefined;
|
|
526
|
+
}
|
|
527
|
+
static resolveData(data) {
|
|
528
|
+
if (!data) {
|
|
529
|
+
return [undefined, false];
|
|
530
|
+
}
|
|
531
|
+
if (this.isBuilder(data)) {
|
|
532
|
+
return [data.placeholderID.toString(), true];
|
|
533
|
+
}
|
|
534
|
+
return [data, false];
|
|
535
|
+
}
|
|
536
|
+
static inboundEdge(builder, edgeType, id1, nodeType, options) {
|
|
537
|
+
let [id2Val, id2Type, id2Placeholder, id1Val, id1Placeholder] = EdgeOperation.resolveIDs(builder, id1);
|
|
538
|
+
let [data, dataPlaceholder] = EdgeOperation.resolveData(options?.data);
|
|
539
|
+
const edge = {
|
|
540
|
+
id1: id1Val,
|
|
541
|
+
edgeType: edgeType,
|
|
542
|
+
id2: id2Val,
|
|
543
|
+
id2Type: id2Type,
|
|
544
|
+
id1Type: nodeType,
|
|
545
|
+
...options,
|
|
546
|
+
};
|
|
547
|
+
if (data) {
|
|
548
|
+
edge.data = data;
|
|
549
|
+
}
|
|
550
|
+
return new EdgeOperation(builder, edge, {
|
|
551
|
+
operation: action_1.WriteOperation.Insert,
|
|
552
|
+
id2Placeholder,
|
|
553
|
+
id1Placeholder,
|
|
554
|
+
dataPlaceholder,
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
static outboundEdge(builder, edgeType, id2, nodeType, options) {
|
|
558
|
+
let [id1Val, id1Type, id1Placeholder, id2Val, id2Placeholder] = EdgeOperation.resolveIDs(builder, id2);
|
|
559
|
+
let [data, dataPlaceholder] = EdgeOperation.resolveData(options?.data);
|
|
560
|
+
const edge = {
|
|
561
|
+
id1: id1Val,
|
|
562
|
+
edgeType: edgeType,
|
|
563
|
+
id2: id2Val,
|
|
564
|
+
id2Type: nodeType,
|
|
565
|
+
id1Type: id1Type,
|
|
566
|
+
...options,
|
|
567
|
+
};
|
|
568
|
+
if (data) {
|
|
569
|
+
edge.data = data;
|
|
570
|
+
}
|
|
571
|
+
return new EdgeOperation(builder, edge, {
|
|
572
|
+
operation: action_1.WriteOperation.Insert,
|
|
573
|
+
id1Placeholder,
|
|
574
|
+
id2Placeholder,
|
|
575
|
+
dataPlaceholder,
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
static removeInboundEdge(builder, edgeType, id1, options) {
|
|
579
|
+
if (!builder.existingEnt) {
|
|
580
|
+
throw new Error("cannot remove an edge from a non-existing ent");
|
|
581
|
+
}
|
|
582
|
+
const edge = {
|
|
583
|
+
id1: id1,
|
|
584
|
+
edgeType: edgeType,
|
|
585
|
+
id2: builder.existingEnt.id,
|
|
586
|
+
id2Type: "",
|
|
587
|
+
id1Type: "",
|
|
588
|
+
disableTransformations: options?.disableTransformations,
|
|
589
|
+
};
|
|
590
|
+
return new EdgeOperation(builder, edge, {
|
|
591
|
+
operation: action_1.WriteOperation.Delete,
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
static removeOutboundEdge(builder, edgeType, id2, options) {
|
|
595
|
+
if (!builder.existingEnt) {
|
|
596
|
+
throw new Error("cannot remove an edge from a non-existing ent");
|
|
597
|
+
}
|
|
598
|
+
const edge = {
|
|
599
|
+
id2: id2,
|
|
600
|
+
edgeType: edgeType,
|
|
601
|
+
id1: builder.existingEnt.id,
|
|
602
|
+
id2Type: "",
|
|
603
|
+
id1Type: "",
|
|
604
|
+
disableTransformations: options?.disableTransformations,
|
|
605
|
+
};
|
|
606
|
+
return new EdgeOperation(builder, edge, {
|
|
607
|
+
operation: action_1.WriteOperation.Delete,
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
exports.EdgeOperation = EdgeOperation;
|
|
612
|
+
class ConditionalOperation {
|
|
613
|
+
constructor(op, conditionalBuilder) {
|
|
614
|
+
this.op = op;
|
|
615
|
+
this.conditionalBuilder = conditionalBuilder;
|
|
616
|
+
this.shortCircuited = false;
|
|
617
|
+
this.builder = op.builder;
|
|
618
|
+
this.placeholderID = op.placeholderID;
|
|
619
|
+
}
|
|
620
|
+
shortCircuit(executor) {
|
|
621
|
+
this.shortCircuited = executor.builderOpChanged(this.conditionalBuilder);
|
|
622
|
+
return this.shortCircuited;
|
|
623
|
+
}
|
|
624
|
+
async preFetch(queryer, context) {
|
|
625
|
+
if (this.op.preFetch) {
|
|
626
|
+
return this.op.preFetch(queryer, context);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
performWriteSync(queryer, context) {
|
|
630
|
+
this.op.performWriteSync(queryer, context);
|
|
631
|
+
}
|
|
632
|
+
performWrite(queryer, context) {
|
|
633
|
+
return this.op.performWrite(queryer, context);
|
|
634
|
+
}
|
|
635
|
+
returnedRow() {
|
|
636
|
+
if (this.op.returnedRow) {
|
|
637
|
+
return this.op.returnedRow();
|
|
638
|
+
}
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
updatedOperation() {
|
|
642
|
+
if (this.op.updatedOperation) {
|
|
643
|
+
return this.op.updatedOperation();
|
|
644
|
+
}
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
resolve(executor) {
|
|
648
|
+
if (this.op.resolve) {
|
|
649
|
+
return this.op.resolve(executor);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
async postFetch(queryer, context) {
|
|
653
|
+
if (this.op.postFetch) {
|
|
654
|
+
return this.op.postFetch(queryer, context);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
exports.ConditionalOperation = ConditionalOperation;
|
|
659
|
+
// separate because we need to implement createdEnt and we manually run those before edge/other operations in executors
|
|
660
|
+
class ConditionalNodeOperation extends ConditionalOperation {
|
|
661
|
+
createdEnt(viewer) {
|
|
662
|
+
if (this.op.createdEnt) {
|
|
663
|
+
return this.op.createdEnt(viewer);
|
|
664
|
+
}
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
updatedOperation() {
|
|
668
|
+
if (!this.op.updatedOperation) {
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
const ret = this.op.updatedOperation();
|
|
672
|
+
if (ret !== null) {
|
|
673
|
+
return ret;
|
|
674
|
+
}
|
|
675
|
+
if (!this.shortCircuited) {
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
// hack. if this short circuited, claim that this updated as an edit and it should invalidate other builders
|
|
679
|
+
// this API needs to change or EditNodeOperation needs to be used instead of this...
|
|
680
|
+
return {
|
|
681
|
+
operation: action_1.WriteOperation.Edit,
|
|
682
|
+
builder: this.builder,
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
exports.ConditionalNodeOperation = ConditionalNodeOperation;
|