@lobb-js/core 0.13.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/package.json +48 -0
- package/src/Lobb.ts +150 -0
- package/src/LobbError.ts +105 -0
- package/src/TypesGenerator.ts +11 -0
- package/src/api/WebServer.ts +126 -0
- package/src/api/collections/CollectionControllers.ts +485 -0
- package/src/api/collections/CollectionService.ts +162 -0
- package/src/api/collections/collectionRoutes.ts +105 -0
- package/src/api/collections/collectionStore.ts +647 -0
- package/src/api/collections/transactions.ts +166 -0
- package/src/api/collections/utils.ts +73 -0
- package/src/api/errorHandler.ts +73 -0
- package/src/api/events/index.ts +129 -0
- package/src/api/meta/route.ts +66 -0
- package/src/api/meta/service.ts +163 -0
- package/src/api/middlewares.ts +71 -0
- package/src/api/openApiRoute.ts +1017 -0
- package/src/api/schema/SchemaService.ts +71 -0
- package/src/api/schema/schemaRoutes.ts +13 -0
- package/src/config/ConfigManager.ts +252 -0
- package/src/config/validations.ts +49 -0
- package/src/coreCollections/collectionsCollection.ts +56 -0
- package/src/coreCollections/index.ts +14 -0
- package/src/coreCollections/migrationsCollection.ts +36 -0
- package/src/coreCollections/queryCollection.ts +26 -0
- package/src/coreCollections/workflowsCollection.ts +73 -0
- package/src/coreDbSetup/index.ts +72 -0
- package/src/coreMigrations/index.ts +3 -0
- package/src/database/DatabaseService.ts +44 -0
- package/src/database/DatabaseSyncManager.ts +173 -0
- package/src/database/MigrationsManager.ts +95 -0
- package/src/database/drivers/MongoDriver.ts +750 -0
- package/src/database/drivers/pgDriver/PGDriver.ts +655 -0
- package/src/database/drivers/pgDriver/QueryBuilder.ts +474 -0
- package/src/database/drivers/pgDriver/utils.ts +6 -0
- package/src/events/EventSystem.ts +191 -0
- package/src/events/coreEvents/index.ts +218 -0
- package/src/events/studioEvents/index.ts +32 -0
- package/src/extension/ExtensionSystem.ts +236 -0
- package/src/extension/dashboardRoute.ts +35 -0
- package/src/fields/ArrayField.ts +33 -0
- package/src/fields/BoolField.ts +34 -0
- package/src/fields/DateField.ts +13 -0
- package/src/fields/DateTimeField.ts +13 -0
- package/src/fields/DecimalField.ts +13 -0
- package/src/fields/FieldUtils.ts +56 -0
- package/src/fields/FloatField.ts +13 -0
- package/src/fields/IntegerField.ts +13 -0
- package/src/fields/LongField.ts +13 -0
- package/src/fields/ObjectField.ts +15 -0
- package/src/fields/StringField.ts +13 -0
- package/src/fields/TextField.ts +13 -0
- package/src/fields/TimeField.ts +13 -0
- package/src/index.ts +53 -0
- package/src/studio/Studio.ts +108 -0
- package/src/types/CollectionControllers.ts +15 -0
- package/src/types/DatabaseDriver.ts +115 -0
- package/src/types/Extension.ts +46 -0
- package/src/types/Field.ts +29 -0
- package/src/types/apiSchema.ts +12 -0
- package/src/types/collectionServiceSchema.ts +18 -0
- package/src/types/config/collectionFields.ts +85 -0
- package/src/types/config/collectionsConfig.ts +50 -0
- package/src/types/config/config.ts +66 -0
- package/src/types/config/relations.ts +17 -0
- package/src/types/filterSchema.ts +88 -0
- package/src/types/index.ts +38 -0
- package/src/types/migrations.ts +12 -0
- package/src/types/websockets.ts +34 -0
- package/src/types/workflows/processors.ts +1 -0
- package/src/utils/lockCollectionToObject.ts +204 -0
- package/src/utils/utils.ts +310 -0
- package/src/workflows/WorkflowSystem.ts +182 -0
- package/src/workflows/coreWorkflows/collectionsTable/index.ts +118 -0
- package/src/workflows/coreWorkflows/index.ts +18 -0
- package/src/workflows/coreWorkflows/processors/postOperationsWorkflows.ts +46 -0
- package/src/workflows/coreWorkflows/processors/preOperationsWorkflows.ts +27 -0
- package/src/workflows/coreWorkflows/processors/processorForDB.ts +13 -0
- package/src/workflows/coreWorkflows/processors/processors/processor.ts +23 -0
- package/src/workflows/coreWorkflows/processors/processors/processorsFunctions.ts +47 -0
- package/src/workflows/coreWorkflows/processors/utils.ts +102 -0
- package/src/workflows/coreWorkflows/processors/validator/validator.ts +19 -0
- package/src/workflows/coreWorkflows/processors/validator/validatorsFunction.ts +52 -0
- package/src/workflows/coreWorkflows/queryCoreWorkflows.ts +31 -0
- package/src/workflows/coreWorkflows/utilsCoreWorkflows.ts +40 -0
- package/src/workflows/coreWorkflows/workflowsCollection/workflowsCollectionWorkflows.ts +101 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import type { Context } from "hono";
|
|
2
|
+
import type { ApiCollectionAction } from "../types/index.ts";
|
|
3
|
+
import type { ProcessorType } from "../types/index.ts";
|
|
4
|
+
import type { CollectionFieldBase } from "../types/index.ts";
|
|
5
|
+
import type { CollectionConfig, CollectionsConfig } from "../types/index.ts";
|
|
6
|
+
import type { PoolClient } from "pg";
|
|
7
|
+
|
|
8
|
+
import _ from "lodash";
|
|
9
|
+
import nunjucks from "nunjucks";
|
|
10
|
+
import { transform } from "sucrase";
|
|
11
|
+
import { LobbError } from "../LobbError.ts";
|
|
12
|
+
import { FieldUtils } from "../fields/FieldUtils.ts";
|
|
13
|
+
import { coreCollections } from "../coreCollections/index.ts";
|
|
14
|
+
import { Lobb } from "../Lobb.ts";
|
|
15
|
+
import {
|
|
16
|
+
processPayloadWithSchema,
|
|
17
|
+
validatePayloadWithSchema,
|
|
18
|
+
} from "../workflows/coreWorkflows/processors/utils.ts";
|
|
19
|
+
import { createTypeAlias, printNode, zodToTs } from "zod-to-ts";
|
|
20
|
+
import {
|
|
21
|
+
innerLockCollectionToObject,
|
|
22
|
+
LockCollectionToObjectProps,
|
|
23
|
+
} from "./lockCollectionToObject.ts";
|
|
24
|
+
|
|
25
|
+
export const Utils = {
|
|
26
|
+
isPlainInteger(value: any): boolean {
|
|
27
|
+
return (
|
|
28
|
+
_.isNumber(value) &&
|
|
29
|
+
_.isInteger(value) &&
|
|
30
|
+
value >= Number.MIN_SAFE_INTEGER &&
|
|
31
|
+
value <= Number.MAX_SAFE_INTEGER
|
|
32
|
+
);
|
|
33
|
+
},
|
|
34
|
+
setRequestBody(c: Context, data: any) {
|
|
35
|
+
c.set("body", data);
|
|
36
|
+
},
|
|
37
|
+
async getRequestBody(c: Context): Promise<any> {
|
|
38
|
+
// return the passed body if existed
|
|
39
|
+
const passedBody = c.get("body");
|
|
40
|
+
if (passedBody) {
|
|
41
|
+
return passedBody;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const contentType = c.req.header("Content-Type");
|
|
45
|
+
if (contentType) {
|
|
46
|
+
if (contentType.startsWith("multipart/form-data")) {
|
|
47
|
+
const formData = await c.req.formData();
|
|
48
|
+
let payload = formData.get("payload")?.toString();
|
|
49
|
+
if (!payload) {
|
|
50
|
+
payload = "{}";
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(payload);
|
|
54
|
+
} catch (_error) {
|
|
55
|
+
throw new LobbError({
|
|
56
|
+
code: "BAD_REQUEST",
|
|
57
|
+
message:
|
|
58
|
+
"couldn't JSON.parse the data property in the multipart/form-data.",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
} else if (contentType.startsWith("application/json")) {
|
|
62
|
+
return await c.req.json();
|
|
63
|
+
} else if (contentType.startsWith("text/plain")) {
|
|
64
|
+
try {
|
|
65
|
+
return await c.req.json();
|
|
66
|
+
} catch (_error) {
|
|
67
|
+
return await c.req.text();
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
throw new LobbError({
|
|
71
|
+
code: "BAD_REQUEST",
|
|
72
|
+
message: "request body is not valid json.",
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
} else {
|
|
76
|
+
try {
|
|
77
|
+
return JSON.parse(await c.req.text());
|
|
78
|
+
} catch (_error) {
|
|
79
|
+
const textValue = await c.req.text();
|
|
80
|
+
if (!textValue) {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
return textValue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
getApiCollectionAction(c: Context): ApiCollectionAction {
|
|
88
|
+
const pathSegments = c.req.path.split("/");
|
|
89
|
+
const pathSegmentsLength = pathSegments.length;
|
|
90
|
+
const pathSegmentsLastElement = pathSegments[pathSegmentsLength - 1];
|
|
91
|
+
const isMany = pathSegmentsLastElement === "many";
|
|
92
|
+
if (
|
|
93
|
+
c.req.method === "GET" &&
|
|
94
|
+
pathSegmentsLength === 4 &&
|
|
95
|
+
!isMany
|
|
96
|
+
) {
|
|
97
|
+
return "findAll";
|
|
98
|
+
} else if (
|
|
99
|
+
c.req.method === "POST" &&
|
|
100
|
+
pathSegmentsLength === 5 &&
|
|
101
|
+
!isMany
|
|
102
|
+
) {
|
|
103
|
+
return "findAll";
|
|
104
|
+
} else if (
|
|
105
|
+
c.req.method === "GET" &&
|
|
106
|
+
pathSegmentsLength === 5 &&
|
|
107
|
+
!isMany
|
|
108
|
+
) {
|
|
109
|
+
return "findOne";
|
|
110
|
+
} else if (
|
|
111
|
+
c.req.method === "DELETE" &&
|
|
112
|
+
pathSegmentsLength === 5 &&
|
|
113
|
+
!isMany
|
|
114
|
+
) {
|
|
115
|
+
return "deleteOne";
|
|
116
|
+
} else if (
|
|
117
|
+
c.req.method === "POST" &&
|
|
118
|
+
pathSegmentsLength === 4 &&
|
|
119
|
+
!isMany
|
|
120
|
+
) {
|
|
121
|
+
return "createOne";
|
|
122
|
+
} else if (
|
|
123
|
+
c.req.method === "PATCH" &&
|
|
124
|
+
pathSegmentsLength === 5 &&
|
|
125
|
+
!isMany
|
|
126
|
+
) {
|
|
127
|
+
return "updateOne";
|
|
128
|
+
} else if (
|
|
129
|
+
c.req.method === "DELETE" &&
|
|
130
|
+
pathSegmentsLength === 5 &&
|
|
131
|
+
isMany
|
|
132
|
+
) {
|
|
133
|
+
return "deleteMany";
|
|
134
|
+
} else if (
|
|
135
|
+
c.req.method === "PATCH" &&
|
|
136
|
+
pathSegmentsLength === 5 &&
|
|
137
|
+
isMany
|
|
138
|
+
) {
|
|
139
|
+
return "updateMany";
|
|
140
|
+
} else if (
|
|
141
|
+
c.req.method === "POST" &&
|
|
142
|
+
pathSegmentsLength === 5 &&
|
|
143
|
+
isMany
|
|
144
|
+
) {
|
|
145
|
+
return "createMany";
|
|
146
|
+
} else {
|
|
147
|
+
throw new LobbError({
|
|
148
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
149
|
+
message: "can't get the api collection action",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
sleep(ms: number) {
|
|
154
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
155
|
+
},
|
|
156
|
+
renderTemplateDeep(data: any, context: any) {
|
|
157
|
+
return _.cloneDeepWith(data, (value: any) => {
|
|
158
|
+
if (typeof value === "function") {
|
|
159
|
+
return value(context);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (typeof value === "string") {
|
|
163
|
+
return nunjucks.renderString(value, context);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
fieldExists(
|
|
168
|
+
fieldName: string,
|
|
169
|
+
collectionName: string,
|
|
170
|
+
): boolean {
|
|
171
|
+
return Lobb.instance.configManager.fieldExists(fieldName, collectionName);
|
|
172
|
+
},
|
|
173
|
+
moveElementAfter(
|
|
174
|
+
array: any[],
|
|
175
|
+
moveIndex: number,
|
|
176
|
+
afterIndex: number,
|
|
177
|
+
) {
|
|
178
|
+
if (moveIndex < 0 || moveIndex >= array.length) {
|
|
179
|
+
throw new LobbError({
|
|
180
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
181
|
+
message: `Invalid moveIndex: ${moveIndex}.`,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
if (afterIndex < 0 || afterIndex >= array.length) {
|
|
185
|
+
throw new LobbError({
|
|
186
|
+
code: "INTERNAL_SERVER_ERROR",
|
|
187
|
+
message: `Invalid afterIndex: ${afterIndex}.`,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const [movedElement] = array.splice(moveIndex, 1);
|
|
192
|
+
const insertIndex = afterIndex >= moveIndex ? afterIndex : afterIndex + 1;
|
|
193
|
+
array.splice(insertIndex, 0, movedElement);
|
|
194
|
+
|
|
195
|
+
return array;
|
|
196
|
+
},
|
|
197
|
+
processDocumentsForDb(
|
|
198
|
+
type: "encode" | "decode",
|
|
199
|
+
collectionName: string,
|
|
200
|
+
data: any,
|
|
201
|
+
) {
|
|
202
|
+
const isArray = Array.isArray(data);
|
|
203
|
+
const entries = isArray ? data : [data];
|
|
204
|
+
for (let index = 0; index < entries.length; index++) {
|
|
205
|
+
for (const fieldName of Object.keys(entries[index])) {
|
|
206
|
+
const fieldValue = entries[index][fieldName];
|
|
207
|
+
if (fieldValue === null) {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const doesFieldExists = Lobb.instance.configManager.fieldExists(
|
|
211
|
+
fieldName,
|
|
212
|
+
collectionName,
|
|
213
|
+
);
|
|
214
|
+
if (!doesFieldExists) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
const field = FieldUtils.getFieldInstance(
|
|
218
|
+
fieldName,
|
|
219
|
+
collectionName,
|
|
220
|
+
);
|
|
221
|
+
let result;
|
|
222
|
+
if (type === "encode") {
|
|
223
|
+
result = field.encodeFieldValue(fieldValue);
|
|
224
|
+
} else {
|
|
225
|
+
result = field.decodeFieldValue(fieldValue);
|
|
226
|
+
}
|
|
227
|
+
if (result !== undefined) {
|
|
228
|
+
entries[index][fieldName] = result;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return isArray ? entries : entries[0];
|
|
234
|
+
},
|
|
235
|
+
getCollectionOwner(collectionName: string) {
|
|
236
|
+
const lobbInstance = Lobb.instance;
|
|
237
|
+
const owner = lobbInstance.extensionSystem.getCollectionOwner(
|
|
238
|
+
collectionName,
|
|
239
|
+
);
|
|
240
|
+
if (owner) {
|
|
241
|
+
return owner;
|
|
242
|
+
}
|
|
243
|
+
const coreCollectionNames = Object.keys(coreCollections());
|
|
244
|
+
if (coreCollectionNames.includes(collectionName)) {
|
|
245
|
+
return "__core";
|
|
246
|
+
}
|
|
247
|
+
return "__project";
|
|
248
|
+
},
|
|
249
|
+
processPayloadWithSchema(
|
|
250
|
+
type: ProcessorType,
|
|
251
|
+
data: any,
|
|
252
|
+
fieldsSchema: Record<string, CollectionFieldBase>,
|
|
253
|
+
processAllFields: boolean = false,
|
|
254
|
+
context: any,
|
|
255
|
+
) {
|
|
256
|
+
return processPayloadWithSchema(
|
|
257
|
+
type,
|
|
258
|
+
data,
|
|
259
|
+
fieldsSchema,
|
|
260
|
+
processAllFields,
|
|
261
|
+
context,
|
|
262
|
+
);
|
|
263
|
+
},
|
|
264
|
+
validatePayloadWithSchema(
|
|
265
|
+
data: any,
|
|
266
|
+
fieldsSchema: Record<string, CollectionFieldBase>,
|
|
267
|
+
processAllFields: boolean,
|
|
268
|
+
context: any,
|
|
269
|
+
): Promise<any> {
|
|
270
|
+
return validatePayloadWithSchema(
|
|
271
|
+
data,
|
|
272
|
+
fieldsSchema,
|
|
273
|
+
processAllFields,
|
|
274
|
+
context,
|
|
275
|
+
);
|
|
276
|
+
},
|
|
277
|
+
parseFunction(functionString: string) {
|
|
278
|
+
const { code: vanillaJsFunctionString } = transform(functionString, {
|
|
279
|
+
transforms: ["typescript"],
|
|
280
|
+
});
|
|
281
|
+
const functionObj = new Function("return " + vanillaJsFunctionString)();
|
|
282
|
+
return functionObj;
|
|
283
|
+
},
|
|
284
|
+
async runParsedFunction(
|
|
285
|
+
functionString: string,
|
|
286
|
+
...params: any[]
|
|
287
|
+
): Promise<any> {
|
|
288
|
+
const func = this.parseFunction(functionString);
|
|
289
|
+
return await func(...params);
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
lockCollectionToObject(
|
|
293
|
+
props: LockCollectionToObjectProps,
|
|
294
|
+
): CollectionConfig {
|
|
295
|
+
return innerLockCollectionToObject(props);
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export function convertSchemaToTypeString(
|
|
300
|
+
identifier: string,
|
|
301
|
+
schema: any,
|
|
302
|
+
): string {
|
|
303
|
+
const { node } = zodToTs(schema);
|
|
304
|
+
const typeAlias = createTypeAlias(
|
|
305
|
+
node,
|
|
306
|
+
identifier,
|
|
307
|
+
);
|
|
308
|
+
const nodeString = printNode(typeAlias);
|
|
309
|
+
return nodeString;
|
|
310
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { Subscription } from "../events/EventSystem.ts";
|
|
2
|
+
import type { ZodObject } from "zod";
|
|
3
|
+
import type { z } from "zod";
|
|
4
|
+
import { getCoreWorkflows } from "./coreWorkflows/index.ts";
|
|
5
|
+
import { Lobb } from "../Lobb.ts";
|
|
6
|
+
import { LobbError } from "../LobbError.ts";
|
|
7
|
+
import { TransactionBody } from "../api/collections/transactions.ts";
|
|
8
|
+
|
|
9
|
+
export interface Workflow {
|
|
10
|
+
name: string;
|
|
11
|
+
handler: Subscription["handler"];
|
|
12
|
+
eventName?: string;
|
|
13
|
+
inputSchema?: (zodObject: typeof z) => ZodObject<any>;
|
|
14
|
+
outputSchema?: (zodObject: typeof z) => ZodObject<any>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class WorkflowSystem {
|
|
18
|
+
public initialized: boolean = false;
|
|
19
|
+
public workflows: Workflow[] = [];
|
|
20
|
+
public queuedWorkflows: Workflow[] = [];
|
|
21
|
+
|
|
22
|
+
public async init() {
|
|
23
|
+
// get current project workflows
|
|
24
|
+
this.initialized = true;
|
|
25
|
+
this.addQueuedWorkflows();
|
|
26
|
+
await this.registerCollectionsWorkflows();
|
|
27
|
+
await this.importExtensionWorkflows();
|
|
28
|
+
await this.importProjectWorkflows();
|
|
29
|
+
await this.importCoreWorkflows();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public close() {
|
|
33
|
+
this.workflows = [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public trigger(workflow: Workflow) {
|
|
37
|
+
// TODO
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public add(workflow: Workflow) {
|
|
41
|
+
if (this.initialized) {
|
|
42
|
+
if (this.workflowExist(workflow.name)) {
|
|
43
|
+
throw new LobbError({
|
|
44
|
+
code: "BAD_REQUEST",
|
|
45
|
+
message:
|
|
46
|
+
`The workflow with the (${workflow.name}) name already exists`,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (workflow.eventName) {
|
|
50
|
+
Lobb.instance.eventSystem.subscribe({
|
|
51
|
+
name: `${workflow.name}_${workflow.eventName}`,
|
|
52
|
+
eventName: workflow.eventName,
|
|
53
|
+
handler: workflow.handler,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
this.workflows.push(workflow);
|
|
57
|
+
} else {
|
|
58
|
+
this.queuedWorkflows.push(workflow);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public async update(workflowName: string, newWorkflow: Workflow) {
|
|
63
|
+
await this.remove(workflowName);
|
|
64
|
+
await this.add(newWorkflow);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public async remove(workflowName: string) {
|
|
68
|
+
const workflowWeWillRemove = this.workflows.find(
|
|
69
|
+
(workflow) => workflow.name === workflowName,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
if (!workflowWeWillRemove) {
|
|
73
|
+
throw new LobbError({
|
|
74
|
+
code: "BAD_REQUEST",
|
|
75
|
+
message: `The (${workflowName}) workflow doesnt exist`,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.workflows = this.workflows.filter(
|
|
80
|
+
(workflow) => workflow.name !== workflowName,
|
|
81
|
+
);
|
|
82
|
+
// remove events that were issues by the workflow
|
|
83
|
+
await Lobb.instance.eventSystem.unsubscribe(
|
|
84
|
+
`${workflowWeWillRemove.name}_${workflowWeWillRemove.eventName}`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public workflowExist(workflowName: string) {
|
|
89
|
+
return this.workflows.some((workflow) => workflow.name === workflowName);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private async addQueuedWorkflows() {
|
|
93
|
+
for (let index = 0; index < this.queuedWorkflows.length; index++) {
|
|
94
|
+
const queuedWorkflow = this.queuedWorkflows[index];
|
|
95
|
+
await this.add(queuedWorkflow);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private async importCoreWorkflows() {
|
|
100
|
+
const coreWorkflows = getCoreWorkflows();
|
|
101
|
+
for (let index = 0; index < coreWorkflows.length; index++) {
|
|
102
|
+
const coreWorkflow = coreWorkflows[index];
|
|
103
|
+
if (!coreWorkflow.name.startsWith("core")) {
|
|
104
|
+
throw new LobbError({
|
|
105
|
+
code: "BAD_REQUEST",
|
|
106
|
+
message:
|
|
107
|
+
`The (${coreWorkflow.name}) workflow should start with the (core) prefix`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
await this.add(coreWorkflow);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private async importExtensionWorkflows() {
|
|
115
|
+
const extensionNames = Lobb.instance.configManager.getExtensionNames();
|
|
116
|
+
for (let index = 0; index < extensionNames.length; index++) {
|
|
117
|
+
const extensionName = extensionNames[index];
|
|
118
|
+
const extensionWorkflows = Lobb.instance.extensionSystem.getWorkflows(
|
|
119
|
+
extensionName,
|
|
120
|
+
);
|
|
121
|
+
for (let index = 0; index < extensionWorkflows.length; index++) {
|
|
122
|
+
const extensionWorkflow = extensionWorkflows[index];
|
|
123
|
+
if (!extensionWorkflow.name.startsWith(`${extensionName}`)) {
|
|
124
|
+
throw new LobbError({
|
|
125
|
+
code: "BAD_REQUEST",
|
|
126
|
+
message:
|
|
127
|
+
`The (${extensionWorkflow.name}) workflow should start with the (${extensionName}) prefix`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
await this.add(extensionWorkflow);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private async importProjectWorkflows() {
|
|
136
|
+
const workflows = Lobb.instance.configManager.config.workflows;
|
|
137
|
+
if (workflows) {
|
|
138
|
+
for (let index = 0; index < workflows.length; index++) {
|
|
139
|
+
const coreWorkflow = workflows[index];
|
|
140
|
+
await this.add(coreWorkflow);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public async registerCollectionsWorkflows() {
|
|
146
|
+
await this.add({
|
|
147
|
+
name: `collectionService`,
|
|
148
|
+
handler: async (input: TransactionBody) => {
|
|
149
|
+
if (input.method === "findAll") {
|
|
150
|
+
return await Lobb.instance.collectionService.findAll(input.props);
|
|
151
|
+
} else if (input.method === "findOne") {
|
|
152
|
+
return await Lobb.instance.collectionService.findOne(input.props);
|
|
153
|
+
} else if (input.method === "createOne") {
|
|
154
|
+
return await Lobb.instance.collectionService.createOne(input.props);
|
|
155
|
+
} else if (input.method === "updateOne") {
|
|
156
|
+
return await Lobb.instance.collectionService.updateOne(input.props);
|
|
157
|
+
} else if (input.method === "deleteOne") {
|
|
158
|
+
return await Lobb.instance.collectionService.deleteOne(input.props);
|
|
159
|
+
} else if (input.method === "readSingleton") {
|
|
160
|
+
return await Lobb.instance.collectionService.readSingleton(
|
|
161
|
+
input.props,
|
|
162
|
+
);
|
|
163
|
+
} else if (input.method === "updateSingleton") {
|
|
164
|
+
return await Lobb.instance.collectionService.updateSingleton(
|
|
165
|
+
input.props,
|
|
166
|
+
);
|
|
167
|
+
} else if (input.method === "createMany") {
|
|
168
|
+
return await Lobb.instance.collectionService.createMany(input.props);
|
|
169
|
+
} else if (input.method === "updateMany") {
|
|
170
|
+
return await Lobb.instance.collectionService.updateMany(input.props);
|
|
171
|
+
} else if (input.method === "deleteMany") {
|
|
172
|
+
return await Lobb.instance.collectionService.deleteMany(input.props);
|
|
173
|
+
} else {
|
|
174
|
+
throw new LobbError({
|
|
175
|
+
code: "BAD_REQUEST",
|
|
176
|
+
message: `The (${(input as any).method}) method is not supported`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Lobb } from "../../../Lobb.ts";
|
|
2
|
+
import type { Workflow } from "../../WorkflowSystem.ts";
|
|
3
|
+
import { Utils } from "../../../utils/utils.ts";
|
|
4
|
+
|
|
5
|
+
let oldCollectionName: string | null = null;
|
|
6
|
+
|
|
7
|
+
async function getCollectionNameById(id: string): Promise<string> {
|
|
8
|
+
const result = await Lobb.instance.collectionService.findOne({
|
|
9
|
+
collectionName: "core_collections",
|
|
10
|
+
id,
|
|
11
|
+
});
|
|
12
|
+
const collectionName = result.data.name;
|
|
13
|
+
return collectionName;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getCollectionsTableWorkflows(): Workflow[] {
|
|
17
|
+
const workflows: Workflow[] = [];
|
|
18
|
+
|
|
19
|
+
workflows.push({
|
|
20
|
+
name: `core_move_collections_from_db_to_lobb`,
|
|
21
|
+
eventName: "core.init",
|
|
22
|
+
handler: async () => {
|
|
23
|
+
const dbCollections = (await Lobb.instance.collectionService.findAll({
|
|
24
|
+
collectionName: "core_collections",
|
|
25
|
+
})).data;
|
|
26
|
+
for (let index = 0; index < dbCollections.length; index++) {
|
|
27
|
+
const collectionEntry = dbCollections[index];
|
|
28
|
+
const collectionParsedValue = await Utils.runParsedFunction(
|
|
29
|
+
collectionEntry.value,
|
|
30
|
+
);
|
|
31
|
+
await Lobb.instance.schemaService.createCollection(
|
|
32
|
+
collectionEntry.name,
|
|
33
|
+
collectionParsedValue,
|
|
34
|
+
false,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
workflows.push({
|
|
41
|
+
name: "core_add_created_db_collection",
|
|
42
|
+
eventName: "core.store.createOne",
|
|
43
|
+
handler: async (input) => {
|
|
44
|
+
if (input.collectionName === "core_collections") {
|
|
45
|
+
const collectionEntry = input.data;
|
|
46
|
+
const collectionParsedValue = await Utils.runParsedFunction(
|
|
47
|
+
collectionEntry.value,
|
|
48
|
+
);
|
|
49
|
+
await Lobb.instance.schemaService.createCollection(
|
|
50
|
+
collectionEntry.name,
|
|
51
|
+
collectionParsedValue,
|
|
52
|
+
false,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return input;
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
workflows.push({
|
|
60
|
+
name: "core_handle_db_collection_pre_update",
|
|
61
|
+
eventName: "core.store.preUpdateOne",
|
|
62
|
+
handler: async (input) => {
|
|
63
|
+
if (input.collectionName === "core_collections") {
|
|
64
|
+
oldCollectionName = await getCollectionNameById(input.id);
|
|
65
|
+
}
|
|
66
|
+
return input;
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
workflows.push({
|
|
71
|
+
name: "core_handle_db_collection_post_update",
|
|
72
|
+
eventName: "core.store.updateOne",
|
|
73
|
+
handler: async (input) => {
|
|
74
|
+
if (input.collectionName === "core_collections") {
|
|
75
|
+
const payload = input.data;
|
|
76
|
+
const collectionName = payload.name;
|
|
77
|
+
const collectionParsedValue = await Utils.runParsedFunction(
|
|
78
|
+
payload.value,
|
|
79
|
+
);
|
|
80
|
+
if (oldCollectionName && oldCollectionName !== collectionName) {
|
|
81
|
+
await Lobb.instance.schemaService.deleteCollection(
|
|
82
|
+
oldCollectionName,
|
|
83
|
+
false,
|
|
84
|
+
);
|
|
85
|
+
await Lobb.instance.schemaService.createCollection(
|
|
86
|
+
collectionName,
|
|
87
|
+
collectionParsedValue,
|
|
88
|
+
false,
|
|
89
|
+
);
|
|
90
|
+
} else {
|
|
91
|
+
await Lobb.instance.schemaService.updateCollection(
|
|
92
|
+
collectionName,
|
|
93
|
+
collectionParsedValue,
|
|
94
|
+
false,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return input;
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
workflows.push({
|
|
103
|
+
name: "core_handle_db_collection_delete",
|
|
104
|
+
eventName: "core.store.deleteOne",
|
|
105
|
+
handler: async (input) => {
|
|
106
|
+
if (input.collectionName === "core_collections") {
|
|
107
|
+
const collectionEntry = input.data;
|
|
108
|
+
await Lobb.instance.schemaService.deleteCollection(
|
|
109
|
+
collectionEntry.name,
|
|
110
|
+
false,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return input;
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return workflows;
|
|
118
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Workflow } from "../WorkflowSystem.ts";
|
|
2
|
+
import { getCollectionsTableWorkflows } from "./collectionsTable/index.ts";
|
|
3
|
+
import { getUtilsCoreWorkflows } from "./utilsCoreWorkflows.ts";
|
|
4
|
+
import { postOperationsWorkflows } from "./processors/postOperationsWorkflows.ts";
|
|
5
|
+
import { preOperationsWorkflows } from "./processors/preOperationsWorkflows.ts";
|
|
6
|
+
import { coreWorkflowsCollectionWorkflows } from "./workflowsCollection/workflowsCollectionWorkflows.ts";
|
|
7
|
+
import { getQueryCoreWorkflows } from "./queryCoreWorkflows.ts";
|
|
8
|
+
|
|
9
|
+
export function getCoreWorkflows(): Array<Workflow> {
|
|
10
|
+
return [
|
|
11
|
+
...preOperationsWorkflows,
|
|
12
|
+
...postOperationsWorkflows,
|
|
13
|
+
...coreWorkflowsCollectionWorkflows,
|
|
14
|
+
...getCollectionsTableWorkflows(),
|
|
15
|
+
...getQueryCoreWorkflows(),
|
|
16
|
+
...getUtilsCoreWorkflows(),
|
|
17
|
+
];
|
|
18
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Workflow } from "../../WorkflowSystem.ts";
|
|
2
|
+
import { processorForDB } from "./processorForDB.ts";
|
|
3
|
+
import { processor } from "./processors/processor.ts";
|
|
4
|
+
|
|
5
|
+
export const postOperationsWorkflows: Workflow[] = [
|
|
6
|
+
{
|
|
7
|
+
name: "core_postProcessingForCreate",
|
|
8
|
+
eventName: "core.store.createOne",
|
|
9
|
+
handler: async (input) => {
|
|
10
|
+
input = processorForDB("decode", input);
|
|
11
|
+
input = await processor(input, "post_processors", true);
|
|
12
|
+
|
|
13
|
+
return input;
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "core_postProcessingForRead",
|
|
18
|
+
eventName: "core.store.findOne",
|
|
19
|
+
handler: async (input) => {
|
|
20
|
+
input = processorForDB("decode", input);
|
|
21
|
+
input = await processor(input, "post_processors", true);
|
|
22
|
+
|
|
23
|
+
return input;
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: "core_postProcessingForUpdate",
|
|
28
|
+
eventName: "core.store.updateOne",
|
|
29
|
+
handler: async (input) => {
|
|
30
|
+
input = processorForDB("decode", input);
|
|
31
|
+
input = await processor(input, "post_processors", true);
|
|
32
|
+
|
|
33
|
+
return input;
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "core_postProcessingForDelete",
|
|
38
|
+
eventName: "core.store.deleteOne",
|
|
39
|
+
handler: async (input) => {
|
|
40
|
+
input = processorForDB("decode", input);
|
|
41
|
+
input = await processor(input, "post_processors", true);
|
|
42
|
+
|
|
43
|
+
return input;
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Workflow } from "../../WorkflowSystem.ts";
|
|
2
|
+
import { processorForDB } from "./processorForDB.ts";
|
|
3
|
+
import { processor } from "./processors/processor.ts";
|
|
4
|
+
import { validator } from "./validator/validator.ts";
|
|
5
|
+
|
|
6
|
+
export const preOperationsWorkflows: Workflow[] = [
|
|
7
|
+
{
|
|
8
|
+
name: "core_preProcessingForPreCreate",
|
|
9
|
+
eventName: "core.store.preCreateOne",
|
|
10
|
+
handler: async (input) => {
|
|
11
|
+
input = await processor(input, "pre_processors", true);
|
|
12
|
+
await validator(input, true);
|
|
13
|
+
input = processorForDB("encode", input);
|
|
14
|
+
return input;
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "core_preProcessingForPreUpdate",
|
|
19
|
+
eventName: "core.store.preUpdateOne",
|
|
20
|
+
handler: async (input) => {
|
|
21
|
+
input = await processor(input, "pre_processors", false);
|
|
22
|
+
await validator(input, false);
|
|
23
|
+
input = processorForDB("encode", input);
|
|
24
|
+
return input;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
];
|