remult 0.25.8 → 0.26.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/README.md +194 -129
- package/esm/graphql.js +131 -59
- package/esm/index.js +1 -1
- package/esm/migrations/compare-migration-snapshots.js +61 -0
- package/esm/migrations/generate-migrations.js +68 -0
- package/esm/migrations/index.js +2 -0
- package/esm/migrations/migrate.js +90 -0
- package/esm/migrations/migration-types.js +36 -0
- package/esm/migrations/update-migrations-ts-file.js +115 -0
- package/esm/postgres/postgres-data-provider.js +24 -3
- package/esm/postgres/schema-builder.js +35 -26
- package/esm/remult-better-sqlite3.js +47 -0
- package/esm/remult-bun-sqlite.js +41 -0
- package/esm/remult-knex/index.js +180 -51
- package/esm/remult-mongo.js +2 -2
- package/esm/remult-sql-js.js +3 -78
- package/esm/remult-sqlite-core.js +104 -0
- package/esm/server/expressBridge.js +130 -29
- package/esm/server/initAsyncHooks.js +75 -1
- package/esm/src/CompoundIdField.js +8 -2
- package/esm/src/context.js +20 -24
- package/esm/src/data-api.js +71 -30
- package/esm/src/data-providers/rest-data-provider.js +17 -15
- package/esm/src/data-providers/sql-database.js +32 -7
- package/esm/src/data-providers/web-sql-data-provider.js +1 -9
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +37 -11
- package/esm/src/filter/filter-interfaces.js +229 -17
- package/esm/src/isOfType.js +9 -0
- package/esm/src/remult3/Fields.js +70 -18
- package/esm/src/remult3/RepositoryImplementation.js +47 -21
- package/esm/src/remult3/addValidator.js +15 -0
- package/esm/src/remult3/remult3.js +28 -57
- package/esm/src/server-action.js +4 -4
- package/esm/src/validators.js +6 -3
- package/esm/src/valueConverters.js +1 -1
- package/graphql.js +156 -71
- package/index.d.ts +4 -4
- package/index.js +2 -1
- package/migrations/compare-migration-snapshots.d.ts +27 -0
- package/migrations/compare-migration-snapshots.js +165 -0
- package/migrations/generate-migrations.d.ts +21 -0
- package/migrations/generate-migrations.js +104 -0
- package/migrations/index.d.ts +3 -0
- package/migrations/index.js +7 -0
- package/migrations/migrate.d.ts +27 -0
- package/migrations/migrate.js +175 -0
- package/migrations/migration-types.d.ts +48 -0
- package/migrations/migration-types.js +88 -0
- package/migrations/update-migrations-ts-file.d.ts +1 -0
- package/migrations/update-migrations-ts-file.js +141 -0
- package/package.json +21 -1
- package/postgres/postgres-data-provider.d.ts +8 -3
- package/postgres/postgres-data-provider.js +46 -3
- package/postgres/schema-builder.js +81 -48
- package/remult-better-sqlite3.d.ts +12 -0
- package/remult-better-sqlite3.js +64 -0
- package/remult-bun-sqlite.d.ts +11 -0
- package/remult-bun-sqlite.js +56 -0
- package/remult-knex/index.d.ts +12 -5
- package/remult-knex/index.js +257 -90
- package/remult-mongo.d.ts +2 -2
- package/remult-mongo.js +2 -2
- package/remult-sql-js.d.ts +2 -15
- package/remult-sql-js.js +11 -152
- package/remult-sqlite-core.d.ts +21 -0
- package/remult-sqlite-core.js +217 -0
- package/server/expressBridge.d.ts +30 -1
- package/server/expressBridge.js +140 -32
- package/server/initAsyncHooks.d.ts +16 -0
- package/server/initAsyncHooks.js +128 -2
- package/src/CompoundIdField.js +8 -2
- package/src/column-interfaces.d.ts +9 -3
- package/src/context.d.ts +8 -6
- package/src/context.js +27 -36
- package/src/data-api.d.ts +13 -9
- package/src/data-api.js +184 -135
- package/src/data-providers/rest-data-provider.js +26 -15
- package/src/data-providers/sql-database.d.ts +17 -5
- package/src/data-providers/sql-database.js +31 -7
- package/src/data-providers/web-sql-data-provider.d.ts +1 -2
- package/src/data-providers/web-sql-data-provider.js +4 -8
- package/src/entity.d.ts +64 -6
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +31 -7
- package/src/filter/filter-consumer-bridge-to-sql-request.js +46 -21
- package/src/filter/filter-interfaces.d.ts +106 -39
- package/src/filter/filter-interfaces.js +312 -32
- package/src/isOfType.d.ts +2 -0
- package/src/isOfType.js +14 -0
- package/src/remult3/Fields.d.ts +36 -0
- package/src/remult3/Fields.js +81 -19
- package/src/remult3/RepositoryImplementation.d.ts +7 -3
- package/src/remult3/RepositoryImplementation.js +106 -71
- package/src/remult3/addValidator.d.ts +2 -0
- package/src/remult3/addValidator.js +20 -0
- package/src/remult3/remult3.d.ts +6 -2
- package/src/remult3/remult3.js +28 -57
- package/src/server-action.d.ts +1 -1
- package/src/server-action.js +5 -4
- package/src/sql-command.d.ts +6 -1
- package/src/validators.d.ts +1 -0
- package/src/validators.js +10 -4
- package/src/valueConverters.js +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { remult as defaultRemult } from '../src/remult-proxy.js';
|
|
1
2
|
import pg from 'pg';
|
|
2
3
|
const { Pool } = pg;
|
|
3
4
|
import { Remult } from '../src/context.js';
|
|
@@ -7,9 +8,11 @@ export class PostgresDataProvider {
|
|
|
7
8
|
pool;
|
|
8
9
|
options;
|
|
9
10
|
supportsJsonColumnType = true;
|
|
10
|
-
static getDb(
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
static getDb(dataProvider) {
|
|
12
|
+
const r = (dataProvider || defaultRemult.dataProvider);
|
|
13
|
+
if (!r._getSourceSql)
|
|
14
|
+
throw 'the data provider is not an SqlDatabase';
|
|
15
|
+
const me = r._getSourceSql();
|
|
13
16
|
if (!me.pool) {
|
|
14
17
|
throw 'the data provider is not a PostgresDataProvider';
|
|
15
18
|
}
|
|
@@ -35,6 +38,21 @@ export class PostgresDataProvider {
|
|
|
35
38
|
this.pool = new PostgresSchemaWrapper(pool, options.schema);
|
|
36
39
|
}
|
|
37
40
|
}
|
|
41
|
+
end() {
|
|
42
|
+
return this.pool.end();
|
|
43
|
+
}
|
|
44
|
+
provideMigrationBuilder(builder) {
|
|
45
|
+
var db = new SqlDatabase(this);
|
|
46
|
+
var sb = new PostgresSchemaBuilder(db, this.options?.schema);
|
|
47
|
+
return {
|
|
48
|
+
addColumn: async (meta, field) => {
|
|
49
|
+
builder.addSql(await sb.getAddColumnScript(meta, field));
|
|
50
|
+
},
|
|
51
|
+
createTable: async (meta) => {
|
|
52
|
+
builder.addSql(await sb.createTableScript(meta));
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
38
56
|
wrapIdentifier = (name) => name
|
|
39
57
|
.split('.')
|
|
40
58
|
.map((name) => name.startsWith('"') ? name : '"' + name.replace(/"/g, '""') + '"')
|
|
@@ -172,4 +190,7 @@ export class PostgresSchemaWrapper {
|
|
|
172
190
|
c.release();
|
|
173
191
|
}
|
|
174
192
|
}
|
|
193
|
+
end() {
|
|
194
|
+
return this.pool.end();
|
|
195
|
+
}
|
|
175
196
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dbNamesOf, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
|
|
1
|
+
import { dbNamesOf, shouldCreateEntity, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
|
|
2
2
|
import { remult as defaultRemult } from '../src/remult-proxy.js';
|
|
3
3
|
import { remultStatic } from '../src/remult-static.js';
|
|
4
4
|
import { isAutoIncrement } from '../src/remult3/RepositoryImplementation.js';
|
|
@@ -19,7 +19,7 @@ export function postgresColumnSyntax(x, dbName) {
|
|
|
19
19
|
if (x.valueConverter == ValueConverters.DateOnly)
|
|
20
20
|
result += ' date';
|
|
21
21
|
else
|
|
22
|
-
result += '
|
|
22
|
+
result += ' timestamptz';
|
|
23
23
|
else
|
|
24
24
|
result += ' ' + x.valueConverter.fieldTypeInDb;
|
|
25
25
|
}
|
|
@@ -109,11 +109,9 @@ export class PostgresSchemaBuilder {
|
|
|
109
109
|
for (const entity of entities) {
|
|
110
110
|
let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
|
|
111
111
|
try {
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
await this.verifyAllColumns(entity);
|
|
116
|
-
}
|
|
112
|
+
if (shouldCreateEntity(entity, e)) {
|
|
113
|
+
await this.createIfNotExist(entity);
|
|
114
|
+
await this.verifyAllColumns(entity);
|
|
117
115
|
}
|
|
118
116
|
}
|
|
119
117
|
catch (err) {
|
|
@@ -130,29 +128,41 @@ export class PostgresSchemaBuilder {
|
|
|
130
128
|
`${this.whereTableAndSchema(c, e)}`)
|
|
131
129
|
.then(async (r) => {
|
|
132
130
|
if (r.rows.length == 0) {
|
|
133
|
-
|
|
134
|
-
for (const x of entity.fields) {
|
|
135
|
-
if (!shouldNotCreateField(x, e) || isAutoIncrement(x)) {
|
|
136
|
-
if (result.length != 0)
|
|
137
|
-
result += ',';
|
|
138
|
-
result += '\r\n ';
|
|
139
|
-
if (isAutoIncrement(x))
|
|
140
|
-
result += e.$dbNameOf(x) + ' serial';
|
|
141
|
-
else {
|
|
142
|
-
result += postgresColumnSyntax(x, e.$dbNameOf(x));
|
|
143
|
-
}
|
|
144
|
-
if (x == entity.idMetadata.field)
|
|
145
|
-
result += ' primary key';
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
let sql = `CREATE SCHEMA IF NOT EXISTS ${this.schemaOnly(e)};
|
|
149
|
-
CREATE table ${this.schemaAndName(e)} (${result}\r\n)`;
|
|
131
|
+
const sql = await this.createTableScript(entity);
|
|
150
132
|
if (PostgresSchemaBuilder.logToConsole)
|
|
151
133
|
console.info(sql);
|
|
152
134
|
await this.pool.execute(sql);
|
|
153
135
|
}
|
|
154
136
|
});
|
|
155
137
|
}
|
|
138
|
+
/* @internal*/
|
|
139
|
+
async getAddColumnScript(entity, field) {
|
|
140
|
+
let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
|
|
141
|
+
return (`ALTER table ${this.schemaAndName(e)} ` +
|
|
142
|
+
`ADD column ${postgresColumnSyntax(field, e.$dbNameOf(field))}`);
|
|
143
|
+
}
|
|
144
|
+
/* @internal*/
|
|
145
|
+
async createTableScript(entity) {
|
|
146
|
+
let result = '';
|
|
147
|
+
let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
|
|
148
|
+
for (const x of entity.fields) {
|
|
149
|
+
if (!shouldNotCreateField(x, e) || isAutoIncrement(x)) {
|
|
150
|
+
if (result.length != 0)
|
|
151
|
+
result += ',';
|
|
152
|
+
result += '\r\n ';
|
|
153
|
+
if (isAutoIncrement(x))
|
|
154
|
+
result += e.$dbNameOf(x) + ' serial';
|
|
155
|
+
else {
|
|
156
|
+
result += postgresColumnSyntax(x, e.$dbNameOf(x));
|
|
157
|
+
}
|
|
158
|
+
if (x == entity.idMetadata.field)
|
|
159
|
+
result += ' primary key';
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let sql = `CREATE SCHEMA IF NOT EXISTS ${this.schemaOnly(e)};
|
|
163
|
+
CREATE table ${this.schemaAndName(e)} (${result}\r\n)`;
|
|
164
|
+
return sql;
|
|
165
|
+
}
|
|
156
166
|
async addColumnIfNotExist(entity, c) {
|
|
157
167
|
let e = await dbNamesOf(entity, this.pool.wrapIdentifier);
|
|
158
168
|
if (shouldNotCreateField(c(entity), e))
|
|
@@ -163,8 +173,7 @@ CREATE table ${this.schemaAndName(e)} (${result}\r\n)`;
|
|
|
163
173
|
if ((await cmd.execute(`SELECT 1 FROM information_schema.columns WHERE ` +
|
|
164
174
|
`${this.whereTableAndSchema(cmd, e)} ` +
|
|
165
175
|
`AND column_name=${cmd.param(colName.toLocaleLowerCase())}`)).rows.length == 0) {
|
|
166
|
-
let sql =
|
|
167
|
-
`ADD column ${postgresColumnSyntax(c(entity), colName)}`;
|
|
176
|
+
let sql = await this.getAddColumnScript(entity, c(entity));
|
|
168
177
|
if (PostgresSchemaBuilder.logToConsole)
|
|
169
178
|
console.info(sql);
|
|
170
179
|
await this.pool.execute(sql);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SqliteCoreDataProvider } from './remult-sqlite-core.js';
|
|
2
|
+
export class BetterSqlite3DataProvider extends SqliteCoreDataProvider {
|
|
3
|
+
constructor(db) {
|
|
4
|
+
super(() => new BetterSqlite3Command(db), async () => { db.close(); });
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
class BetterSqlite3Command {
|
|
8
|
+
db;
|
|
9
|
+
values = {};
|
|
10
|
+
i = 0;
|
|
11
|
+
constructor(db) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
}
|
|
14
|
+
async execute(sql) {
|
|
15
|
+
const s = this.db.prepare(sql);
|
|
16
|
+
if (s.reader) {
|
|
17
|
+
return new BetterSqlite3SqlResult(s.all(this.values));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const result = s.run(this.values);
|
|
21
|
+
return new BetterSqlite3SqlResult([]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
addParameterAndReturnSqlToken(val) {
|
|
25
|
+
return this.param(val);
|
|
26
|
+
}
|
|
27
|
+
param(val) {
|
|
28
|
+
if (val instanceof Date)
|
|
29
|
+
val = val.valueOf();
|
|
30
|
+
if (typeof val === "boolean")
|
|
31
|
+
val = val ? 1 : 0;
|
|
32
|
+
const key = ':' + (this.i++);
|
|
33
|
+
this.values[key.substring(1)] = (val);
|
|
34
|
+
return key;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export class BetterSqlite3SqlResult {
|
|
38
|
+
result;
|
|
39
|
+
constructor(result) {
|
|
40
|
+
this.result = result;
|
|
41
|
+
this.rows = result;
|
|
42
|
+
}
|
|
43
|
+
rows;
|
|
44
|
+
getColumnKeyInResultForIndexInSelect(index) {
|
|
45
|
+
return Object.keys(this.result[0])[index];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { SqliteCoreDataProvider } from "./remult-sqlite-core.js";
|
|
2
|
+
export class BunSqliteDataProvider extends SqliteCoreDataProvider {
|
|
3
|
+
constructor(db) {
|
|
4
|
+
super(() => new BunSqliteCommand(db), async () => { db.close(); });
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
class BunSqliteCommand {
|
|
8
|
+
db;
|
|
9
|
+
values = {};
|
|
10
|
+
i = 0;
|
|
11
|
+
constructor(db) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
}
|
|
14
|
+
async execute(sql) {
|
|
15
|
+
const s = this.db.query(sql);
|
|
16
|
+
return new BunSqliteSqlResult(s.all(this.values));
|
|
17
|
+
}
|
|
18
|
+
addParameterAndReturnSqlToken(val) {
|
|
19
|
+
return this.param(val);
|
|
20
|
+
}
|
|
21
|
+
param(val) {
|
|
22
|
+
if (val instanceof Date)
|
|
23
|
+
val = val.valueOf();
|
|
24
|
+
if (typeof val === "boolean")
|
|
25
|
+
val = val ? 1 : 0;
|
|
26
|
+
const key = ':' + (this.i++);
|
|
27
|
+
this.values[key] = (val);
|
|
28
|
+
return key;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
class BunSqliteSqlResult {
|
|
32
|
+
result;
|
|
33
|
+
constructor(result) {
|
|
34
|
+
this.result = result;
|
|
35
|
+
this.rows = result;
|
|
36
|
+
}
|
|
37
|
+
rows;
|
|
38
|
+
getColumnKeyInResultForIndexInSelect(index) {
|
|
39
|
+
return Object.keys(this.result[0])[index];
|
|
40
|
+
}
|
|
41
|
+
}
|
package/esm/remult-knex/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CustomSqlFilterBuilder, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
|
|
2
|
+
import { dbNamesOf, isDbReadonly, shouldCreateEntity, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
|
|
2
3
|
import { customDatabaseFilterToken, Filter, } from '../src/filter/filter-interfaces.js';
|
|
3
4
|
import { CompoundIdField } from '../src/CompoundIdField.js';
|
|
4
5
|
import { remult as remultContext } from '../src/remult-proxy.js';
|
|
@@ -13,8 +14,36 @@ export class KnexDataProvider {
|
|
|
13
14
|
constructor(knex) {
|
|
14
15
|
this.knex = knex;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
end() {
|
|
18
|
+
return this.knex.destroy();
|
|
19
|
+
}
|
|
20
|
+
/* @internal */
|
|
21
|
+
provideMigrationBuilder(builder) {
|
|
22
|
+
var sb = new KnexSchemaBuilder(this.knex);
|
|
23
|
+
return {
|
|
24
|
+
async createTable(entity) {
|
|
25
|
+
let e = await dbNamesOf(entity, (x) => x);
|
|
26
|
+
sb.createTableKnexCommand(entity, e)
|
|
27
|
+
.toSQL()
|
|
28
|
+
.forEach((sql) => builder.addSql(sql.sql));
|
|
29
|
+
},
|
|
30
|
+
async addColumn(entity, field) {
|
|
31
|
+
let e = await dbNamesOf(entity, (x) => x);
|
|
32
|
+
await sb
|
|
33
|
+
.createColumnKnexCommand(e, field, e.$dbNameOf(field))
|
|
34
|
+
.toSQL()
|
|
35
|
+
.forEach((sql) => builder.addSql(sql.sql));
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
createCommand() {
|
|
40
|
+
return new KnexBridgeToSQLCommand(this.knex);
|
|
41
|
+
}
|
|
42
|
+
execute(sql) {
|
|
43
|
+
return this.createCommand().execute(sql);
|
|
44
|
+
}
|
|
45
|
+
static getDb(dataProvider) {
|
|
46
|
+
const r = (dataProvider || remultContext.dataProvider);
|
|
18
47
|
if (!r.knex)
|
|
19
48
|
throw 'the data provider is not an KnexDataProvider';
|
|
20
49
|
return r.knex;
|
|
@@ -43,7 +72,7 @@ export class KnexDataProvider {
|
|
|
43
72
|
}
|
|
44
73
|
}
|
|
45
74
|
}
|
|
46
|
-
return new KnexEntityDataProvider(entity, this.knex);
|
|
75
|
+
return new KnexEntityDataProvider(entity, this.knex, this.wrapIdentifier);
|
|
47
76
|
}
|
|
48
77
|
async transaction(action) {
|
|
49
78
|
let t = await this.knex.transaction();
|
|
@@ -63,9 +92,9 @@ export class KnexDataProvider {
|
|
|
63
92
|
},
|
|
64
93
|
};
|
|
65
94
|
}
|
|
66
|
-
static async filterToRaw(entity, condition) {
|
|
95
|
+
static async filterToRaw(entity, condition, wrapIdentifier) {
|
|
67
96
|
const repo = getRepository(entity);
|
|
68
|
-
var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata, (x) => x));
|
|
97
|
+
var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata, (x) => x), wrapIdentifier);
|
|
69
98
|
b._addWhere = false;
|
|
70
99
|
await (await getRepositoryInternals(repo)._translateWhereToFilter(condition)).__applyToConsumer(b);
|
|
71
100
|
let r = await b.resolveWhere();
|
|
@@ -80,13 +109,15 @@ export class KnexDataProvider {
|
|
|
80
109
|
class KnexEntityDataProvider {
|
|
81
110
|
entity;
|
|
82
111
|
knex;
|
|
83
|
-
|
|
112
|
+
rawSqlWrapIdentifier;
|
|
113
|
+
constructor(entity, knex, rawSqlWrapIdentifier) {
|
|
84
114
|
this.entity = entity;
|
|
85
115
|
this.knex = knex;
|
|
116
|
+
this.rawSqlWrapIdentifier = rawSqlWrapIdentifier;
|
|
86
117
|
}
|
|
87
118
|
async count(where) {
|
|
88
119
|
const e = await this.init();
|
|
89
|
-
const br = new FilterConsumerBridgeToKnexRequest(e);
|
|
120
|
+
const br = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
|
|
90
121
|
where.__applyToConsumer(br);
|
|
91
122
|
let r = await br.resolveWhere();
|
|
92
123
|
const result = await this.knex(e.$entityName)
|
|
@@ -115,7 +146,7 @@ class KnexEntityDataProvider {
|
|
|
115
146
|
}
|
|
116
147
|
let query = this.knex(e.$entityName).select(cols);
|
|
117
148
|
if (options?.where) {
|
|
118
|
-
const br = new FilterConsumerBridgeToKnexRequest(e);
|
|
149
|
+
const br = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
|
|
119
150
|
options.where.__applyToConsumer(br);
|
|
120
151
|
let r = await br.resolveWhere();
|
|
121
152
|
query.where((b) => r.forEach((y) => y(b)));
|
|
@@ -160,11 +191,12 @@ class KnexEntityDataProvider {
|
|
|
160
191
|
return r.$dbNameOf(f);
|
|
161
192
|
},
|
|
162
193
|
$entityName: r.$entityName,
|
|
194
|
+
wrapIdentifier: r.wrapIdentifier,
|
|
163
195
|
};
|
|
164
196
|
}
|
|
165
197
|
async update(id, data) {
|
|
166
198
|
const e = await this.init();
|
|
167
|
-
let f = new FilterConsumerBridgeToKnexRequest(e);
|
|
199
|
+
let f = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
|
|
168
200
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
169
201
|
let resultFilter = this.entity.idMetadata.getIdFilter(id);
|
|
170
202
|
if (data.id != undefined)
|
|
@@ -191,7 +223,7 @@ class KnexEntityDataProvider {
|
|
|
191
223
|
}
|
|
192
224
|
async delete(id) {
|
|
193
225
|
const e = await this.init();
|
|
194
|
-
let f = new FilterConsumerBridgeToKnexRequest(e);
|
|
226
|
+
let f = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
|
|
195
227
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
196
228
|
let where = await f.resolveWhere();
|
|
197
229
|
await this.knex(e.$entityName)
|
|
@@ -239,7 +271,8 @@ class KnexEntityDataProvider {
|
|
|
239
271
|
}
|
|
240
272
|
}
|
|
241
273
|
class FilterConsumerBridgeToKnexRequest {
|
|
242
|
-
|
|
274
|
+
innerNameProvider;
|
|
275
|
+
rawSqlWrapIdentifier;
|
|
243
276
|
_addWhere = true;
|
|
244
277
|
promises = [];
|
|
245
278
|
result = [];
|
|
@@ -253,8 +286,9 @@ class FilterConsumerBridgeToKnexRequest {
|
|
|
253
286
|
}
|
|
254
287
|
return this.result;
|
|
255
288
|
}
|
|
256
|
-
constructor(
|
|
257
|
-
this.
|
|
289
|
+
constructor(innerNameProvider, rawSqlWrapIdentifier) {
|
|
290
|
+
this.innerNameProvider = innerNameProvider;
|
|
291
|
+
this.rawSqlWrapIdentifier = rawSqlWrapIdentifier;
|
|
258
292
|
}
|
|
259
293
|
custom(key, customItem) {
|
|
260
294
|
throw new Error('Custom filter should be translated before it gets here');
|
|
@@ -263,7 +297,7 @@ class FilterConsumerBridgeToKnexRequest {
|
|
|
263
297
|
this.promises.push((async () => {
|
|
264
298
|
const result = [];
|
|
265
299
|
for (const element of orElements) {
|
|
266
|
-
let f = new FilterConsumerBridgeToKnexRequest(this.
|
|
300
|
+
let f = new FilterConsumerBridgeToKnexRequest(this.innerNameProvider, this.rawSqlWrapIdentifier);
|
|
267
301
|
f._addWhere = false;
|
|
268
302
|
element.__applyToConsumer(f);
|
|
269
303
|
let where = await f.resolveWhere();
|
|
@@ -283,13 +317,13 @@ class FilterConsumerBridgeToKnexRequest {
|
|
|
283
317
|
})());
|
|
284
318
|
}
|
|
285
319
|
isNull(col) {
|
|
286
|
-
this.result.push((b) => b.whereNull(this.
|
|
320
|
+
this.result.push((b) => b.whereNull(this.innerNameProvider.$dbNameOf(col)));
|
|
287
321
|
}
|
|
288
322
|
isNotNull(col) {
|
|
289
|
-
this.result.push((b) => b.whereNotNull(this.
|
|
323
|
+
this.result.push((b) => b.whereNotNull(this.innerNameProvider.$dbNameOf(col)));
|
|
290
324
|
}
|
|
291
325
|
isIn(col, val) {
|
|
292
|
-
this.result.push((knex) => knex.whereIn(this.
|
|
326
|
+
this.result.push((knex) => knex.whereIn(this.innerNameProvider.$dbNameOf(col), val.map((x) => translateValueAndHandleArrayAndHandleArray(col, x))));
|
|
293
327
|
}
|
|
294
328
|
isEqualTo(col, val) {
|
|
295
329
|
this.add(col, val, '=');
|
|
@@ -311,7 +345,7 @@ class FilterConsumerBridgeToKnexRequest {
|
|
|
311
345
|
}
|
|
312
346
|
containsCaseInsensitive(col, val) {
|
|
313
347
|
this.result.push((b) => b.whereRaw('lower (' +
|
|
314
|
-
b.client.ref(this.
|
|
348
|
+
b.client.ref(this.innerNameProvider.$dbNameOf(col)) +
|
|
315
349
|
") like lower ('%" +
|
|
316
350
|
val.replace(/'/g, "''") +
|
|
317
351
|
"%')"));
|
|
@@ -319,20 +353,30 @@ class FilterConsumerBridgeToKnexRequest {
|
|
|
319
353
|
}
|
|
320
354
|
notContainsCaseInsensitive(col, val) {
|
|
321
355
|
this.result.push((b) => b.whereRaw('not lower (' +
|
|
322
|
-
b.client.ref(this.
|
|
356
|
+
b.client.ref(this.innerNameProvider.$dbNameOf(col)) +
|
|
323
357
|
") like lower ('%" +
|
|
324
358
|
val.replace(/'/g, "''") +
|
|
325
359
|
"%')"));
|
|
326
360
|
this.promises.push((async () => { })());
|
|
327
361
|
}
|
|
328
362
|
add(col, val, operator) {
|
|
329
|
-
this.result.push((b) => b.where(this.
|
|
363
|
+
this.result.push((b) => b.where(this.innerNameProvider.$dbNameOf(col), operator, translateValueAndHandleArrayAndHandleArray(col, val)));
|
|
330
364
|
}
|
|
331
365
|
databaseCustom(databaseCustom) {
|
|
332
366
|
this.promises.push((async () => {
|
|
333
367
|
if (databaseCustom?.buildKnex) {
|
|
334
368
|
this.result.push(await databaseCustom.buildKnex());
|
|
335
369
|
}
|
|
370
|
+
if (databaseCustom?.buildSql) {
|
|
371
|
+
let r = new KnexCommandHelper();
|
|
372
|
+
const item = new CustomSqlFilterBuilder(r, this.rawSqlWrapIdentifier);
|
|
373
|
+
let sql = await databaseCustom.buildSql(item);
|
|
374
|
+
if (typeof sql !== 'string')
|
|
375
|
+
sql = item.sql;
|
|
376
|
+
if (sql) {
|
|
377
|
+
this.result.push((b) => b.whereRaw(sql, r.values));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
336
380
|
})());
|
|
337
381
|
}
|
|
338
382
|
}
|
|
@@ -350,11 +394,9 @@ export class KnexSchemaBuilder {
|
|
|
350
394
|
for (const entity of entities) {
|
|
351
395
|
let e = await dbNamesOf(entity, (x) => x);
|
|
352
396
|
try {
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
await this.verifyAllColumns(entity);
|
|
357
|
-
}
|
|
397
|
+
if (shouldCreateEntity(entity, e)) {
|
|
398
|
+
await this.createIfNotExist(entity);
|
|
399
|
+
await this.verifyAllColumns(entity);
|
|
358
400
|
}
|
|
359
401
|
}
|
|
360
402
|
catch (err) {
|
|
@@ -366,27 +408,30 @@ export class KnexSchemaBuilder {
|
|
|
366
408
|
async createIfNotExist(entity) {
|
|
367
409
|
const e = await dbNamesOf(entity, (x) => x);
|
|
368
410
|
if (!(await this.knex.schema.hasTable(e.$entityName))) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
411
|
+
await logSql(this.createTableKnexCommand(entity, e));
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
createTableKnexCommand(entity, e) {
|
|
415
|
+
let cols = new Map();
|
|
416
|
+
for (const f of entity.fields) {
|
|
417
|
+
cols.set(f, {
|
|
418
|
+
name: e.$dbNameOf(f),
|
|
419
|
+
readonly: shouldNotCreateField(f, e),
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
return this.knex.schema.createTable(e.$entityName, (b) => {
|
|
423
|
+
for (const x of entity.fields) {
|
|
424
|
+
if (!cols.get(x).readonly || isAutoIncrement(x)) {
|
|
425
|
+
if (isAutoIncrement(x))
|
|
426
|
+
b.increments(cols.get(x).name);
|
|
427
|
+
else {
|
|
428
|
+
buildColumn(x, cols.get(x).name, b, supportsJsonDataStorage(this.knex));
|
|
429
|
+
if (x == entity.idMetadata.field)
|
|
430
|
+
b.primary([cols.get(x).name]);
|
|
386
431
|
}
|
|
387
432
|
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
433
|
+
}
|
|
434
|
+
});
|
|
390
435
|
}
|
|
391
436
|
async addColumnIfNotExist(entity, c) {
|
|
392
437
|
let e = await dbNamesOf(entity, (x) => x);
|
|
@@ -395,11 +440,14 @@ export class KnexSchemaBuilder {
|
|
|
395
440
|
let col = c(entity);
|
|
396
441
|
let colName = e.$dbNameOf(col);
|
|
397
442
|
if (!(await this.knex.schema.hasColumn(e.$entityName, colName))) {
|
|
398
|
-
await logSql(this.
|
|
399
|
-
buildColumn(col, colName, b, supportsJsonDataStorage(this.knex));
|
|
400
|
-
}));
|
|
443
|
+
await logSql(this.createColumnKnexCommand(e, col, colName));
|
|
401
444
|
}
|
|
402
445
|
}
|
|
446
|
+
createColumnKnexCommand(e, col, colName) {
|
|
447
|
+
return this.knex.schema.alterTable(e.$entityName, (b) => {
|
|
448
|
+
buildColumn(col, colName, b, supportsJsonDataStorage(this.knex));
|
|
449
|
+
});
|
|
450
|
+
}
|
|
403
451
|
async verifyAllColumns(entity) {
|
|
404
452
|
let e = await dbNamesOf(entity, (x) => x);
|
|
405
453
|
try {
|
|
@@ -475,16 +523,24 @@ export function buildColumn(x, dbName, b, supportsJson = true) {
|
|
|
475
523
|
else if (x.valueConverter.fieldTypeInDb == 'json')
|
|
476
524
|
if (supportsJson)
|
|
477
525
|
b.json(dbName);
|
|
478
|
-
else
|
|
479
|
-
b.text(dbName);
|
|
526
|
+
else {
|
|
527
|
+
let c = b.text(dbName);
|
|
528
|
+
if (!x.allowNull)
|
|
529
|
+
c.defaultTo('').notNullable();
|
|
530
|
+
}
|
|
480
531
|
else
|
|
481
532
|
b.specificType(dbName, x.valueConverter.fieldTypeInDb);
|
|
482
533
|
}
|
|
483
|
-
else {
|
|
534
|
+
else if (x.valueType === String) {
|
|
484
535
|
let c = b.string(dbName, x.options.maxLength);
|
|
485
536
|
if (!x.allowNull)
|
|
486
537
|
c.defaultTo('').notNullable();
|
|
487
538
|
}
|
|
539
|
+
else {
|
|
540
|
+
let c = b.text(dbName);
|
|
541
|
+
if (!x.allowNull)
|
|
542
|
+
c.defaultTo('').notNullable();
|
|
543
|
+
}
|
|
488
544
|
}
|
|
489
545
|
function logSql(who) {
|
|
490
546
|
if (KnexSchemaBuilder.logToConsole)
|
|
@@ -502,3 +558,76 @@ function translateValueAndHandleArrayAndHandleArray(field, val) {
|
|
|
502
558
|
return JSON.stringify(result);
|
|
503
559
|
return result;
|
|
504
560
|
}
|
|
561
|
+
class KnexCommandHelper {
|
|
562
|
+
values = {};
|
|
563
|
+
i = 0;
|
|
564
|
+
addParameterAndReturnSqlToken(val) {
|
|
565
|
+
return this.param(val);
|
|
566
|
+
}
|
|
567
|
+
param(val) {
|
|
568
|
+
if (Array.isArray(val))
|
|
569
|
+
val = JSON.stringify(val);
|
|
570
|
+
const key = ':' + this.i++;
|
|
571
|
+
this.values[key.substring(1)] = val;
|
|
572
|
+
return key;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
class KnexBridgeToSQLCommand extends KnexCommandHelper {
|
|
576
|
+
source;
|
|
577
|
+
constructor(source) {
|
|
578
|
+
super();
|
|
579
|
+
this.source = source;
|
|
580
|
+
}
|
|
581
|
+
values = {};
|
|
582
|
+
i = 0;
|
|
583
|
+
addParameterAndReturnSqlToken(val) {
|
|
584
|
+
return this.param(val);
|
|
585
|
+
}
|
|
586
|
+
param(val) {
|
|
587
|
+
if (Array.isArray(val))
|
|
588
|
+
val = JSON.stringify(val);
|
|
589
|
+
const key = ':' + this.i++;
|
|
590
|
+
this.values[key.substring(1)] = val;
|
|
591
|
+
return key;
|
|
592
|
+
}
|
|
593
|
+
async execute(sql) {
|
|
594
|
+
return await this.source.raw(sql, this.values).then((r) => {
|
|
595
|
+
switch (this.source.client.config.client) {
|
|
596
|
+
case 'mysql':
|
|
597
|
+
case 'mysql2':
|
|
598
|
+
return new KnexPostgresBridgeToSQLQueryResult({
|
|
599
|
+
fields: r[1],
|
|
600
|
+
rows: r[0],
|
|
601
|
+
});
|
|
602
|
+
case 'pg':
|
|
603
|
+
return new KnexPostgresBridgeToSQLQueryResult(r);
|
|
604
|
+
default:
|
|
605
|
+
case 'better-sqlite3':
|
|
606
|
+
case 'mssql':
|
|
607
|
+
return new KnexPostgresBridgeToSQLQueryResult({
|
|
608
|
+
rows: r,
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
class KnexPostgresBridgeToSQLQueryResult {
|
|
615
|
+
r;
|
|
616
|
+
getColumnKeyInResultForIndexInSelect(index) {
|
|
617
|
+
if (this.r.fields)
|
|
618
|
+
return this.r.fields[index].name;
|
|
619
|
+
if (this.rows.length == 0)
|
|
620
|
+
throw Error('No rows');
|
|
621
|
+
let i = 0;
|
|
622
|
+
for (let m in this.rows[0]) {
|
|
623
|
+
if (i++ == index)
|
|
624
|
+
return m;
|
|
625
|
+
}
|
|
626
|
+
throw Error('index not found');
|
|
627
|
+
}
|
|
628
|
+
constructor(r) {
|
|
629
|
+
this.r = r;
|
|
630
|
+
this.rows = r.rows;
|
|
631
|
+
}
|
|
632
|
+
rows;
|
|
633
|
+
}
|
package/esm/remult-mongo.js
CHANGED
|
@@ -16,8 +16,8 @@ export class MongoDataProvider {
|
|
|
16
16
|
}
|
|
17
17
|
session;
|
|
18
18
|
disableTransactions = false;
|
|
19
|
-
static getDb(
|
|
20
|
-
const r = (
|
|
19
|
+
static getDb(dataProvider) {
|
|
20
|
+
const r = (dataProvider || remultContext.dataProvider);
|
|
21
21
|
if (!r.db)
|
|
22
22
|
throw 'the data provider is not a MongoDataProvider';
|
|
23
23
|
return { db: r.db, session: r.session };
|