@snowtop/ent 0.1.0-alpha95 → 0.1.0-alpha96
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 +3 -3
- package/action/executor.js +6 -1
- package/action/experimental_action.d.ts +5 -2
- package/action/experimental_action.js +15 -12
- package/action/index.d.ts +2 -0
- package/action/index.js +7 -1
- package/action/orchestrator.d.ts +4 -2
- package/action/orchestrator.js +6 -0
- package/action/relative_value.d.ts +47 -0
- package/action/relative_value.js +125 -0
- package/action/transaction.d.ts +10 -0
- package/action/transaction.js +23 -0
- package/auth/auth.d.ts +1 -1
- package/core/base.d.ts +4 -2
- package/core/clause.d.ts +6 -1
- package/core/clause.js +25 -4
- package/core/config.d.ts +2 -1
- package/core/config.js +2 -0
- package/core/date.js +1 -5
- package/core/db.d.ts +9 -6
- package/core/db.js +14 -6
- package/core/ent.d.ts +3 -1
- package/core/ent.js +76 -26
- package/core/logger.d.ts +1 -1
- package/core/query/assoc_query.d.ts +2 -2
- package/core/query/shared_assoc_test.js +1 -2
- package/core/query/shared_test.js +0 -1
- package/graphql/graphql.d.ts +6 -6
- package/graphql/graphql.js +1 -0
- package/graphql/query/connection_type.d.ts +1 -1
- package/graphql/query/shared_assoc_test.js +1 -1
- package/graphql/query/shared_edge_connection.js +0 -4
- package/imports/index.d.ts +6 -1
- package/imports/index.js +14 -3
- package/index.d.ts +1 -0
- package/package.json +16 -16
- package/parse_schema/parse.d.ts +7 -7
- package/schema/base_schema.d.ts +3 -3
- package/schema/field.js +2 -2
- package/schema/schema.d.ts +11 -10
- package/schema/schema.js +3 -13
- package/scripts/custom_graphql.js +30 -4
- package/testutils/action/complex_schemas.d.ts +69 -0
- package/testutils/action/complex_schemas.js +398 -0
- package/testutils/builder.d.ts +21 -36
- package/testutils/builder.js +39 -45
- package/testutils/db/temp_db.d.ts +6 -3
- package/testutils/db/temp_db.js +79 -7
- package/testutils/db/value.d.ts +1 -0
- package/testutils/db/value.js +2 -2
- package/testutils/db_mock.d.ts +16 -4
- package/testutils/db_mock.js +48 -5
- package/testutils/ent-graphql-tests/index.d.ts +7 -1
- package/testutils/ent-graphql-tests/index.js +17 -5
- package/testutils/fake_data/fake_contact.d.ts +1 -0
- package/testutils/fake_data/fake_contact.js +6 -5
- package/testutils/fake_data/fake_event.d.ts +1 -0
- package/testutils/fake_data/fake_event.js +4 -3
- package/testutils/fake_data/fake_tag.d.ts +2 -1
- package/testutils/fake_data/fake_tag.js +6 -5
- package/testutils/fake_data/fake_user.d.ts +2 -1
- package/testutils/fake_data/fake_user.js +14 -13
- package/tsc/ast.d.ts +1 -1
package/schema/schema.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ interface FieldInfo {
|
|
|
9
9
|
dbCol: string;
|
|
10
10
|
inputKey: string;
|
|
11
11
|
}
|
|
12
|
-
export
|
|
12
|
+
export type FieldInfoMap = {
|
|
13
13
|
[key: string]: FieldInfo;
|
|
14
14
|
};
|
|
15
15
|
export interface GlobalSchema {
|
|
@@ -18,12 +18,12 @@ export interface GlobalSchema {
|
|
|
18
18
|
transformEdgeRead?: () => Clause;
|
|
19
19
|
transformEdgeWrite?: (stmt: EdgeUpdateOperation) => TransformedEdgeUpdateOperation | null;
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
export
|
|
21
|
+
type FieldOverride = Pick<FieldOptions, "nullable" | "storageKey" | "serverDefault" | "unique" | "hideFromGraphQL" | "graphqlName" | "index">;
|
|
22
|
+
export type FieldOverrideMap = {
|
|
23
23
|
[key: string]: FieldOverride;
|
|
24
24
|
};
|
|
25
25
|
export default interface Schema {
|
|
26
|
-
fields: FieldMap
|
|
26
|
+
fields: FieldMap;
|
|
27
27
|
fieldOverrides?: FieldOverrideMap;
|
|
28
28
|
tableName?: string;
|
|
29
29
|
patterns?: Pattern[];
|
|
@@ -78,10 +78,10 @@ export interface AssocEdgeGroup {
|
|
|
78
78
|
nullStateFn?: string;
|
|
79
79
|
edgeAction?: EdgeGroupAction;
|
|
80
80
|
}
|
|
81
|
-
export
|
|
81
|
+
export type Edge = AssocEdge;
|
|
82
82
|
export interface Pattern {
|
|
83
83
|
name: string;
|
|
84
|
-
fields: FieldMap
|
|
84
|
+
fields: FieldMap;
|
|
85
85
|
disableMixin?: boolean;
|
|
86
86
|
edges?: Edge[];
|
|
87
87
|
transformRead?: () => Clause;
|
|
@@ -173,7 +173,7 @@ export interface ForeignKey {
|
|
|
173
173
|
disableBuilderType?: boolean;
|
|
174
174
|
[x: string]: any;
|
|
175
175
|
}
|
|
176
|
-
|
|
176
|
+
type getLoaderInfoFn = (type: string) => LoaderInfo;
|
|
177
177
|
export interface InverseFieldEdge {
|
|
178
178
|
name: string;
|
|
179
179
|
edgeConstName?: string;
|
|
@@ -214,6 +214,7 @@ export interface FieldOptions {
|
|
|
214
214
|
getDerivedFields?(name: string): FieldMap;
|
|
215
215
|
convert?: ConvertType;
|
|
216
216
|
fetchOnDemand?: boolean;
|
|
217
|
+
dbOnly?: boolean;
|
|
217
218
|
[x: string]: any;
|
|
218
219
|
}
|
|
219
220
|
export interface PolymorphicOptions {
|
|
@@ -233,7 +234,7 @@ export interface Field extends FieldOptions {
|
|
|
233
234
|
export interface SchemaConstructor {
|
|
234
235
|
new (): Schema;
|
|
235
236
|
}
|
|
236
|
-
export
|
|
237
|
+
export type SchemaInputType = Schema | SchemaConstructor;
|
|
237
238
|
export declare function getSchema(value: SchemaInputType): Schema;
|
|
238
239
|
export declare function getFields(value: SchemaInputType): Map<string, Field>;
|
|
239
240
|
/**
|
|
@@ -257,8 +258,8 @@ export declare enum ActionOperation {
|
|
|
257
258
|
RemoveEdge = 32,
|
|
258
259
|
EdgeGroup = 64
|
|
259
260
|
}
|
|
260
|
-
|
|
261
|
-
|
|
261
|
+
type actionFieldType = "ID" | "Boolean" | "Int" | "Float" | "String" | "Time" | "Object";
|
|
262
|
+
type NullableListOptions = "contents" | "contentsAndList";
|
|
262
263
|
export interface ActionField {
|
|
263
264
|
name: string;
|
|
264
265
|
type: actionFieldType;
|
package/schema/schema.js
CHANGED
|
@@ -56,21 +56,11 @@ exports.getSchema = getSchema;
|
|
|
56
56
|
function getFields(value) {
|
|
57
57
|
const schema = getSchema(value);
|
|
58
58
|
function addFields(fields) {
|
|
59
|
-
if (Array.isArray(fields)) {
|
|
60
|
-
for (const field of fields) {
|
|
61
|
-
const name = field.name;
|
|
62
|
-
if (!name) {
|
|
63
|
-
throw new Error(`name required`);
|
|
64
|
-
}
|
|
65
|
-
if (field.getDerivedFields !== undefined) {
|
|
66
|
-
addFields(field.getDerivedFields(name));
|
|
67
|
-
}
|
|
68
|
-
m.set(name, field);
|
|
69
|
-
}
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
59
|
for (const name in fields) {
|
|
73
60
|
const field = fields[name];
|
|
61
|
+
if (field.dbOnly) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
74
64
|
if (field.getDerivedFields !== undefined) {
|
|
75
65
|
addFields(field.getDerivedFields(name));
|
|
76
66
|
}
|
|
@@ -114,6 +114,7 @@ function processTopLevel(l, l2) {
|
|
|
114
114
|
fieldType: custom.fieldType,
|
|
115
115
|
args: transformArgs(custom),
|
|
116
116
|
results: transformResultType(custom),
|
|
117
|
+
description: custom.description,
|
|
117
118
|
});
|
|
118
119
|
}
|
|
119
120
|
}
|
|
@@ -128,6 +129,7 @@ function processCustomFields(fields, gqlCapture, nodeName) {
|
|
|
128
129
|
fieldType: f.fieldType,
|
|
129
130
|
args: transformArgs(f),
|
|
130
131
|
results: transformResultType(f),
|
|
132
|
+
description: f.description,
|
|
131
133
|
});
|
|
132
134
|
}
|
|
133
135
|
m.set(nodeName, results);
|
|
@@ -213,11 +215,27 @@ async function requireFiles(files) {
|
|
|
213
215
|
throw new Error(err);
|
|
214
216
|
});
|
|
215
217
|
}
|
|
218
|
+
// filePath is path-to-src
|
|
216
219
|
async function parseImports(filePath) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
return (0, imports_1.parseCustomImports)(filePath, [
|
|
221
|
+
{
|
|
222
|
+
// graphql files
|
|
223
|
+
root: path.join(filePath, "graphql"),
|
|
224
|
+
opts: {
|
|
225
|
+
ignore: ["**/generated/**", "**/tests/**"],
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
// can't just use top level ent files but have to check for all (non-generated) files
|
|
230
|
+
// in src/ent/* because custom edges (or other things) could have @gqlField etc
|
|
231
|
+
// and then have to look for these imports etc
|
|
232
|
+
root: path.join(filePath, "ent"),
|
|
233
|
+
opts: {
|
|
234
|
+
// not in action files since we can't customize payloads (yet?)
|
|
235
|
+
ignore: ["**/generated/**", "**/tests/**", "**/actions/**"],
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
]);
|
|
221
239
|
}
|
|
222
240
|
function findGraphQLPath(filePath) {
|
|
223
241
|
while (filePath !== "/") {
|
|
@@ -232,6 +250,10 @@ function findGraphQLPath(filePath) {
|
|
|
232
250
|
}
|
|
233
251
|
return undefined;
|
|
234
252
|
}
|
|
253
|
+
// test as follows:
|
|
254
|
+
// there should be an easier way to do this...
|
|
255
|
+
// also, there should be a way to get the list of objects here that's not manual
|
|
256
|
+
//echo "User\nContact\nContactEmail\nComment" | ts-node-script --log-error --project ./tsconfig.json -r tsconfig-paths/register ../../ts/src/scripts/custom_graphql.ts --path ~/code/ent/examples/simple/src/
|
|
235
257
|
async function main() {
|
|
236
258
|
// known custom types that are not required
|
|
237
259
|
// if not in the schema, will be ignored
|
|
@@ -345,6 +367,10 @@ async function main() {
|
|
|
345
367
|
};
|
|
346
368
|
buildClasses(mutations);
|
|
347
369
|
buildClasses(queries);
|
|
370
|
+
// call for every field in a node
|
|
371
|
+
for (const k in fields) {
|
|
372
|
+
buildClasses(fields[k]);
|
|
373
|
+
}
|
|
348
374
|
console.log(JSON.stringify({
|
|
349
375
|
args,
|
|
350
376
|
inputs,
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Ent, ID, Viewer, Data } from "../../core/base";
|
|
2
|
+
import { DataOperation } from "../../core/ent";
|
|
3
|
+
import { Action, Builder, Executor, WriteOperation, Trigger, Observer, TriggerReturn } from "../../action/action";
|
|
4
|
+
import { EdgeInputData } from "../../action/orchestrator";
|
|
5
|
+
import { User, Group, Message, Contact, SimpleBuilder, BuilderSchema, SimpleAction, BaseEnt } from "../../testutils/builder";
|
|
6
|
+
import { MockLogs } from "../../testutils/mock_log";
|
|
7
|
+
import { Table } from "../db/temp_db";
|
|
8
|
+
export declare function setupTest(): void;
|
|
9
|
+
export declare function getML(): MockLogs;
|
|
10
|
+
export declare function getOperations(): DataOperation<Ent<Viewer<Ent<any> | null, ID | null>>>[];
|
|
11
|
+
export declare const UserSchema: BuilderSchema<User>;
|
|
12
|
+
export declare class UserWithBalance extends User {
|
|
13
|
+
}
|
|
14
|
+
export declare const UserBalanceSchema: BuilderSchema<UserWithBalance>;
|
|
15
|
+
export declare class UserWithBalanceWithCheck extends UserWithBalance {
|
|
16
|
+
}
|
|
17
|
+
export declare const UserBalanceWithCheckSchema: BuilderSchema<UserWithBalanceWithCheck>;
|
|
18
|
+
export declare class Account extends BaseEnt {
|
|
19
|
+
accountID: string;
|
|
20
|
+
nodeType: string;
|
|
21
|
+
}
|
|
22
|
+
export declare const AccountSchema: BuilderSchema<Account>;
|
|
23
|
+
export declare const ContactSchema: BuilderSchema<Contact>;
|
|
24
|
+
export declare const GroupSchema: BuilderSchema<Group>;
|
|
25
|
+
export declare class GroupMembership extends BaseEnt {
|
|
26
|
+
nodeType: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const GroupMembershipSchema: BuilderSchema<GroupMembership>;
|
|
29
|
+
export declare class Changelog extends BaseEnt {
|
|
30
|
+
nodeType: string;
|
|
31
|
+
}
|
|
32
|
+
export declare const ChangelogSchema: BuilderSchema<Changelog>;
|
|
33
|
+
export declare const MessageSchema: BuilderSchema<Message>;
|
|
34
|
+
export declare function executeAction<T extends Ent, E = any>(action: Action<T, Builder<T>>, name?: E): Promise<Executor>;
|
|
35
|
+
export declare function createGroup(): Promise<Group>;
|
|
36
|
+
export declare function createUser(): Promise<User>;
|
|
37
|
+
export declare class MessageAction extends SimpleAction<Message> {
|
|
38
|
+
constructor(viewer: Viewer, fields: Map<string, any>, operation: WriteOperation, existingEnt: Message | null);
|
|
39
|
+
getTriggers(): Trigger<Message, SimpleBuilder<Message, Message | null>>[];
|
|
40
|
+
getObservers(): Observer<Message, SimpleBuilder<Message>>[];
|
|
41
|
+
}
|
|
42
|
+
export declare class UserAction extends SimpleAction<User> {
|
|
43
|
+
contactAction: SimpleAction<Contact> | undefined;
|
|
44
|
+
constructor(viewer: Viewer, fields: Map<string, any>, operation: WriteOperation, existingEnt: User | null);
|
|
45
|
+
getTriggers(): Trigger<User, SimpleBuilder<User>>[];
|
|
46
|
+
getObservers(): Observer<User, SimpleBuilder<User>>[];
|
|
47
|
+
}
|
|
48
|
+
type getMembershipFunction = (viewer: Viewer, edge: EdgeInputData) => SimpleAction<Ent>;
|
|
49
|
+
export declare class GroupMembershipTrigger implements Trigger<Group, SimpleBuilder<Group>> {
|
|
50
|
+
private getter;
|
|
51
|
+
constructor(getter: getMembershipFunction);
|
|
52
|
+
changeset(builder: SimpleBuilder<Group>, input: Data): TriggerReturn;
|
|
53
|
+
}
|
|
54
|
+
export declare class EditGroupAction extends SimpleAction<Group> {
|
|
55
|
+
viewer: Viewer;
|
|
56
|
+
private getter;
|
|
57
|
+
constructor(viewer: Viewer, schema: BuilderSchema<Group>, fields: Map<string, any>, existingEnt: Group, getter: getMembershipFunction);
|
|
58
|
+
getTriggers: () => GroupMembershipTrigger[];
|
|
59
|
+
}
|
|
60
|
+
export declare function verifyGroupMembers(group: Group, members: User[]): Promise<ID[]>;
|
|
61
|
+
export declare function loadMemberships(viewer: Viewer, membershipids: ID[]): Promise<GroupMembership[]>;
|
|
62
|
+
export declare function loadChangelogs(viewer: Viewer, clids: ID[]): Promise<Changelog[]>;
|
|
63
|
+
export declare function verifyChangelogFromMeberships(user: User, memberships: GroupMembership[]): Promise<void>;
|
|
64
|
+
export declare class GroupMemberOf extends BaseEnt {
|
|
65
|
+
nodeType: string;
|
|
66
|
+
}
|
|
67
|
+
export declare const GroupMemberOfSchema: BuilderSchema<GroupMemberOf>;
|
|
68
|
+
export declare const getTables: () => Table[];
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,398 @@
|
|
|
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.getTables = exports.GroupMemberOfSchema = exports.GroupMemberOf = exports.verifyChangelogFromMeberships = exports.loadChangelogs = exports.loadMemberships = exports.verifyGroupMembers = exports.EditGroupAction = exports.GroupMembershipTrigger = exports.UserAction = exports.MessageAction = exports.createUser = exports.createGroup = exports.executeAction = exports.MessageSchema = exports.ChangelogSchema = exports.Changelog = exports.GroupMembershipSchema = exports.GroupMembership = exports.GroupSchema = exports.ContactSchema = exports.AccountSchema = exports.Account = exports.UserBalanceWithCheckSchema = exports.UserWithBalanceWithCheck = exports.UserBalanceSchema = exports.UserWithBalance = exports.UserSchema = exports.getOperations = exports.getML = exports.setupTest = void 0;
|
|
27
|
+
const ent_1 = require("../../core/ent");
|
|
28
|
+
const object_loader_1 = require("../../core/loaders/object_loader");
|
|
29
|
+
const action_1 = require("../../action/action");
|
|
30
|
+
const executor_1 = require("../../action/executor");
|
|
31
|
+
const builder_1 = require("../../testutils/builder");
|
|
32
|
+
const viewer_1 = require("../../core/viewer");
|
|
33
|
+
const field_1 = require("../../schema/field");
|
|
34
|
+
const json_field_1 = require("../../schema/json_field");
|
|
35
|
+
const fake_log_1 = require("../../testutils/fake_log");
|
|
36
|
+
const write_1 = require("../../testutils/write");
|
|
37
|
+
const mock_log_1 = require("../../testutils/mock_log");
|
|
38
|
+
const logger_1 = require("../../core/logger");
|
|
39
|
+
const action = __importStar(require("../../action"));
|
|
40
|
+
const convert_1 = require("../../core/convert");
|
|
41
|
+
const uuid_1 = require("uuid");
|
|
42
|
+
const temp_db_1 = require("../db/temp_db");
|
|
43
|
+
const db_1 = require("../../core/db");
|
|
44
|
+
const schema_1 = require("../../schema");
|
|
45
|
+
const ml = new mock_log_1.MockLogs();
|
|
46
|
+
let operations = [];
|
|
47
|
+
const edges = [
|
|
48
|
+
"fake_edge",
|
|
49
|
+
"selfContact",
|
|
50
|
+
"channelMember",
|
|
51
|
+
"senderToMessage",
|
|
52
|
+
"workspaceMember",
|
|
53
|
+
"recipientToMessage",
|
|
54
|
+
"objectToChangelog",
|
|
55
|
+
"changelogToParent",
|
|
56
|
+
];
|
|
57
|
+
function setupTest() {
|
|
58
|
+
beforeEach(async () => {
|
|
59
|
+
// does assoc_edge_config loader need to be cleared?
|
|
60
|
+
for (const edge of edges) {
|
|
61
|
+
await (0, write_1.createRowForTest)({
|
|
62
|
+
tableName: "assoc_edge_config",
|
|
63
|
+
fields: {
|
|
64
|
+
edge_table: `${edge}_table`,
|
|
65
|
+
symmetric_edge: false,
|
|
66
|
+
inverse_edge_type: null,
|
|
67
|
+
edge_type: edge,
|
|
68
|
+
edge_name: "name",
|
|
69
|
+
created_at: new Date(),
|
|
70
|
+
updated_at: new Date(),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
ml.clear();
|
|
75
|
+
});
|
|
76
|
+
beforeAll(() => {
|
|
77
|
+
(0, logger_1.setLogLevels)(["query", "error", "cache"]);
|
|
78
|
+
ml.mock();
|
|
79
|
+
});
|
|
80
|
+
afterEach(() => {
|
|
81
|
+
ml.clear();
|
|
82
|
+
});
|
|
83
|
+
afterAll(() => {
|
|
84
|
+
ml.restore();
|
|
85
|
+
});
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
fake_log_1.FakeLogger.clear();
|
|
88
|
+
operations = [];
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
exports.setupTest = setupTest;
|
|
92
|
+
function getML() {
|
|
93
|
+
return ml;
|
|
94
|
+
}
|
|
95
|
+
exports.getML = getML;
|
|
96
|
+
function getOperations() {
|
|
97
|
+
return operations;
|
|
98
|
+
}
|
|
99
|
+
exports.getOperations = getOperations;
|
|
100
|
+
exports.UserSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
101
|
+
FirstName: (0, field_1.StringType)(),
|
|
102
|
+
LastName: (0, field_1.StringType)(),
|
|
103
|
+
EmailAddress: (0, field_1.StringType)({ nullable: true }),
|
|
104
|
+
AccountID: (0, field_1.UUIDType)({ nullable: true }),
|
|
105
|
+
}, builder_1.User);
|
|
106
|
+
class UserWithBalance extends builder_1.User {
|
|
107
|
+
}
|
|
108
|
+
exports.UserWithBalance = UserWithBalance;
|
|
109
|
+
exports.UserBalanceSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
110
|
+
first_name: (0, field_1.StringType)(),
|
|
111
|
+
last_name: (0, field_1.StringType)(),
|
|
112
|
+
email_address: (0, field_1.StringType)({ nullable: true }),
|
|
113
|
+
balance: (0, field_1.FloatType)(),
|
|
114
|
+
}, UserWithBalance);
|
|
115
|
+
class UserWithBalanceWithCheck extends UserWithBalance {
|
|
116
|
+
}
|
|
117
|
+
exports.UserWithBalanceWithCheck = UserWithBalanceWithCheck;
|
|
118
|
+
exports.UserBalanceWithCheckSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
119
|
+
first_name: (0, field_1.StringType)(),
|
|
120
|
+
last_name: (0, field_1.StringType)(),
|
|
121
|
+
email_address: (0, field_1.StringType)({ nullable: true }),
|
|
122
|
+
balance: (0, field_1.FloatType)(),
|
|
123
|
+
}, UserWithBalanceWithCheck, {
|
|
124
|
+
constraints: [
|
|
125
|
+
{
|
|
126
|
+
type: schema_1.ConstraintType.Check,
|
|
127
|
+
name: "positive_balance",
|
|
128
|
+
columns: ["balance"],
|
|
129
|
+
condition: "balance >= 0",
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
});
|
|
133
|
+
class Account extends builder_1.BaseEnt {
|
|
134
|
+
constructor() {
|
|
135
|
+
super(...arguments);
|
|
136
|
+
this.accountID = "";
|
|
137
|
+
this.nodeType = "Account";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.Account = Account;
|
|
141
|
+
exports.AccountSchema = (0, builder_1.getBuilderSchemaFromFields)({}, Account);
|
|
142
|
+
exports.ContactSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
143
|
+
FirstName: (0, field_1.StringType)(),
|
|
144
|
+
LastName: (0, field_1.StringType)(),
|
|
145
|
+
UserID: (0, field_1.StringType)(),
|
|
146
|
+
}, builder_1.Contact);
|
|
147
|
+
exports.GroupSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
148
|
+
name: (0, field_1.StringType)(),
|
|
149
|
+
funField: (0, field_1.StringType)({ nullable: true }),
|
|
150
|
+
}, builder_1.Group);
|
|
151
|
+
class GroupMembership extends builder_1.BaseEnt {
|
|
152
|
+
constructor() {
|
|
153
|
+
super(...arguments);
|
|
154
|
+
this.nodeType = "GroupMembership";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.GroupMembership = GroupMembership;
|
|
158
|
+
exports.GroupMembershipSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
159
|
+
ownerID: (0, field_1.UUIDType)(),
|
|
160
|
+
addedBy: (0, field_1.UUIDType)(),
|
|
161
|
+
notificationsEnabled: (0, field_1.BooleanType)(),
|
|
162
|
+
}, GroupMembership);
|
|
163
|
+
class Changelog extends builder_1.BaseEnt {
|
|
164
|
+
constructor() {
|
|
165
|
+
super(...arguments);
|
|
166
|
+
this.nodeType = "Changelog";
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.Changelog = Changelog;
|
|
170
|
+
exports.ChangelogSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
171
|
+
parentID: (0, field_1.UUIDType)({ polymorphic: true }),
|
|
172
|
+
log: (0, json_field_1.JSONBType)(),
|
|
173
|
+
}, Changelog);
|
|
174
|
+
exports.MessageSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
175
|
+
// TODO both id fields
|
|
176
|
+
sender: (0, field_1.StringType)(),
|
|
177
|
+
recipient: (0, field_1.StringType)(),
|
|
178
|
+
message: (0, field_1.StringType)(),
|
|
179
|
+
transient: (0, field_1.BooleanType)({ nullable: true }),
|
|
180
|
+
expiresAt: (0, field_1.TimestampType)({ nullable: true }),
|
|
181
|
+
}, builder_1.Message);
|
|
182
|
+
jest.spyOn(action, "saveBuilder").mockImplementation(saveBuilder);
|
|
183
|
+
jest.spyOn(action, "saveBuilderX").mockImplementation(saveBuilderX);
|
|
184
|
+
async function saveBuilder(builder) {
|
|
185
|
+
const changeset = await builder.build();
|
|
186
|
+
const executor = changeset.executor();
|
|
187
|
+
operations = await (0, executor_1.executeOperations)(executor, builder.viewer.context, true);
|
|
188
|
+
}
|
|
189
|
+
async function saveBuilderX(builder) {
|
|
190
|
+
return saveBuilder(builder);
|
|
191
|
+
}
|
|
192
|
+
async function executeAction(action, name) {
|
|
193
|
+
const exec = await executor(action.builder);
|
|
194
|
+
if (name !== undefined) {
|
|
195
|
+
expect(exec).toBeInstanceOf(name);
|
|
196
|
+
}
|
|
197
|
+
operations = await (0, executor_1.executeOperations)(exec, action.builder.viewer.context, true);
|
|
198
|
+
return exec;
|
|
199
|
+
}
|
|
200
|
+
exports.executeAction = executeAction;
|
|
201
|
+
async function executor(builder) {
|
|
202
|
+
const changeset = await builder.build();
|
|
203
|
+
return changeset.executor();
|
|
204
|
+
}
|
|
205
|
+
async function createGroup() {
|
|
206
|
+
let groupID = (0, uuid_1.v4)();
|
|
207
|
+
let groupFields = {
|
|
208
|
+
id: groupID,
|
|
209
|
+
name: "group",
|
|
210
|
+
created_at: new Date(),
|
|
211
|
+
updated_at: new Date(),
|
|
212
|
+
};
|
|
213
|
+
// need to create the group first
|
|
214
|
+
await (0, write_1.createRowForTest)({
|
|
215
|
+
tableName: "groups",
|
|
216
|
+
fields: groupFields,
|
|
217
|
+
});
|
|
218
|
+
return new builder_1.Group(new viewer_1.LoggedOutViewer(), groupFields);
|
|
219
|
+
}
|
|
220
|
+
exports.createGroup = createGroup;
|
|
221
|
+
async function createUser() {
|
|
222
|
+
const id = (0, uuid_1.v4)();
|
|
223
|
+
return new builder_1.User(new viewer_1.IDViewer(id), { id });
|
|
224
|
+
}
|
|
225
|
+
exports.createUser = createUser;
|
|
226
|
+
class MessageAction extends builder_1.SimpleAction {
|
|
227
|
+
constructor(viewer, fields, operation, existingEnt) {
|
|
228
|
+
super(viewer, exports.MessageSchema, fields, operation, existingEnt);
|
|
229
|
+
}
|
|
230
|
+
getTriggers() {
|
|
231
|
+
return [
|
|
232
|
+
{
|
|
233
|
+
changeset: (builder, _input) => {
|
|
234
|
+
let sender = builder.fields.get("sender");
|
|
235
|
+
let recipient = builder.fields.get("recipient");
|
|
236
|
+
builder.orchestrator.addInboundEdge(sender, "senderToMessage", "user");
|
|
237
|
+
builder.orchestrator.addInboundEdge(recipient, "recipientToMessage", "user");
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
getObservers() {
|
|
243
|
+
return [new fake_log_1.EntCreationObserver()];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.MessageAction = MessageAction;
|
|
247
|
+
class UserAction extends builder_1.SimpleAction {
|
|
248
|
+
constructor(viewer, fields, operation, existingEnt) {
|
|
249
|
+
super(viewer, exports.UserSchema, fields, operation, existingEnt);
|
|
250
|
+
}
|
|
251
|
+
getTriggers() {
|
|
252
|
+
return [
|
|
253
|
+
{
|
|
254
|
+
changeset: (builder) => {
|
|
255
|
+
let firstName = builder.fields.get("FirstName");
|
|
256
|
+
let lastName = builder.fields.get("LastName");
|
|
257
|
+
this.contactAction = new builder_1.SimpleAction(builder.viewer, exports.ContactSchema, new Map([
|
|
258
|
+
["FirstName", firstName],
|
|
259
|
+
["LastName", lastName],
|
|
260
|
+
["UserID", builder],
|
|
261
|
+
]), action_1.WriteOperation.Insert, null);
|
|
262
|
+
this.contactAction.getObservers = () => [
|
|
263
|
+
new fake_log_1.EntCreationObserver(),
|
|
264
|
+
];
|
|
265
|
+
builder.orchestrator.addOutboundEdge(this.contactAction.builder, "selfContact", "contact");
|
|
266
|
+
return this.contactAction.changeset();
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
];
|
|
270
|
+
}
|
|
271
|
+
getObservers() {
|
|
272
|
+
return [new fake_log_1.EntCreationObserver()];
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
exports.UserAction = UserAction;
|
|
276
|
+
class GroupMembershipTrigger {
|
|
277
|
+
constructor(getter) {
|
|
278
|
+
this.getter = getter;
|
|
279
|
+
}
|
|
280
|
+
changeset(builder, input) {
|
|
281
|
+
const inputEdges = builder.orchestrator.getInputEdges("workspaceMember", action_1.WriteOperation.Insert);
|
|
282
|
+
const changesets = [];
|
|
283
|
+
for (const edge of inputEdges) {
|
|
284
|
+
// we're going to simplify and assume it doesn't currently exist
|
|
285
|
+
const memberAction = this.getter(builder.viewer, edge);
|
|
286
|
+
// store the membership edge in data field of member edge
|
|
287
|
+
builder.orchestrator.addOutboundEdge(edge.id, "workspaceMember", "User", {
|
|
288
|
+
data: memberAction.builder,
|
|
289
|
+
});
|
|
290
|
+
changesets.push(memberAction.changeset());
|
|
291
|
+
}
|
|
292
|
+
return Promise.all(changesets);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
exports.GroupMembershipTrigger = GroupMembershipTrigger;
|
|
296
|
+
class EditGroupAction extends builder_1.SimpleAction {
|
|
297
|
+
constructor(viewer, schema, fields, existingEnt, getter) {
|
|
298
|
+
super(viewer, schema, fields, action_1.WriteOperation.Edit, existingEnt);
|
|
299
|
+
this.viewer = viewer;
|
|
300
|
+
this.getter = getter;
|
|
301
|
+
this.getTriggers = () => [new GroupMembershipTrigger(this.getter)];
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
exports.EditGroupAction = EditGroupAction;
|
|
305
|
+
async function verifyGroupMembers(group, members) {
|
|
306
|
+
const memberEdges = await (0, ent_1.loadEdges)({
|
|
307
|
+
edgeType: "workspaceMember",
|
|
308
|
+
id1: group.id,
|
|
309
|
+
});
|
|
310
|
+
const memberIDs = members.map((ent) => ent.id);
|
|
311
|
+
expect(memberIDs.sort()).toEqual(memberEdges.map((edge) => edge.id2).sort());
|
|
312
|
+
// @ts-ignore
|
|
313
|
+
const membershipids = memberEdges
|
|
314
|
+
.map((edge) => edge.data)
|
|
315
|
+
.filter((str) => str !== null && str !== undefined);
|
|
316
|
+
return membershipids;
|
|
317
|
+
}
|
|
318
|
+
exports.verifyGroupMembers = verifyGroupMembers;
|
|
319
|
+
async function loadMemberships(viewer, membershipids) {
|
|
320
|
+
const tableName = (0, builder_1.getTableName)(exports.GroupMembershipSchema);
|
|
321
|
+
const ents = await (0, ent_1.loadEnts)(viewer, {
|
|
322
|
+
tableName,
|
|
323
|
+
ent: GroupMembership,
|
|
324
|
+
fields: ["id", "owner_id", "added_by", "notifications_enabled"],
|
|
325
|
+
loaderFactory: new object_loader_1.ObjectLoaderFactory({
|
|
326
|
+
tableName,
|
|
327
|
+
fields: ["id", "owner_id", "added_by", "notifications_enabled"],
|
|
328
|
+
key: "id",
|
|
329
|
+
}),
|
|
330
|
+
}, ...membershipids);
|
|
331
|
+
return Array.from(ents.values());
|
|
332
|
+
}
|
|
333
|
+
exports.loadMemberships = loadMemberships;
|
|
334
|
+
async function loadChangelogs(viewer, clids) {
|
|
335
|
+
const ents = await (0, ent_1.loadEnts)(viewer, {
|
|
336
|
+
tableName: "changelogs",
|
|
337
|
+
ent: Changelog,
|
|
338
|
+
fields: ["id", "parent_id", "log"],
|
|
339
|
+
loaderFactory: new object_loader_1.ObjectLoaderFactory({
|
|
340
|
+
tableName: "changelogs",
|
|
341
|
+
fields: ["id", "parent_id", "log"],
|
|
342
|
+
key: "id",
|
|
343
|
+
}),
|
|
344
|
+
}, ...clids);
|
|
345
|
+
return Array.from(ents.values());
|
|
346
|
+
}
|
|
347
|
+
exports.loadChangelogs = loadChangelogs;
|
|
348
|
+
async function verifyChangelogFromMeberships(user, memberships) {
|
|
349
|
+
await Promise.all(memberships.map(async (membership) => {
|
|
350
|
+
const edges = await (0, ent_1.loadEdges)({
|
|
351
|
+
edgeType: "objectToChangelog",
|
|
352
|
+
id1: membership.id,
|
|
353
|
+
});
|
|
354
|
+
expect(edges.length).toBe(1);
|
|
355
|
+
const clIDs = edges.map((edge) => edge.id2);
|
|
356
|
+
const cls = await loadChangelogs(user.viewer, clIDs);
|
|
357
|
+
expect(cls.length).toBe(1);
|
|
358
|
+
const cl = cls[0];
|
|
359
|
+
expect(edges[0].id2).toBe(cl.id);
|
|
360
|
+
expect((0, convert_1.convertJSON)(cl.data.log)).toMatchObject({
|
|
361
|
+
// also has ownerID...
|
|
362
|
+
addedBy: user.id,
|
|
363
|
+
notificationsEnabled: true,
|
|
364
|
+
});
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
exports.verifyChangelogFromMeberships = verifyChangelogFromMeberships;
|
|
368
|
+
class GroupMemberOf extends builder_1.BaseEnt {
|
|
369
|
+
constructor() {
|
|
370
|
+
super(...arguments);
|
|
371
|
+
this.nodeType = "GroupMemberOf";
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
exports.GroupMemberOf = GroupMemberOf;
|
|
375
|
+
exports.GroupMemberOfSchema = (0, builder_1.getBuilderSchemaFromFields)({
|
|
376
|
+
userID: (0, field_1.UUIDType)({ index: true }),
|
|
377
|
+
addedBy: (0, field_1.UUIDType)(),
|
|
378
|
+
groupID: (0, field_1.UUIDType)(),
|
|
379
|
+
notificationsEnabled: (0, field_1.BooleanType)(),
|
|
380
|
+
}, GroupMemberOf);
|
|
381
|
+
const getTables = () => {
|
|
382
|
+
const tables = [(0, temp_db_1.assoc_edge_config_table)()];
|
|
383
|
+
edges.map((edge) => tables.push((0, temp_db_1.assoc_edge_table)(`${edge}_table`)));
|
|
384
|
+
[
|
|
385
|
+
exports.AccountSchema,
|
|
386
|
+
exports.ContactSchema,
|
|
387
|
+
exports.GroupSchema,
|
|
388
|
+
exports.UserSchema,
|
|
389
|
+
exports.MessageSchema,
|
|
390
|
+
exports.GroupMembershipSchema,
|
|
391
|
+
exports.ChangelogSchema,
|
|
392
|
+
exports.GroupMemberOfSchema,
|
|
393
|
+
exports.UserBalanceSchema,
|
|
394
|
+
exports.UserBalanceWithCheckSchema,
|
|
395
|
+
].map((s) => tables.push((0, temp_db_1.getSchemaTable)(s, db_1.Dialect.SQLite)));
|
|
396
|
+
return tables;
|
|
397
|
+
};
|
|
398
|
+
exports.getTables = getTables;
|