remult 0.22.3 → 0.22.4
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/esm/angular/interfaces/index.d.ts +1 -0
- package/esm/angular/interfaces/index.js +1 -0
- package/esm/angular/interfaces/src/column-collection.d.ts +70 -0
- package/esm/angular/interfaces/src/column-collection.js +341 -0
- package/esm/angular/interfaces/src/data-area-settings.d.ts +15 -0
- package/esm/angular/interfaces/src/data-area-settings.js +35 -0
- package/esm/angular/interfaces/src/data-control-interfaces.d.ts +36 -0
- package/esm/angular/interfaces/src/data-control-interfaces.js +57 -0
- package/esm/angular/interfaces/src/dataList.d.ts +13 -0
- package/esm/angular/interfaces/src/dataList.js +42 -0
- package/esm/angular/interfaces/src/filter-helper.d.ts +13 -0
- package/esm/angular/interfaces/src/filter-helper.js +59 -0
- package/esm/angular/interfaces/src/grid-settings.d.ts +145 -0
- package/esm/angular/interfaces/src/grid-settings.js +387 -0
- package/esm/angular/interfaces/src/public_api.d.ts +4 -0
- package/esm/angular/interfaces/src/public_api.js +4 -0
- package/esm/angular/src/angular/RemultAngularPluginsService.d.ts +4 -0
- package/esm/angular/src/angular/RemultAngularPluginsService.js +3 -0
- package/esm/angular/src/angular/data-control/data-control2.component.d.ts +49 -0
- package/esm/angular/src/angular/data-control/data-control2.component.js +138 -0
- package/esm/core/SseSubscriptionServer.d.ts +33 -0
- package/esm/core/SseSubscriptionServer.js +107 -0
- package/esm/core/assign.d.ts +1 -0
- package/esm/core/assign.js +5 -0
- package/esm/core/classType.d.ts +3 -0
- package/esm/core/classType.js +1 -0
- package/esm/core/index.d.ts +27 -0
- package/esm/core/index.js +25 -0
- package/esm/core/inputTypes.d.ts +9 -0
- package/esm/core/inputTypes.js +9 -0
- package/esm/core/live-query/data-provider-live-query-storage.d.ts +22 -0
- package/esm/core/live-query/data-provider-live-query-storage.js +71 -0
- package/esm/core/postgres/index.d.ts +2 -0
- package/esm/core/postgres/index.js +2 -0
- package/esm/core/postgres/postgres-data-provider.d.ts +36 -0
- package/esm/core/postgres/postgres-data-provider.js +120 -0
- package/esm/core/postgres/schema-builder.d.ts +17 -0
- package/esm/core/postgres/schema-builder.js +153 -0
- package/esm/core/remult-fresh.d.ts +17 -0
- package/esm/core/remult-fresh.js +29 -0
- package/esm/core/remult-knex/index.d.ts +30 -0
- package/esm/core/remult-knex/index.js +446 -0
- package/esm/core/remult-mongo.d.ts +24 -0
- package/esm/core/remult-mongo.js +254 -0
- package/esm/core/server/JsonEntityFileStorage.d.ts +10 -0
- package/esm/core/server/JsonEntityFileStorage.js +25 -0
- package/esm/core/server/core.d.ts +4 -0
- package/esm/core/server/core.js +4 -0
- package/esm/core/server/expressBridge.d.ts +182 -0
- package/esm/core/server/expressBridge.js +938 -0
- package/esm/core/server/index.d.ts +6 -0
- package/esm/core/server/index.js +9 -0
- package/esm/core/server/initAsyncHooks.d.ts +1 -0
- package/esm/core/server/initAsyncHooks.js +9 -0
- package/esm/core/server/initDataProvider.d.ts +2 -0
- package/esm/core/server/initDataProvider.js +14 -0
- package/esm/core/src/__EntityValueProvider.d.ts +11 -0
- package/esm/core/src/__EntityValueProvider.js +1 -0
- package/esm/core/src/__RowsOfDataForTesting.d.ts +3 -0
- package/esm/core/src/__RowsOfDataForTesting.js +1 -0
- package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +6 -0
- package/esm/core/src/backend-tests/backend-database-test-setup.backend-spec.js +147 -0
- package/{src → esm/core/src}/backend-tests/my-test.backend-spec.d.ts +1 -1
- package/esm/core/src/backend-tests/my-test.backend-spec.js +197 -0
- package/esm/core/src/backend-tests/test-http-server.backend-spec.d.ts +1 -0
- package/esm/core/src/backend-tests/test-http-server.backend-spec.js +167 -0
- package/esm/core/src/buildRestDataProvider.d.ts +31 -0
- package/esm/core/src/buildRestDataProvider.js +113 -0
- package/esm/core/src/column-interfaces.d.ts +154 -0
- package/esm/core/src/column-interfaces.js +7 -0
- package/esm/core/src/column.d.ts +58 -0
- package/esm/core/src/column.js +174 -0
- package/esm/core/src/context.d.ts +134 -0
- package/esm/core/src/context.js +286 -0
- package/esm/core/src/data-api.d.ts +39 -0
- package/esm/core/src/data-api.js +279 -0
- package/esm/core/src/data-interfaces.d.ts +41 -0
- package/esm/core/src/data-interfaces.js +12 -0
- package/esm/core/src/data-providers/array-entity-data-provider.d.ts +22 -0
- package/esm/core/src/data-providers/array-entity-data-provider.js +252 -0
- package/esm/core/src/data-providers/in-memory-database.d.ts +9 -0
- package/esm/core/src/data-providers/in-memory-database.js +14 -0
- package/esm/core/src/data-providers/json-data-provider.d.ts +12 -0
- package/esm/core/src/data-providers/json-data-provider.js +55 -0
- package/esm/core/src/data-providers/rest-data-provider.d.ts +49 -0
- package/esm/core/src/data-providers/rest-data-provider.js +256 -0
- package/esm/core/src/data-providers/sql-database.d.ts +33 -0
- package/esm/core/src/data-providers/sql-database.js +384 -0
- package/esm/core/src/data-providers/web-sql-data-provider.d.ts +24 -0
- package/esm/core/src/data-providers/web-sql-data-provider.js +143 -0
- package/esm/core/src/entity.d.ts +91 -0
- package/esm/core/src/entity.js +1 -0
- package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.d.ts +50 -0
- package/esm/core/src/filter/filter-consumer-bridge-to-sql-request.js +150 -0
- package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.d.ts +1 -0
- package/esm/core/src/filter/filter-consumer-bridge-to-url-builder.js +1 -0
- package/esm/core/src/filter/filter-interfaces.d.ts +85 -0
- package/esm/core/src/filter/filter-interfaces.js +477 -0
- package/esm/core/src/live-query/LiveQueryClient.d.ts +20 -0
- package/esm/core/src/live-query/LiveQueryClient.js +188 -0
- package/esm/core/src/live-query/SseSubscriptionClient.d.ts +5 -0
- package/esm/core/src/live-query/SseSubscriptionClient.js +86 -0
- package/esm/core/src/live-query/SubscriptionChannel.d.ts +72 -0
- package/esm/core/src/live-query/SubscriptionChannel.js +123 -0
- package/esm/core/src/live-query/SubscriptionServer.d.ts +53 -0
- package/esm/core/src/live-query/SubscriptionServer.js +111 -0
- package/esm/core/src/live-query/live-query-tests.spec.d.ts +6 -0
- package/esm/core/src/live-query/live-query-tests.spec.js +952 -0
- package/esm/core/src/remult-proxy.d.ts +35 -0
- package/esm/core/src/remult-proxy.js +113 -0
- package/esm/core/src/remult3/DecoratorReplacer.d.ts +10 -0
- package/esm/core/src/remult3/DecoratorReplacer.js +20 -0
- package/esm/core/src/remult3/RepositoryImplementation.d.ts +355 -0
- package/esm/core/src/remult3/RepositoryImplementation.js +2109 -0
- package/esm/core/src/remult3/index.d.ts +2 -0
- package/esm/core/src/remult3/index.js +2 -0
- package/esm/core/src/remult3/remult3.d.ts +395 -0
- package/esm/core/src/remult3/remult3.js +2 -0
- package/esm/core/src/server-action.d.ts +81 -0
- package/esm/core/src/server-action.js +394 -0
- package/esm/core/src/shared-tests/db-tests-setup.d.ts +32 -0
- package/esm/core/src/shared-tests/db-tests-setup.js +78 -0
- package/esm/core/src/shared-tests/db-tests.db-tests.d.ts +25 -0
- package/esm/core/src/shared-tests/db-tests.db-tests.js +810 -0
- package/esm/core/src/shared-tests/deleteAll.d.ts +2 -0
- package/esm/core/src/shared-tests/deleteAll.js +4 -0
- package/esm/core/src/shared-tests/entityWithValidations.d.ts +14 -0
- package/esm/core/src/shared-tests/entityWithValidations.js +43 -0
- package/esm/core/src/shared-tests/index.d.ts +4 -0
- package/esm/core/src/shared-tests/index.js +4 -0
- package/esm/core/src/shared-tests/test-custom-id-column.spec.d.ts +1 -0
- package/esm/core/src/shared-tests/test-custom-id-column.spec.js +67 -0
- package/esm/core/src/shared-tests/test-special-value.spec.d.ts +10 -0
- package/esm/core/src/shared-tests/test-special-value.spec.js +73 -0
- package/esm/core/src/shared-tests/test-update-with-null.spec.d.ts +1 -0
- package/esm/core/src/shared-tests/test-update-with-null.spec.js +31 -0
- package/esm/core/src/sort.d.ts +16 -0
- package/esm/core/src/sort.js +103 -0
- package/esm/core/src/sql-command.d.ts +19 -0
- package/esm/core/src/sql-command.js +1 -0
- package/esm/core/src/test.d.ts +3 -0
- package/esm/core/src/test.js +12 -0
- package/esm/core/src/tests/Done.d.ts +5 -0
- package/esm/core/src/tests/Done.js +9 -0
- package/esm/core/src/tests/RowProvider.spec.d.ts +16 -0
- package/esm/core/src/tests/RowProvider.spec.js +631 -0
- package/esm/core/src/tests/TestDataApiResponse.d.ts +10 -0
- package/esm/core/src/tests/TestDataApiResponse.js +22 -0
- package/esm/core/src/tests/basicRowFunctionality.spec.d.ts +8 -0
- package/esm/core/src/tests/basicRowFunctionality.spec.js +2103 -0
- package/esm/core/src/tests/c.d.ts +8 -0
- package/esm/core/src/tests/c.js +13 -0
- package/esm/core/src/tests/createData.d.ts +7 -0
- package/esm/core/src/tests/createData.js +22 -0
- package/esm/core/src/tests/d.d.ts +6 -0
- package/esm/core/src/tests/d.js +11 -0
- package/esm/core/src/tests/dWithPrefilter.d.ts +7 -0
- package/esm/core/src/tests/dWithPrefilter.js +18 -0
- package/esm/core/src/tests/entityForCustomFilter.d.ts +16 -0
- package/esm/core/src/tests/entityForCustomFilter.js +33 -0
- package/esm/core/src/tests/entityWithValidationsOnColumn.d.ts +5 -0
- package/esm/core/src/tests/entityWithValidationsOnColumn.js +13 -0
- package/esm/core/src/tests/frontend-database-tests-setup.spec.d.ts +4 -0
- package/esm/core/src/tests/frontend-database-tests-setup.spec.js +37 -0
- package/esm/core/src/tests/h.d.ts +6 -0
- package/esm/core/src/tests/h.js +24 -0
- package/esm/core/src/tests/remult-3-basic-tests.spec.d.ts +1 -0
- package/esm/core/src/tests/remult-3-basic-tests.spec.js +236 -0
- package/esm/core/src/tests/remult-3-entities.d.ts +23 -0
- package/esm/core/src/tests/remult-3-entities.js +39 -0
- package/esm/core/src/tests/tasks.d.ts +6 -0
- package/esm/core/src/tests/tasks.js +10 -0
- package/esm/core/src/tests/test-context-as-storage.spec.d.ts +0 -0
- package/esm/core/src/tests/test-context-as-storage.spec.js +1 -0
- package/esm/core/src/tests/test-data-api/predefined-filter.spec.d.ts +1 -0
- package/esm/core/src/tests/test-data-api/predefined-filter.spec.js +389 -0
- package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.d.ts +5 -0
- package/esm/core/src/tests/test-data-api/test-put-with-validation.spec.js +152 -0
- package/esm/core/src/tests/test-decorator-precedence.spec.d.ts +1 -0
- package/esm/core/src/tests/test-decorator-precedence.spec.js +38 -0
- package/esm/core/src/tests/test-default-value.spec.d.ts +1 -0
- package/esm/core/src/tests/test-default-value.spec.js +33 -0
- package/esm/core/src/tests/test-entity-inheritance.spec.d.ts +14 -0
- package/esm/core/src/tests/test-entity-inheritance.spec.js +82 -0
- package/esm/core/src/tests/test-exceptions.spec.d.ts +1 -0
- package/esm/core/src/tests/test-exceptions.spec.js +375 -0
- package/esm/core/src/tests/test-json.spec.d.ts +1 -0
- package/esm/core/src/tests/test-json.spec.js +115 -0
- package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.d.ts +9 -0
- package/esm/core/src/tests/test-many-to-one-relation-in-entity.spec.js +809 -0
- package/esm/core/src/tests/test-non-active-record.spec.d.ts +1 -0
- package/esm/core/src/tests/test-non-active-record.spec.js +66 -0
- package/esm/core/src/tests/test-object-column.spec.d.ts +1 -0
- package/esm/core/src/tests/test-object-column.spec.js +189 -0
- package/esm/core/src/tests/test-paged-foreach.spec.d.ts +1 -0
- package/esm/core/src/tests/test-paged-foreach.spec.js +328 -0
- package/esm/core/src/tests/test-remult-angular.spec.d.ts +1 -0
- package/esm/core/src/tests/test-remult-angular.spec.js +23 -0
- package/esm/core/src/tests/test-server-controller.spec.d.ts +7 -0
- package/esm/core/src/tests/test-server-controller.spec.js +489 -0
- package/esm/core/src/tests/test-server-expressions.spec.d.ts +1 -0
- package/esm/core/src/tests/test-server-expressions.spec.js +178 -0
- package/esm/core/src/tests/test-server-method-on-entity.spec.d.ts +1 -0
- package/esm/core/src/tests/test-server-method-on-entity.spec.js +306 -0
- package/esm/core/src/tests/test-sql-expression.spec.d.ts +5 -0
- package/esm/core/src/tests/test-sql-expression.spec.js +205 -0
- package/esm/core/src/tests/test-sql.spec.d.ts +1 -0
- package/esm/core/src/tests/test-sql.spec.js +170 -0
- package/esm/core/src/tests/test-subscribe.spec.d.ts +1 -0
- package/esm/core/src/tests/test-subscribe.spec.js +135 -0
- package/esm/core/src/tests/test-type-recovery.spec.d.ts +1 -0
- package/esm/core/src/tests/test-type-recovery.spec.js +49 -0
- package/esm/core/src/tests/test-where-api.spec.d.ts +1 -0
- package/esm/core/src/tests/test-where-api.spec.js +434 -0
- package/esm/core/src/tests/testHelper.spec.d.ts +36 -0
- package/esm/core/src/tests/testHelper.spec.js +226 -0
- package/esm/core/src/tests/testModel/models.d.ts +16 -0
- package/esm/core/src/tests/testModel/models.js +25 -0
- package/esm/core/src/validators.d.ts +14 -0
- package/esm/core/src/validators.js +33 -0
- package/{valueConverters.d.ts → esm/core/src/valueConverters.d.ts} +13 -12
- package/esm/core/src/valueConverters.js +197 -0
- package/esm/core/urlBuilder.d.ts +6 -0
- package/esm/core/urlBuilder.js +20 -0
- package/esm/graphql.js +27 -27
- package/esm/postgres/schema-builder.js +4 -4
- package/esm/src/remult3/RepositoryImplementation.d.ts +1 -1
- package/esm/src/remult3/RepositoryImplementation.js +27 -4
- package/esm/src/shared-tests/db-tests.db-tests.js +57 -0
- package/esm/test-servers/shared/Task.d.ts +9 -0
- package/esm/test-servers/shared/Task.js +32 -0
- package/esm/test.d.ts +5 -0
- package/esm/test.js +6 -0
- package/package.json +1 -1
- package/src/remult3/RepositoryImplementation.d.ts +1 -1
- package/src/remult3/RepositoryImplementation.js +88 -63
- package/src/shared-tests/db-tests.db-tests.js +97 -0
- package/esm/src/id-entity.d.ts +0 -4
- package/esm/src/id-entity.js +0 -8
- package/postgres/postgresColumnSyntax.d.ts +0 -2
- package/postgres/postgresColumnSyntax.js +0 -34
- package/remult-middleware.d.ts +0 -2
- package/remult-middleware.js +0 -70
- package/server/register-actions-on-server.d.ts +0 -3
- package/server/register-actions-on-server.js +0 -50
- package/server/register-entities-on-server.d.ts +0 -3
- package/server/register-entities-on-server.js +0 -19
- package/src/backend-tests/my-test.backend-spec.js +0 -217
- package/src/backend-tests/test-http-server.backend-spec.d.ts +0 -6
- package/src/backend-tests/test-http-server.backend-spec.js +0 -342
- package/src/id-entity.d.ts +0 -4
- package/src/id-entity.js +0 -17
- package/valueConverters.js +0 -168
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { allEntities } from '../src/context';
|
|
2
|
+
import { dbNamesOf, isDbReadonly } from '../src/filter/filter-consumer-bridge-to-sql-request';
|
|
3
|
+
import { remult as defaultRemult } from '../src/remult-proxy';
|
|
4
|
+
import { isAutoIncrement } from '../src/remult3';
|
|
5
|
+
import { ValueConverters } from '../src/valueConverters';
|
|
6
|
+
export function postgresColumnSyntax(x, dbName) {
|
|
7
|
+
let result = dbName;
|
|
8
|
+
if (x.valueType == Number) {
|
|
9
|
+
if (!x.valueConverter.fieldTypeInDb)
|
|
10
|
+
result += " numeric" + (x.allowNull ? "" : " default 0 not null");
|
|
11
|
+
else
|
|
12
|
+
result += " " + x.valueConverter.fieldTypeInDb + (x.allowNull ? "" : " default 0 not null");
|
|
13
|
+
}
|
|
14
|
+
else if (x.valueType == Date) {
|
|
15
|
+
if (!x.valueConverter.fieldTypeInDb)
|
|
16
|
+
if (x.valueConverter == ValueConverters.DateOnly)
|
|
17
|
+
result += " date";
|
|
18
|
+
else
|
|
19
|
+
result += " timestamp";
|
|
20
|
+
else
|
|
21
|
+
result += " " + x.valueConverter.fieldTypeInDb;
|
|
22
|
+
}
|
|
23
|
+
else if (x.valueType == Boolean)
|
|
24
|
+
result += " boolean" + (x.allowNull ? "" : " default false not null");
|
|
25
|
+
else if (x.valueConverter.fieldTypeInDb) {
|
|
26
|
+
result += " " + x.valueConverter.fieldTypeInDb;
|
|
27
|
+
if (!x.allowNull && x.valueConverter.fieldTypeInDb == 'integer') {
|
|
28
|
+
result += " default 0 not null";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else
|
|
32
|
+
result += " varchar" + (x.allowNull ? "" : " default '' not null");
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
export async function verifyStructureOfAllEntities(db, remult) {
|
|
36
|
+
return await new PostgresSchemaBuilder(db).verifyStructureOfAllEntities(remult);
|
|
37
|
+
}
|
|
38
|
+
export class PostgresSchemaBuilder {
|
|
39
|
+
pool;
|
|
40
|
+
//@internal
|
|
41
|
+
static logToConsole = true;
|
|
42
|
+
async verifyStructureOfAllEntities(remult) {
|
|
43
|
+
if (!remult) {
|
|
44
|
+
remult = defaultRemult;
|
|
45
|
+
}
|
|
46
|
+
const completed = new Set();
|
|
47
|
+
const entities = [];
|
|
48
|
+
for (const entityClass of [...allEntities].reverse()) {
|
|
49
|
+
let entity = remult.repo(entityClass).metadata;
|
|
50
|
+
let e = await dbNamesOf(entity);
|
|
51
|
+
if (completed.has(e.$entityName))
|
|
52
|
+
continue;
|
|
53
|
+
completed.add(e.$entityName);
|
|
54
|
+
entities.push(entity);
|
|
55
|
+
}
|
|
56
|
+
await this.ensureSchema(entities);
|
|
57
|
+
}
|
|
58
|
+
async ensureSchema(entities) {
|
|
59
|
+
for (const entity of entities) {
|
|
60
|
+
let e = await dbNamesOf(entity);
|
|
61
|
+
try {
|
|
62
|
+
if (!entity.options.sqlExpression) {
|
|
63
|
+
if (e.$entityName.toLowerCase().indexOf('from ') < 0) {
|
|
64
|
+
await this.createIfNotExist(entity);
|
|
65
|
+
await this.verifyAllColumns(entity);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.error("failed verify structure of " + e.$entityName + " ", err);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async createIfNotExist(entity) {
|
|
75
|
+
var c = this.pool.createCommand();
|
|
76
|
+
let e = await dbNamesOf(entity);
|
|
77
|
+
await c.execute("select 1 from information_Schema.tables where table_name=" + c.addParameterAndReturnSqlToken((e.$entityName).toLowerCase()) + this.additionalWhere).then(async (r) => {
|
|
78
|
+
if (r.rows.length == 0) {
|
|
79
|
+
let result = '';
|
|
80
|
+
for (const x of entity.fields) {
|
|
81
|
+
if (!isDbReadonly(x, e) || isAutoIncrement(x)) {
|
|
82
|
+
if (result.length != 0)
|
|
83
|
+
result += ',';
|
|
84
|
+
result += '\r\n ';
|
|
85
|
+
if (isAutoIncrement(x))
|
|
86
|
+
result += e.$dbNameOf(x) + ' serial';
|
|
87
|
+
else {
|
|
88
|
+
result += postgresColumnSyntax(x, e.$dbNameOf(x));
|
|
89
|
+
}
|
|
90
|
+
if (x == entity.idMetadata.field)
|
|
91
|
+
result += ' primary key';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
let sql = 'create table ' + e.$entityName + ' (' + result + '\r\n)';
|
|
95
|
+
if (PostgresSchemaBuilder.logToConsole)
|
|
96
|
+
console.info(sql);
|
|
97
|
+
await this.pool.execute(sql);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async addColumnIfNotExist(entity, c) {
|
|
102
|
+
let e = await dbNamesOf(entity);
|
|
103
|
+
if (isDbReadonly(c(entity), e))
|
|
104
|
+
return;
|
|
105
|
+
try {
|
|
106
|
+
let cmd = this.pool.createCommand();
|
|
107
|
+
const colName = e.$dbNameOf(c(entity));
|
|
108
|
+
if ((await cmd.execute(`select 1
|
|
109
|
+
FROM information_schema.columns
|
|
110
|
+
WHERE table_name=${cmd.addParameterAndReturnSqlToken((e.$entityName).toLocaleLowerCase())} and column_name=${cmd.addParameterAndReturnSqlToken((colName).toLocaleLowerCase())}` + this.additionalWhere)).rows.length == 0) {
|
|
111
|
+
let sql = `alter table ${e.$entityName} add column ${postgresColumnSyntax(c(entity), colName)}`;
|
|
112
|
+
if (PostgresSchemaBuilder.logToConsole)
|
|
113
|
+
console.info(sql);
|
|
114
|
+
await this.pool.execute(sql);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
console.error(err);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async verifyAllColumns(entity) {
|
|
122
|
+
try {
|
|
123
|
+
let cmd = this.pool.createCommand();
|
|
124
|
+
let e = await dbNamesOf(entity);
|
|
125
|
+
let cols = (await cmd.execute(`select column_name
|
|
126
|
+
FROM information_schema.columns
|
|
127
|
+
WHERE table_name=${cmd.addParameterAndReturnSqlToken((e.$entityName).toLocaleLowerCase())} ` + this.additionalWhere)).rows.map(x => x.column_name.toLocaleLowerCase());
|
|
128
|
+
for (const col of entity.fields) {
|
|
129
|
+
if (!isDbReadonly(col, e)) {
|
|
130
|
+
let colName = e.$dbNameOf(col).toLocaleLowerCase();
|
|
131
|
+
if (colName.startsWith('"') && colName.endsWith('"'))
|
|
132
|
+
colName = colName.substring(1, colName.length - 1);
|
|
133
|
+
if (!cols.includes(colName)) {
|
|
134
|
+
let sql = `alter table ${e.$entityName} add column ${postgresColumnSyntax(col, e.$dbNameOf(col))}`;
|
|
135
|
+
if (PostgresSchemaBuilder.logToConsole)
|
|
136
|
+
console.info(sql);
|
|
137
|
+
await this.pool.execute(sql);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
console.error(err);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
additionalWhere = '';
|
|
147
|
+
constructor(pool, schema) {
|
|
148
|
+
this.pool = pool;
|
|
149
|
+
if (schema) {
|
|
150
|
+
this.additionalWhere = ' and table_schema=\'' + schema + '\'';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RemultServerOptions, RemultServerCore } from "./server/expressBridge";
|
|
2
|
+
export declare function remultFresh(options: RemultServerOptions<FreshRequest>, response: FreshResponse): RemultFresh;
|
|
3
|
+
export interface RemultFresh extends RemultServerCore<FreshRequest> {
|
|
4
|
+
handle(req: FreshRequest, ctx: FreshContext): Promise<any>;
|
|
5
|
+
}
|
|
6
|
+
export interface FreshRequest {
|
|
7
|
+
url: string;
|
|
8
|
+
method: string;
|
|
9
|
+
json: () => Promise<any>;
|
|
10
|
+
}
|
|
11
|
+
export interface FreshContext {
|
|
12
|
+
next: () => Promise<any>;
|
|
13
|
+
}
|
|
14
|
+
export interface FreshResponse {
|
|
15
|
+
new (body?: any | undefined, init?: ResponseInit): any;
|
|
16
|
+
json(data: unknown, init?: ResponseInit): any;
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createRemultServerCore } from "./server/expressBridge";
|
|
2
|
+
export function remultFresh(options, response) {
|
|
3
|
+
const server = createRemultServerCore(options, {
|
|
4
|
+
buildGenericRequestInfo: r => r,
|
|
5
|
+
getRequestBody: req => req.json()
|
|
6
|
+
});
|
|
7
|
+
return {
|
|
8
|
+
getRemult: r => server.getRemult(r),
|
|
9
|
+
openApiDoc: x => server.openApiDoc(x),
|
|
10
|
+
handle: async (req, ctx) => {
|
|
11
|
+
let init = {};
|
|
12
|
+
const res = await server.handle(req);
|
|
13
|
+
if (res) {
|
|
14
|
+
init.status = res.statusCode;
|
|
15
|
+
if (res.data) {
|
|
16
|
+
return response.json(res.data, init);
|
|
17
|
+
}
|
|
18
|
+
else
|
|
19
|
+
return new response(undefined, init);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
return ctx.next();
|
|
23
|
+
}
|
|
24
|
+
;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
;
|
|
29
|
+
;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Knex } from 'knex';
|
|
2
|
+
import { Remult } from "../src/context";
|
|
3
|
+
import { EntityFilter, EntityMetadata, RepositoryOverloads } from "../src/remult3";
|
|
4
|
+
import { DataProvider, EntityDataProvider } from '../src/data-interfaces';
|
|
5
|
+
import { FieldMetadata } from '../src/column-interfaces';
|
|
6
|
+
export declare class KnexDataProvider implements DataProvider {
|
|
7
|
+
knex: Knex;
|
|
8
|
+
constructor(knex: Knex);
|
|
9
|
+
static getDb(remult?: Remult): Knex<any, any[]>;
|
|
10
|
+
getEntityDataProvider(entity: EntityMetadata<any>): EntityDataProvider;
|
|
11
|
+
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
12
|
+
static rawFilter(build: CustomKnexFilterBuilderFunction): EntityFilter<any>;
|
|
13
|
+
static filterToRaw<entityType>(entity: RepositoryOverloads<entityType>, condition: EntityFilter<entityType>): Promise<(knex: any) => void>;
|
|
14
|
+
isProxy?: boolean;
|
|
15
|
+
ensureSchema(entities: EntityMetadata<any>[]): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export type CustomKnexFilterBuilderFunction = () => Promise<(builder: Knex.QueryBuilder) => void>;
|
|
18
|
+
export declare class KnexSchemaBuilder {
|
|
19
|
+
private knex;
|
|
20
|
+
static logToConsole: boolean;
|
|
21
|
+
verifyStructureOfAllEntities(remult?: Remult): Promise<void>;
|
|
22
|
+
ensureSchema(entities: EntityMetadata<any>[]): Promise<void>;
|
|
23
|
+
createIfNotExist(entity: EntityMetadata): Promise<void>;
|
|
24
|
+
addColumnIfNotExist<T extends EntityMetadata>(entity: T, c: ((e: T) => FieldMetadata)): Promise<void>;
|
|
25
|
+
verifyAllColumns<T extends EntityMetadata>(entity: T): Promise<void>;
|
|
26
|
+
additionalWhere: string;
|
|
27
|
+
constructor(knex: Knex);
|
|
28
|
+
}
|
|
29
|
+
export declare function buildColumn(x: FieldMetadata, dbName: string, b: Knex.CreateTableBuilder, supportsJson?: boolean): void;
|
|
30
|
+
export declare function createKnexDataProvider(config: Knex.Config): Promise<KnexDataProvider>;
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { customDatabaseFilterToken, Filter } from "../src/filter/filter-interfaces";
|
|
2
|
+
import { dbNamesOf, isDbReadonly } from "../src/filter/filter-consumer-bridge-to-sql-request";
|
|
3
|
+
import { allEntities } from "../src/context";
|
|
4
|
+
import { isAutoIncrement, getRepository } from "../src/remult3";
|
|
5
|
+
import { ValueConverters } from "../src/valueConverters";
|
|
6
|
+
import { CompoundIdField } from '../src/column';
|
|
7
|
+
import { Sort } from '../src/sort';
|
|
8
|
+
import { remult as remultContext } from '../src/remult-proxy';
|
|
9
|
+
export class KnexDataProvider {
|
|
10
|
+
knex;
|
|
11
|
+
constructor(knex) {
|
|
12
|
+
this.knex = knex;
|
|
13
|
+
}
|
|
14
|
+
static getDb(remult) {
|
|
15
|
+
const r = (remult || remultContext).dataProvider;
|
|
16
|
+
if (!r.knex)
|
|
17
|
+
throw "the data provider is not an KnexDataProvider";
|
|
18
|
+
return r.knex;
|
|
19
|
+
}
|
|
20
|
+
getEntityDataProvider(entity) {
|
|
21
|
+
if (!supportsJson(this.knex))
|
|
22
|
+
for (const f of entity.fields.toArray()) {
|
|
23
|
+
if (f.valueConverter.fieldTypeInDb === "json") {
|
|
24
|
+
//@ts-ignore
|
|
25
|
+
f.valueConverter = { ...f.valueConverter, toDb: ValueConverters.JsonString.toDb, fromDb: ValueConverters.JsonString.fromDb };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return new KnexEntityDataProvider(entity, this.knex);
|
|
29
|
+
}
|
|
30
|
+
async transaction(action) {
|
|
31
|
+
let t = await this.knex.transaction();
|
|
32
|
+
try {
|
|
33
|
+
await action(new KnexDataProvider(t));
|
|
34
|
+
await t.commit();
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
await t.rollback();
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
static rawFilter(build) {
|
|
42
|
+
return {
|
|
43
|
+
[customDatabaseFilterToken]: {
|
|
44
|
+
buildKnex: build
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
static async filterToRaw(entity, condition) {
|
|
49
|
+
const repo = getRepository(entity);
|
|
50
|
+
var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata));
|
|
51
|
+
b._addWhere = false;
|
|
52
|
+
await (await (repo.translateWhereToFilter(condition))).__applyToConsumer(b);
|
|
53
|
+
let r = await b.resolveWhere();
|
|
54
|
+
return knex => r.forEach(y => y(knex));
|
|
55
|
+
}
|
|
56
|
+
isProxy;
|
|
57
|
+
async ensureSchema(entities) {
|
|
58
|
+
var sb = new KnexSchemaBuilder(this.knex);
|
|
59
|
+
await sb.ensureSchema(entities);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
class KnexEntityDataProvider {
|
|
63
|
+
entity;
|
|
64
|
+
knex;
|
|
65
|
+
constructor(entity, knex) {
|
|
66
|
+
this.entity = entity;
|
|
67
|
+
this.knex = knex;
|
|
68
|
+
}
|
|
69
|
+
async count(where) {
|
|
70
|
+
const e = await this.init();
|
|
71
|
+
const br = new FilterConsumerBridgeToKnexRequest(e);
|
|
72
|
+
where.__applyToConsumer(br);
|
|
73
|
+
let r = await br.resolveWhere();
|
|
74
|
+
const result = (await this.knex(e.$entityName)
|
|
75
|
+
.count().where(b => r.forEach(w => w(b))));
|
|
76
|
+
var row = result[0];
|
|
77
|
+
for (const key in row) {
|
|
78
|
+
if (Object.prototype.hasOwnProperty.call(row, key)) {
|
|
79
|
+
const element = row[key];
|
|
80
|
+
return +element;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async find(options) {
|
|
85
|
+
const e = await this.init();
|
|
86
|
+
let cols = [];
|
|
87
|
+
let colKeys = [];
|
|
88
|
+
for (const x of this.entity.fields) {
|
|
89
|
+
if (x.isServerExpression) {
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
cols.push(e.$dbNameOf(x));
|
|
93
|
+
colKeys.push(x);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
let query = this.knex(e.$entityName).select(cols);
|
|
97
|
+
if (options?.where) {
|
|
98
|
+
const br = new FilterConsumerBridgeToKnexRequest(e);
|
|
99
|
+
options.where.__applyToConsumer(br);
|
|
100
|
+
let r = await br.resolveWhere();
|
|
101
|
+
query.where(b => r.forEach(y => y(b)));
|
|
102
|
+
}
|
|
103
|
+
if (!options.orderBy) {
|
|
104
|
+
options.orderBy = Sort.createUniqueSort(this.entity, new Sort());
|
|
105
|
+
}
|
|
106
|
+
if (options.orderBy) {
|
|
107
|
+
query = query.orderBy(options.orderBy.Segments.map(s => ({
|
|
108
|
+
column: e.$dbNameOf(s.field),
|
|
109
|
+
order: s.isDescending ? "desc" : "asc"
|
|
110
|
+
})));
|
|
111
|
+
}
|
|
112
|
+
if (options.limit) {
|
|
113
|
+
query = query.limit(options.limit);
|
|
114
|
+
if (options.page)
|
|
115
|
+
query = query.offset((options.page - 1) * options.limit);
|
|
116
|
+
}
|
|
117
|
+
const r = await query;
|
|
118
|
+
return r.map(y => {
|
|
119
|
+
let result = {};
|
|
120
|
+
let i = 0;
|
|
121
|
+
for (let m in y) {
|
|
122
|
+
let field = colKeys[i++];
|
|
123
|
+
try {
|
|
124
|
+
result[field.key] = field.valueConverter.fromDb(y[m]);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
throw new Error("Failed to load from db:" + field.key + "\r\n" + err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async init() {
|
|
134
|
+
return await dbNamesOf(this.entity);
|
|
135
|
+
}
|
|
136
|
+
async update(id, data) {
|
|
137
|
+
const e = await this.init();
|
|
138
|
+
let f = new FilterConsumerBridgeToKnexRequest(e);
|
|
139
|
+
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
140
|
+
let resultFilter = this.entity.idMetadata.getIdFilter(id);
|
|
141
|
+
if (data.id != undefined)
|
|
142
|
+
resultFilter = this.entity.idMetadata.getIdFilter(data.id);
|
|
143
|
+
let updateObject = {};
|
|
144
|
+
for (const x of this.entity.fields) {
|
|
145
|
+
if (isDbReadonly(x, e)) { }
|
|
146
|
+
else if (data[x.key] !== undefined) {
|
|
147
|
+
let v = translateValueAndHandleArrayAndHandleArray(x, data[x.key]);
|
|
148
|
+
if (v !== undefined) {
|
|
149
|
+
let key = await e.$dbNameOf(x);
|
|
150
|
+
updateObject[key] = v;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let where = await f.resolveWhere();
|
|
155
|
+
await this.knex(e.$entityName).update(updateObject).where(b => where.forEach(w => w(b)));
|
|
156
|
+
return this.find({ where: Filter.fromEntityFilter(this.entity, resultFilter) }).then(y => y[0]);
|
|
157
|
+
}
|
|
158
|
+
async delete(id) {
|
|
159
|
+
const e = await this.init();
|
|
160
|
+
let f = new FilterConsumerBridgeToKnexRequest(e);
|
|
161
|
+
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
162
|
+
let where = await f.resolveWhere();
|
|
163
|
+
await this.knex(e.$entityName).delete().where(b => where.forEach(w => w(b)));
|
|
164
|
+
}
|
|
165
|
+
async insert(data) {
|
|
166
|
+
const e = await this.init();
|
|
167
|
+
let resultFilter;
|
|
168
|
+
if (this.entity.idMetadata.field instanceof CompoundIdField)
|
|
169
|
+
resultFilter = this.entity.idMetadata.field.resultIdFilter(undefined, data);
|
|
170
|
+
else
|
|
171
|
+
resultFilter = Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(data[this.entity.idMetadata.field.key]));
|
|
172
|
+
let insertObject = {};
|
|
173
|
+
for (const x of this.entity.fields) {
|
|
174
|
+
if (isDbReadonly(x, e)) { }
|
|
175
|
+
else {
|
|
176
|
+
let v = translateValueAndHandleArrayAndHandleArray(x, data[x.key]);
|
|
177
|
+
if (v != undefined) {
|
|
178
|
+
let key = await e.$dbNameOf(x);
|
|
179
|
+
insertObject[key] = v;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
let insert = this.knex(e.$entityName).insert(insertObject);
|
|
184
|
+
if (isAutoIncrement(this.entity.idMetadata.field)) {
|
|
185
|
+
let newId;
|
|
186
|
+
if (this.knex.client.config.client === 'mysql2') {
|
|
187
|
+
let result = await insert;
|
|
188
|
+
newId = result[0];
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
let result = await insert.returning(this.entity.idMetadata.field.key);
|
|
192
|
+
newId = result[0].id;
|
|
193
|
+
}
|
|
194
|
+
resultFilter = new Filter(x => x.isEqualTo(this.entity.idMetadata.field, newId));
|
|
195
|
+
}
|
|
196
|
+
else
|
|
197
|
+
await insert;
|
|
198
|
+
return this.find({ where: resultFilter }).then(y => {
|
|
199
|
+
return y[0];
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
class FilterConsumerBridgeToKnexRequest {
|
|
204
|
+
nameProvider;
|
|
205
|
+
_addWhere = true;
|
|
206
|
+
promises = [];
|
|
207
|
+
result = [];
|
|
208
|
+
async resolveWhere() {
|
|
209
|
+
while (this.promises.length > 0) {
|
|
210
|
+
let p = this.promises;
|
|
211
|
+
this.promises = [];
|
|
212
|
+
for (const pr of p) {
|
|
213
|
+
await pr;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return this.result;
|
|
217
|
+
}
|
|
218
|
+
constructor(nameProvider) {
|
|
219
|
+
this.nameProvider = nameProvider;
|
|
220
|
+
}
|
|
221
|
+
custom(key, customItem) {
|
|
222
|
+
throw new Error("Custom filter should be translated before it gets here");
|
|
223
|
+
}
|
|
224
|
+
or(orElements) {
|
|
225
|
+
this.promises.push((async () => {
|
|
226
|
+
const result = [];
|
|
227
|
+
for (const element of orElements) {
|
|
228
|
+
let f = new FilterConsumerBridgeToKnexRequest(this.nameProvider);
|
|
229
|
+
f._addWhere = false;
|
|
230
|
+
element.__applyToConsumer(f);
|
|
231
|
+
let where = await f.resolveWhere();
|
|
232
|
+
if (where.length > 0) {
|
|
233
|
+
result.push(b => {
|
|
234
|
+
b.orWhere(b => {
|
|
235
|
+
where.forEach(x => x(b));
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
else
|
|
240
|
+
return; //empty or means all rows
|
|
241
|
+
}
|
|
242
|
+
if (result.length > 0) {
|
|
243
|
+
this.result.push(b => b.where(x => result.find(y => y(x))));
|
|
244
|
+
}
|
|
245
|
+
})());
|
|
246
|
+
}
|
|
247
|
+
isNull(col) {
|
|
248
|
+
this.result.push(b => b.whereNull(this.nameProvider.$dbNameOf(col)));
|
|
249
|
+
}
|
|
250
|
+
isNotNull(col) {
|
|
251
|
+
this.result.push(b => b.whereNotNull(this.nameProvider.$dbNameOf(col)));
|
|
252
|
+
}
|
|
253
|
+
isIn(col, val) {
|
|
254
|
+
this.result.push(knex => knex.whereIn(this.nameProvider.$dbNameOf(col), val.map(x => translateValueAndHandleArrayAndHandleArray(col, x))));
|
|
255
|
+
}
|
|
256
|
+
isEqualTo(col, val) {
|
|
257
|
+
this.add(col, val, "=");
|
|
258
|
+
}
|
|
259
|
+
isDifferentFrom(col, val) {
|
|
260
|
+
this.add(col, val, "<>");
|
|
261
|
+
}
|
|
262
|
+
isGreaterOrEqualTo(col, val) {
|
|
263
|
+
this.add(col, val, ">=");
|
|
264
|
+
}
|
|
265
|
+
isGreaterThan(col, val) {
|
|
266
|
+
this.add(col, val, ">");
|
|
267
|
+
}
|
|
268
|
+
isLessOrEqualTo(col, val) {
|
|
269
|
+
this.add(col, val, "<=");
|
|
270
|
+
}
|
|
271
|
+
isLessThan(col, val) {
|
|
272
|
+
this.add(col, val, "<");
|
|
273
|
+
}
|
|
274
|
+
containsCaseInsensitive(col, val) {
|
|
275
|
+
this.result.push(b => b.whereRaw('lower (' + b.client.ref(this.nameProvider.$dbNameOf(col)) + ") like lower ('%" + val.replace(/'/g, '\'\'') + "%')"));
|
|
276
|
+
this.promises.push((async () => {
|
|
277
|
+
})());
|
|
278
|
+
}
|
|
279
|
+
add(col, val, operator) {
|
|
280
|
+
this.result.push(b => b.where(this.nameProvider.$dbNameOf(col), operator, translateValueAndHandleArrayAndHandleArray(col, val)));
|
|
281
|
+
}
|
|
282
|
+
databaseCustom(databaseCustom) {
|
|
283
|
+
this.promises.push((async () => {
|
|
284
|
+
if (databaseCustom?.buildKnex) {
|
|
285
|
+
this.result.push(await databaseCustom.buildKnex());
|
|
286
|
+
}
|
|
287
|
+
})());
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
export class KnexSchemaBuilder {
|
|
291
|
+
knex;
|
|
292
|
+
//@internal
|
|
293
|
+
static logToConsole = true;
|
|
294
|
+
async verifyStructureOfAllEntities(remult) {
|
|
295
|
+
if (!remult)
|
|
296
|
+
remult = remultContext;
|
|
297
|
+
const entities = allEntities.map(x => remult.repo(x).metadata);
|
|
298
|
+
this.ensureSchema(entities);
|
|
299
|
+
}
|
|
300
|
+
async ensureSchema(entities) {
|
|
301
|
+
for (const entity of entities) {
|
|
302
|
+
let e = await dbNamesOf(entity);
|
|
303
|
+
try {
|
|
304
|
+
if (!entity.options.sqlExpression) {
|
|
305
|
+
if (e.$entityName.toLowerCase().indexOf('from ') < 0) {
|
|
306
|
+
await this.createIfNotExist(entity);
|
|
307
|
+
await this.verifyAllColumns(entity);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
console.error("failed ensure schema of " + e.$entityName + " ", err);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async createIfNotExist(entity) {
|
|
317
|
+
const e = await dbNamesOf(entity);
|
|
318
|
+
if (!await this.knex.schema.hasTable(e.$entityName)) {
|
|
319
|
+
let cols = new Map();
|
|
320
|
+
for (const f of entity.fields) {
|
|
321
|
+
cols.set(f, {
|
|
322
|
+
name: e.$dbNameOf(f),
|
|
323
|
+
readonly: isDbReadonly(f, e)
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
await logSql(this.knex.schema.createTable(e.$entityName, b => {
|
|
327
|
+
for (const x of entity.fields) {
|
|
328
|
+
if (!cols.get(x).readonly || isAutoIncrement(x)) {
|
|
329
|
+
if (isAutoIncrement(x))
|
|
330
|
+
b.increments(cols.get(x).name);
|
|
331
|
+
else {
|
|
332
|
+
buildColumn(x, cols.get(x).name, b, supportsJson(this.knex));
|
|
333
|
+
if (x == entity.idMetadata.field)
|
|
334
|
+
b.primary([cols.get(x).name]);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
async addColumnIfNotExist(entity, c) {
|
|
342
|
+
let e = await dbNamesOf(entity);
|
|
343
|
+
if (isDbReadonly(c(entity), e))
|
|
344
|
+
return;
|
|
345
|
+
let col = c(entity);
|
|
346
|
+
let colName = e.$dbNameOf(col);
|
|
347
|
+
if (!await this.knex.schema.hasColumn(e.$entityName, colName)) {
|
|
348
|
+
await logSql(this.knex.schema.alterTable(e.$entityName, b => {
|
|
349
|
+
buildColumn(col, colName, b, supportsJson(this.knex));
|
|
350
|
+
}));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
async verifyAllColumns(entity) {
|
|
354
|
+
let e = await dbNamesOf(entity);
|
|
355
|
+
try {
|
|
356
|
+
for (const col of entity.fields.toArray()) {
|
|
357
|
+
if (!isDbReadonly(col, e)) {
|
|
358
|
+
await this.addColumnIfNotExist(entity, () => col);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
console.error(err);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
additionalWhere = '';
|
|
367
|
+
constructor(knex) {
|
|
368
|
+
this.knex = knex;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function supportsJson(knex) {
|
|
372
|
+
const client = knex.client.config.client;
|
|
373
|
+
if (client?.includes("sqlite3") || client?.includes("mssql"))
|
|
374
|
+
return false;
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
export function buildColumn(x, dbName, b, supportsJson = true) {
|
|
378
|
+
if (x.valueType == Number) {
|
|
379
|
+
if (!x.valueConverter.fieldTypeInDb) {
|
|
380
|
+
let c = b.decimal(dbName);
|
|
381
|
+
if (!x.allowNull) {
|
|
382
|
+
c.defaultTo(0).notNullable();
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else if (x.valueConverter.fieldTypeInDb == "integer") {
|
|
386
|
+
let c = b.integer(dbName);
|
|
387
|
+
if (!x.allowNull) {
|
|
388
|
+
c.defaultTo(0).notNullable();
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
else
|
|
392
|
+
b.specificType(dbName, x.valueConverter.fieldTypeInDb);
|
|
393
|
+
}
|
|
394
|
+
else if (x.valueType == Date) {
|
|
395
|
+
if (!x.valueConverter.fieldTypeInDb)
|
|
396
|
+
if (x.valueConverter == ValueConverters.DateOnly)
|
|
397
|
+
b.date(dbName);
|
|
398
|
+
else
|
|
399
|
+
b.dateTime(dbName);
|
|
400
|
+
else if (x.valueConverter.fieldTypeInDb == "date")
|
|
401
|
+
b.date(dbName);
|
|
402
|
+
else
|
|
403
|
+
b.specificType(dbName, x.valueConverter.fieldTypeInDb);
|
|
404
|
+
}
|
|
405
|
+
else if (x.valueType == Boolean) {
|
|
406
|
+
let c = b.boolean(dbName);
|
|
407
|
+
if (!x.allowNull)
|
|
408
|
+
c.defaultTo(false).notNullable();
|
|
409
|
+
}
|
|
410
|
+
else if (x.valueConverter.fieldTypeInDb) {
|
|
411
|
+
if (x.valueConverter.fieldTypeInDb == "integer") {
|
|
412
|
+
let c = b.integer(dbName);
|
|
413
|
+
if (!x.allowNull) {
|
|
414
|
+
c.defaultTo(0).notNullable();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
else if (x.valueConverter.fieldTypeInDb == "json")
|
|
418
|
+
if (supportsJson)
|
|
419
|
+
b.json(dbName);
|
|
420
|
+
else
|
|
421
|
+
b.text(dbName);
|
|
422
|
+
else
|
|
423
|
+
b.specificType(dbName, x.valueConverter.fieldTypeInDb);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
let c = b.string(dbName, x.options.maxLength);
|
|
427
|
+
if (!x.allowNull)
|
|
428
|
+
c.defaultTo('').notNullable();
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
function logSql(who) {
|
|
432
|
+
if (KnexSchemaBuilder.logToConsole)
|
|
433
|
+
console.info(who.toSQL());
|
|
434
|
+
return who;
|
|
435
|
+
}
|
|
436
|
+
export async function createKnexDataProvider(config) {
|
|
437
|
+
let k = (await import('knex')).default(config);
|
|
438
|
+
let result = new KnexDataProvider(k);
|
|
439
|
+
return result;
|
|
440
|
+
}
|
|
441
|
+
function translateValueAndHandleArrayAndHandleArray(field, val) {
|
|
442
|
+
let result = field.valueConverter.toDb(val);
|
|
443
|
+
if (Array.isArray(result))
|
|
444
|
+
return JSON.stringify(result);
|
|
445
|
+
return result;
|
|
446
|
+
}
|