remult 0.16.3-exp.1 → 0.16.3-exp.2
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 +3 -5
- package/esm/index.d.ts +1 -2
- package/esm/index.js +1 -2
- package/esm/postgres/postgres-data-provider.d.ts +3 -1
- package/esm/postgres/postgres-data-provider.js +11 -1
- package/esm/postgres/schema-builder.js +20 -20
- package/esm/remult-knex/index.d.ts +4 -28
- package/esm/remult-knex/index.js +46 -33
- package/esm/remult-mongo.d.ts +8 -2
- package/esm/remult-mongo.js +22 -8
- package/esm/server/expressBridge.d.ts +1 -0
- package/esm/src/backend-tests/my-test.backend-spec.js +66 -2
- package/esm/src/context.d.ts +2 -1
- package/esm/src/context.js +2 -4
- package/esm/src/data-providers/sql-database.d.ts +2 -0
- package/esm/src/data-providers/sql-database.js +26 -15
- package/esm/src/data-providers/web-sql-data-provider.d.ts +3 -0
- package/esm/src/data-providers/web-sql-data-provider.js +16 -8
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.d.ts +13 -14
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +52 -19
- package/esm/src/remult-proxy.js +2 -2
- package/esm/src/remult3/RepositoryImplementation.d.ts +1 -2
- package/esm/src/remult3/RepositoryImplementation.js +17 -12
- package/esm/src/shared-tests/db-tests-setup.js +1 -2
- package/esm/src/tests/entityForCustomFilter.js +3 -4
- package/esm/src/tests/frontend-database-tests-setup.spec.js +1 -2
- package/esm/src/tests/testHelper.spec.js +0 -1
- package/index.d.ts +1 -2
- package/index.js +3 -3
- package/package.json +1 -1
- package/postgres/postgres-data-provider.d.ts +3 -1
- package/postgres/postgres-data-provider.js +11 -1
- package/postgres/schema-builder.js +19 -19
- package/remult-knex/index.d.ts +4 -28
- package/remult-knex/index.js +68 -38
- package/remult-mongo.d.ts +8 -2
- package/remult-mongo.js +39 -8
- package/server/expressBridge.d.ts +1 -0
- package/src/backend-tests/my-test.backend-spec.js +212 -0
- package/src/context.d.ts +2 -1
- package/src/context.js +6 -9
- package/src/data-providers/sql-database.d.ts +2 -0
- package/src/data-providers/sql-database.js +25 -14
- package/src/data-providers/web-sql-data-provider.d.ts +3 -0
- package/src/data-providers/web-sql-data-provider.js +15 -7
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +13 -14
- package/src/filter/filter-consumer-bridge-to-sql-request.js +95 -46
- package/src/remult-proxy.js +6 -1
- package/src/remult3/RepositoryImplementation.d.ts +1 -2
- package/src/remult3/RepositoryImplementation.js +31 -16
- package/src/shared-tests/db-tests-setup.js +2 -3
- package/src/tests/entityForCustomFilter.js +3 -4
- package/src/tests/frontend-database-tests-setup.spec.js +4 -5
- package/src/tests/testHelper.spec.js +3 -4
package/README.md
CHANGED
|
@@ -128,11 +128,9 @@ app.listen(port, () => {
|
|
|
128
128
|
```ts
|
|
129
129
|
// frontend/code.ts
|
|
130
130
|
|
|
131
|
-
import {
|
|
131
|
+
import { remult } from "remult";
|
|
132
132
|
import { Product } from "../shared/product";
|
|
133
133
|
|
|
134
|
-
const remult = new Remult();
|
|
135
|
-
|
|
136
134
|
async function increasePriceOfTofu(priceIncrease: number) {
|
|
137
135
|
const productsRepo = remult.repo(Product);
|
|
138
136
|
|
|
@@ -146,8 +144,8 @@ async function increasePriceOfTofu(priceIncrease: number) {
|
|
|
146
144
|
|
|
147
145
|
```ts
|
|
148
146
|
@BackendMethod({ allowed: Allow.authenticated })
|
|
149
|
-
static async increasePriceOfTofu(priceIncrease: number
|
|
150
|
-
const productsRepo = remult
|
|
147
|
+
static async increasePriceOfTofu(priceIncrease: number) {
|
|
148
|
+
const productsRepo = remult.repo(Product);
|
|
151
149
|
|
|
152
150
|
const product = await productsRepo.findFirst({ name: 'Tofu' }); // use Remult in the backend as an ORM
|
|
153
151
|
product.unitPrice += priceIncrease;
|
package/esm/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { InMemoryDataProvider } from './src/data-providers/in-memory-database';
|
|
|
10
10
|
export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider';
|
|
11
11
|
export { WebSqlDataProvider } from './src/data-providers/web-sql-data-provider';
|
|
12
12
|
export { SqlDatabase, } from './src/data-providers/sql-database';
|
|
13
|
-
export { CustomSqlFilterObject, CustomSqlFilterBuilder } from './src/filter/filter-consumer-bridge-to-sql-request';
|
|
13
|
+
export { CustomSqlFilterObject, CustomSqlFilterBuilder, dbNamesOf, sqlCondition } from './src/filter/filter-consumer-bridge-to-sql-request';
|
|
14
14
|
export { JsonDataProvider, JsonEntityStorage } from './src/data-providers/json-data-provider';
|
|
15
15
|
export { Controller, BackendMethodOptions, BackendMethod, ProgressListener } from './src/server-action';
|
|
16
16
|
export { Allowed, Allow, Remult, RemultContext, ApiClient, isBackend, AllowedForInstance, EventDispatcher, EventSource, ExternalHttpProvider, Unobserve, UserInfo } from './src/context';
|
|
@@ -18,7 +18,6 @@ export { IdEntity } from './src/id-entity';
|
|
|
18
18
|
export { SortSegment, Sort } from './src/sort';
|
|
19
19
|
export { OneToMany, CompoundIdField } from './src/column';
|
|
20
20
|
export { Filter } from './src/filter/filter-interfaces';
|
|
21
|
-
export { FilterConsumerBridgeToSqlRequest } from './src/filter/filter-consumer-bridge-to-sql-request';
|
|
22
21
|
export { UrlBuilder } from './urlBuilder';
|
|
23
22
|
export { Validators } from './src/validators';
|
|
24
23
|
export { ValueConverters } from './src/valueConverters';
|
package/esm/index.js
CHANGED
|
@@ -8,7 +8,7 @@ export { InMemoryDataProvider } from './src/data-providers/in-memory-database';
|
|
|
8
8
|
export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider'; //V
|
|
9
9
|
export { WebSqlDataProvider } from './src/data-providers/web-sql-data-provider'; //V
|
|
10
10
|
export { SqlDatabase, } from './src/data-providers/sql-database'; //V
|
|
11
|
-
export { CustomSqlFilterBuilder } from './src/filter/filter-consumer-bridge-to-sql-request';
|
|
11
|
+
export { CustomSqlFilterBuilder, dbNamesOf, sqlCondition } from './src/filter/filter-consumer-bridge-to-sql-request';
|
|
12
12
|
export { JsonDataProvider } from './src/data-providers/json-data-provider'; //V
|
|
13
13
|
//export * from './src/data-api'; //reconsider if to make internal
|
|
14
14
|
export { Controller, BackendMethod, ProgressListener } from './src/server-action';
|
|
@@ -17,7 +17,6 @@ export { IdEntity } from './src/id-entity';
|
|
|
17
17
|
export { Sort } from './src/sort';
|
|
18
18
|
export { OneToMany, CompoundIdField } from './src/column';
|
|
19
19
|
export { Filter } from './src/filter/filter-interfaces';
|
|
20
|
-
export { FilterConsumerBridgeToSqlRequest } from './src/filter/filter-consumer-bridge-to-sql-request';
|
|
21
20
|
export { UrlBuilder } from './urlBuilder';
|
|
22
21
|
export { Validators } from './src/validators';
|
|
23
22
|
export { ValueConverters } from './src/valueConverters';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { PoolConfig, QueryResult } from 'pg';
|
|
1
|
+
import { ClientBase, PoolConfig, QueryResult } from 'pg';
|
|
2
|
+
import { Remult } from '../src/context';
|
|
2
3
|
import { EntityMetadata } from '../src/remult3';
|
|
3
4
|
import { SqlCommand, SqlImplementation } from '../src/sql-command';
|
|
4
5
|
import { SqlDatabase } from '../src/data-providers/sql-database';
|
|
@@ -10,6 +11,7 @@ export interface PostgresClient extends PostgresCommandSource {
|
|
|
10
11
|
}
|
|
11
12
|
export declare class PostgresDataProvider implements SqlImplementation {
|
|
12
13
|
private pool;
|
|
14
|
+
static getDb(remult?: Remult): ClientBase;
|
|
13
15
|
entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
|
|
14
16
|
getLimitSqlSyntax(limit: number, offset: number): string;
|
|
15
17
|
createCommand(): SqlCommand;
|
|
@@ -6,6 +6,14 @@ export class PostgresDataProvider {
|
|
|
6
6
|
constructor(pool) {
|
|
7
7
|
this.pool = pool;
|
|
8
8
|
}
|
|
9
|
+
static getDb(remult) {
|
|
10
|
+
const sql = SqlDatabase.getDb(remult);
|
|
11
|
+
const me = sql._getSourceSql();
|
|
12
|
+
if (!me.pool) {
|
|
13
|
+
throw "the data provider is not a PostgresDataProvider";
|
|
14
|
+
}
|
|
15
|
+
return me.pool;
|
|
16
|
+
}
|
|
9
17
|
async entityIsUsedForTheFirstTime(entity) {
|
|
10
18
|
}
|
|
11
19
|
getLimitSqlSyntax(limit, offset) {
|
|
@@ -22,7 +30,9 @@ export class PostgresDataProvider {
|
|
|
22
30
|
createCommand: () => new PostgresBridgeToSQLCommand(client),
|
|
23
31
|
entityIsUsedForTheFirstTime: this.entityIsUsedForTheFirstTime,
|
|
24
32
|
transaction: () => { throw "nested transactions not allowed"; },
|
|
25
|
-
getLimitSqlSyntax: this.getLimitSqlSyntax
|
|
33
|
+
getLimitSqlSyntax: this.getLimitSqlSyntax,
|
|
34
|
+
//@ts-ignore
|
|
35
|
+
pool: client
|
|
26
36
|
});
|
|
27
37
|
await client.query('COMMIT');
|
|
28
38
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { allEntities } from '../src/context';
|
|
2
|
-
import {
|
|
2
|
+
import { dbNamesOf, isDbReadonly } from '../src/filter/filter-consumer-bridge-to-sql-request';
|
|
3
3
|
import { isAutoIncrement } from '../src/remult3';
|
|
4
4
|
import { ValueConverters } from '../src/valueConverters';
|
|
5
5
|
export function postgresColumnSyntax(x, dbName) {
|
|
@@ -46,57 +46,57 @@ export class PostgresSchemaBuilder {
|
|
|
46
46
|
console.log("start verify structure");
|
|
47
47
|
for (const entityClass of allEntities) {
|
|
48
48
|
let entity = remult.repo(entityClass).metadata;
|
|
49
|
-
let e = await
|
|
49
|
+
let e = await dbNamesOf(entity);
|
|
50
50
|
try {
|
|
51
51
|
if (!entity.options.sqlExpression) {
|
|
52
|
-
if ((await e
|
|
52
|
+
if ((await e.$entityName).toLowerCase().indexOf('from ') < 0) {
|
|
53
53
|
await this.createIfNotExist(entity);
|
|
54
54
|
await this.verifyAllColumns(entity);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
catch (err) {
|
|
59
|
-
console.log("failed verify structure of " + e
|
|
59
|
+
console.log("failed verify structure of " + e.$entityName + " ", err);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
async createIfNotExist(entity) {
|
|
64
64
|
var c = this.pool.createCommand();
|
|
65
|
-
let e = await
|
|
66
|
-
await c.execute("select 1 from information_Schema.tables where table_name=" + c.addParameterAndReturnSqlToken((e
|
|
65
|
+
let e = await dbNamesOf(entity);
|
|
66
|
+
await c.execute("select 1 from information_Schema.tables where table_name=" + c.addParameterAndReturnSqlToken((e.$entityName).toLowerCase()) + this.additionalWhere).then(async (r) => {
|
|
67
67
|
if (r.rows.length == 0) {
|
|
68
68
|
let result = '';
|
|
69
69
|
for (const x of entity.fields) {
|
|
70
|
-
if (!
|
|
70
|
+
if (!isDbReadonly(x, e) || isAutoIncrement(x)) {
|
|
71
71
|
if (result.length != 0)
|
|
72
72
|
result += ',';
|
|
73
73
|
result += '\r\n ';
|
|
74
74
|
if (isAutoIncrement(x))
|
|
75
|
-
result += e.
|
|
75
|
+
result += e.dbNameOf(x) + ' serial';
|
|
76
76
|
else {
|
|
77
|
-
result += postgresColumnSyntax(x, e.
|
|
77
|
+
result += postgresColumnSyntax(x, e.dbNameOf(x));
|
|
78
78
|
if (x == entity.idMetadata.field)
|
|
79
79
|
result += ' primary key';
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
let sql = 'create table ' + e
|
|
83
|
+
let sql = 'create table ' + e.$entityName + ' (' + result + '\r\n)';
|
|
84
84
|
//console.log(sql);
|
|
85
85
|
await this.pool.execute(sql);
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
88
|
}
|
|
89
89
|
async addColumnIfNotExist(entity, c) {
|
|
90
|
-
let e = await
|
|
91
|
-
if (
|
|
90
|
+
let e = await dbNamesOf(entity);
|
|
91
|
+
if (isDbReadonly(c(entity), e))
|
|
92
92
|
return;
|
|
93
93
|
try {
|
|
94
94
|
let cmd = this.pool.createCommand();
|
|
95
|
-
const colName = e.
|
|
95
|
+
const colName = e.dbNameOf(c(entity));
|
|
96
96
|
if ((await cmd.execute(`select 1
|
|
97
97
|
FROM information_schema.columns
|
|
98
|
-
WHERE table_name=${cmd.addParameterAndReturnSqlToken((e
|
|
99
|
-
let sql = `alter table ${e
|
|
98
|
+
WHERE table_name=${cmd.addParameterAndReturnSqlToken((e.$entityName).toLocaleLowerCase())} and column_name=${cmd.addParameterAndReturnSqlToken((colName).toLocaleLowerCase())}` + this.additionalWhere)).rows.length == 0) {
|
|
99
|
+
let sql = `alter table ${e.$entityName} add column ${postgresColumnSyntax(c(entity), colName)}`;
|
|
100
100
|
//console.log(sql);
|
|
101
101
|
await this.pool.execute(sql);
|
|
102
102
|
}
|
|
@@ -108,14 +108,14 @@ export class PostgresSchemaBuilder {
|
|
|
108
108
|
async verifyAllColumns(entity) {
|
|
109
109
|
try {
|
|
110
110
|
let cmd = this.pool.createCommand();
|
|
111
|
-
let e = await
|
|
111
|
+
let e = await dbNamesOf(entity);
|
|
112
112
|
let cols = (await cmd.execute(`select column_name
|
|
113
113
|
FROM information_schema.columns
|
|
114
|
-
WHERE table_name=${cmd.addParameterAndReturnSqlToken((e
|
|
114
|
+
WHERE table_name=${cmd.addParameterAndReturnSqlToken((e.$entityName).toLocaleLowerCase())} ` + this.additionalWhere)).rows.map(x => x.column_name);
|
|
115
115
|
for (const col of entity.fields) {
|
|
116
|
-
if (!
|
|
117
|
-
if (!cols.includes(e.
|
|
118
|
-
let sql = `alter table ${e
|
|
116
|
+
if (!isDbReadonly(col, e))
|
|
117
|
+
if (!cols.includes(e.dbNameOf(col).toLocaleLowerCase())) {
|
|
118
|
+
let sql = `alter table ${e.$entityName} add column ${postgresColumnSyntax(col, e.dbNameOf(col))}`;
|
|
119
119
|
//console.log(sql);
|
|
120
120
|
await this.pool.execute(sql);
|
|
121
121
|
}
|
|
@@ -1,43 +1,19 @@
|
|
|
1
|
-
import { Knex } from 'knex';
|
|
2
|
-
import { Filter, FilterConsumer } from "../src/filter/filter-interfaces";
|
|
3
|
-
import { dbNameProvider } from "../src/filter/filter-consumer-bridge-to-sql-request";
|
|
1
|
+
import type { Knex } from 'knex';
|
|
4
2
|
import { Remult } from "../src/context";
|
|
5
|
-
import { EntityFilter, EntityMetadata } from "../src/remult3";
|
|
3
|
+
import { EntityFilter, EntityMetadata, Repository } from "../src/remult3";
|
|
6
4
|
import { DataProvider, EntityDataProvider } from '../src/data-interfaces';
|
|
7
5
|
import { FieldMetadata } from '../src/column-interfaces';
|
|
8
6
|
export declare class KnexDataProvider implements DataProvider {
|
|
9
7
|
knex: Knex;
|
|
10
8
|
constructor(knex: Knex);
|
|
9
|
+
static getDb(remult?: Remult): Knex<any, Record<string, any>[]>;
|
|
11
10
|
getEntityDataProvider(entity: EntityMetadata<any>): EntityDataProvider;
|
|
12
11
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
13
12
|
static customFilter(build: CustomKnexFilterBuilderFunction): EntityFilter<any>;
|
|
14
13
|
supportsCustomFilter?: boolean;
|
|
15
14
|
}
|
|
16
15
|
export declare type CustomKnexFilterBuilderFunction = () => Promise<(builder: Knex.QueryBuilder) => void>;
|
|
17
|
-
export declare
|
|
18
|
-
private nameProvider;
|
|
19
|
-
_addWhere: boolean;
|
|
20
|
-
promises: Promise<void>[];
|
|
21
|
-
result: ((builder: Knex.QueryBuilder) => void)[];
|
|
22
|
-
resolveWhere(): Promise<((builder: Knex.QueryBuilder<any, any>) => void)[]>;
|
|
23
|
-
constructor(nameProvider: dbNameProvider);
|
|
24
|
-
custom(key: string, customItem: any): void;
|
|
25
|
-
or(orElements: Filter[]): void;
|
|
26
|
-
isNull(col: FieldMetadata): void;
|
|
27
|
-
isNotNull(col: FieldMetadata): void;
|
|
28
|
-
isIn(col: FieldMetadata, val: any[]): void;
|
|
29
|
-
isEqualTo(col: FieldMetadata, val: any): void;
|
|
30
|
-
isDifferentFrom(col: FieldMetadata, val: any): void;
|
|
31
|
-
isGreaterOrEqualTo(col: FieldMetadata, val: any): void;
|
|
32
|
-
isGreaterThan(col: FieldMetadata, val: any): void;
|
|
33
|
-
isLessOrEqualTo(col: FieldMetadata, val: any): void;
|
|
34
|
-
isLessThan(col: FieldMetadata, val: any): void;
|
|
35
|
-
containsCaseInsensitive(col: FieldMetadata, val: any): void;
|
|
36
|
-
private add;
|
|
37
|
-
databaseCustom(databaseCustom: {
|
|
38
|
-
buildKnex: CustomKnexFilterBuilderFunction;
|
|
39
|
-
}): void;
|
|
40
|
-
}
|
|
16
|
+
export declare function knexCondition<entityType>(repo: Repository<entityType>, condition: EntityFilter<entityType>): Promise<(knex: any) => void>;
|
|
41
17
|
export declare class KnexSchemaBuilder {
|
|
42
18
|
private knex;
|
|
43
19
|
verifyStructureOfAllEntities(remult: Remult): Promise<void>;
|
package/esm/remult-knex/index.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
import knex from 'knex';
|
|
2
1
|
import { customDatabaseFilterToken, Filter } from "../src/filter/filter-interfaces";
|
|
3
|
-
import {
|
|
2
|
+
import { dbNamesOf, isDbReadonly } from "../src/filter/filter-consumer-bridge-to-sql-request";
|
|
4
3
|
import { allEntities, Remult } from "../src/context";
|
|
5
4
|
import { isAutoIncrement } from "../src/remult3";
|
|
6
5
|
import { ValueConverters } from "../src/valueConverters";
|
|
7
6
|
import { CompoundIdField } from '../src/column';
|
|
8
7
|
import { Sort } from '../src/sort';
|
|
8
|
+
import { remult as remultContext } from '../src/remult-proxy';
|
|
9
9
|
export class KnexDataProvider {
|
|
10
10
|
constructor(knex) {
|
|
11
11
|
this.knex = knex;
|
|
12
12
|
}
|
|
13
|
+
static getDb(remult) {
|
|
14
|
+
const r = (remult || remultContext).dataProvider;
|
|
15
|
+
if (!r.knex)
|
|
16
|
+
throw "the data provider is not an KnexDataProvider";
|
|
17
|
+
return r.knex;
|
|
18
|
+
}
|
|
13
19
|
getEntityDataProvider(entity) {
|
|
14
20
|
return new KnexEntityDataProvider(entity, this.knex);
|
|
15
21
|
}
|
|
@@ -42,7 +48,7 @@ class KnexEntityDataProvider {
|
|
|
42
48
|
const br = new FilterConsumerBridgeToKnexRequest(e);
|
|
43
49
|
where.__applyToConsumer(br);
|
|
44
50
|
let r = await br.resolveWhere();
|
|
45
|
-
const result = (await this.knex(e
|
|
51
|
+
const result = (await this.knex(e.$entityName)
|
|
46
52
|
.count().where(b => r.forEach(w => w(b))));
|
|
47
53
|
var row = result[0];
|
|
48
54
|
for (const key in row) {
|
|
@@ -60,11 +66,11 @@ class KnexEntityDataProvider {
|
|
|
60
66
|
if (x.isServerExpression) {
|
|
61
67
|
}
|
|
62
68
|
else {
|
|
63
|
-
cols.push(e.
|
|
69
|
+
cols.push(e.dbNameOf(x));
|
|
64
70
|
colKeys.push(x);
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
|
-
let query = this.knex(e
|
|
73
|
+
let query = this.knex(e.$entityName).select(cols);
|
|
68
74
|
if (options?.where) {
|
|
69
75
|
const br = new FilterConsumerBridgeToKnexRequest(e);
|
|
70
76
|
options.where.__applyToConsumer(br);
|
|
@@ -76,7 +82,7 @@ class KnexEntityDataProvider {
|
|
|
76
82
|
}
|
|
77
83
|
if (options.orderBy) {
|
|
78
84
|
query = query.orderBy(options.orderBy.Segments.map(s => ({
|
|
79
|
-
column: e.
|
|
85
|
+
column: e.dbNameOf(s.field),
|
|
80
86
|
order: s.isDescending ? "desc" : "asc"
|
|
81
87
|
})));
|
|
82
88
|
}
|
|
@@ -102,7 +108,7 @@ class KnexEntityDataProvider {
|
|
|
102
108
|
});
|
|
103
109
|
}
|
|
104
110
|
async init() {
|
|
105
|
-
return await
|
|
111
|
+
return await dbNamesOf(this.entity);
|
|
106
112
|
}
|
|
107
113
|
async update(id, data) {
|
|
108
114
|
const e = await this.init();
|
|
@@ -113,17 +119,17 @@ class KnexEntityDataProvider {
|
|
|
113
119
|
resultFilter = this.entity.idMetadata.getIdFilter(data.id);
|
|
114
120
|
let updateObject = {};
|
|
115
121
|
for (const x of this.entity.fields) {
|
|
116
|
-
if (
|
|
122
|
+
if (isDbReadonly(x, e)) { }
|
|
117
123
|
else if (data[x.key] !== undefined) {
|
|
118
124
|
let v = x.valueConverter.toDb(data[x.key]);
|
|
119
125
|
if (v !== undefined) {
|
|
120
|
-
let key = await e.
|
|
126
|
+
let key = await e.dbNameOf(x);
|
|
121
127
|
updateObject[key] = v;
|
|
122
128
|
}
|
|
123
129
|
}
|
|
124
130
|
}
|
|
125
131
|
let where = await f.resolveWhere();
|
|
126
|
-
await this.knex(e
|
|
132
|
+
await this.knex(e.$entityName).update(updateObject).where(b => where.forEach(w => w(b)));
|
|
127
133
|
return this.find({ where: Filter.fromEntityFilter(this.entity, resultFilter) }).then(y => y[0]);
|
|
128
134
|
}
|
|
129
135
|
async delete(id) {
|
|
@@ -131,7 +137,7 @@ class KnexEntityDataProvider {
|
|
|
131
137
|
let f = new FilterConsumerBridgeToKnexRequest(e);
|
|
132
138
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
133
139
|
let where = await f.resolveWhere();
|
|
134
|
-
await this.knex(e
|
|
140
|
+
await this.knex(e.$entityName).delete().where(b => where.forEach(w => w(b)));
|
|
135
141
|
}
|
|
136
142
|
async insert(data) {
|
|
137
143
|
const e = await this.init();
|
|
@@ -142,16 +148,16 @@ class KnexEntityDataProvider {
|
|
|
142
148
|
resultFilter = Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(data[this.entity.idMetadata.field.key]));
|
|
143
149
|
let insertObject = {};
|
|
144
150
|
for (const x of this.entity.fields) {
|
|
145
|
-
if (
|
|
151
|
+
if (isDbReadonly(x, e)) { }
|
|
146
152
|
else {
|
|
147
153
|
let v = x.valueConverter.toDb(data[x.key]);
|
|
148
154
|
if (v != undefined) {
|
|
149
|
-
let key = await e.
|
|
155
|
+
let key = await e.dbNameOf(x);
|
|
150
156
|
insertObject[key] = v;
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
159
|
}
|
|
154
|
-
let insert = this.knex(e
|
|
160
|
+
let insert = this.knex(e.$entityName).insert(insertObject);
|
|
155
161
|
if (isAutoIncrement(this.entity.idMetadata.field)) {
|
|
156
162
|
let result = await insert.returning(this.entity.idMetadata.field.key);
|
|
157
163
|
let newId = result[0].id;
|
|
@@ -164,7 +170,7 @@ class KnexEntityDataProvider {
|
|
|
164
170
|
});
|
|
165
171
|
}
|
|
166
172
|
}
|
|
167
|
-
|
|
173
|
+
class FilterConsumerBridgeToKnexRequest {
|
|
168
174
|
constructor(nameProvider) {
|
|
169
175
|
this.nameProvider = nameProvider;
|
|
170
176
|
this._addWhere = true;
|
|
@@ -208,13 +214,13 @@ export class FilterConsumerBridgeToKnexRequest {
|
|
|
208
214
|
})());
|
|
209
215
|
}
|
|
210
216
|
isNull(col) {
|
|
211
|
-
this.result.push(b => b.whereNull(this.nameProvider.
|
|
217
|
+
this.result.push(b => b.whereNull(this.nameProvider.dbNameOf(col)));
|
|
212
218
|
}
|
|
213
219
|
isNotNull(col) {
|
|
214
|
-
this.result.push(b => b.whereNotNull(this.nameProvider.
|
|
220
|
+
this.result.push(b => b.whereNotNull(this.nameProvider.dbNameOf(col)));
|
|
215
221
|
}
|
|
216
222
|
isIn(col, val) {
|
|
217
|
-
this.result.push(knex => knex.whereIn(this.nameProvider.
|
|
223
|
+
this.result.push(knex => knex.whereIn(this.nameProvider.dbNameOf(col), val.map(x => col.valueConverter.toDb(x))));
|
|
218
224
|
}
|
|
219
225
|
isEqualTo(col, val) {
|
|
220
226
|
this.add(col, val, "=");
|
|
@@ -235,12 +241,12 @@ export class FilterConsumerBridgeToKnexRequest {
|
|
|
235
241
|
this.add(col, val, "<");
|
|
236
242
|
}
|
|
237
243
|
containsCaseInsensitive(col, val) {
|
|
238
|
-
this.result.push(b => b.whereRaw('lower (' + this.nameProvider.
|
|
244
|
+
this.result.push(b => b.whereRaw('lower (' + this.nameProvider.dbNameOf(col) + ") like lower ('%" + val.replace(/'/g, '\'\'') + "%')"));
|
|
239
245
|
this.promises.push((async () => {
|
|
240
246
|
})());
|
|
241
247
|
}
|
|
242
248
|
add(col, val, operator) {
|
|
243
|
-
this.result.push(b => b.where(this.nameProvider.
|
|
249
|
+
this.result.push(b => b.where(this.nameProvider.dbNameOf(col), operator, col.valueConverter.toDb(val)));
|
|
244
250
|
}
|
|
245
251
|
databaseCustom(databaseCustom) {
|
|
246
252
|
this.promises.push((async () => {
|
|
@@ -250,6 +256,13 @@ export class FilterConsumerBridgeToKnexRequest {
|
|
|
250
256
|
})());
|
|
251
257
|
}
|
|
252
258
|
}
|
|
259
|
+
export async function knexCondition(repo, condition) {
|
|
260
|
+
var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata));
|
|
261
|
+
b._addWhere = false;
|
|
262
|
+
await (await (repo.translateWhereToFilter(condition))).__applyToConsumer(b);
|
|
263
|
+
let r = await b.resolveWhere();
|
|
264
|
+
return knex => r.forEach(y => y(knex));
|
|
265
|
+
}
|
|
253
266
|
export class KnexSchemaBuilder {
|
|
254
267
|
constructor(knex) {
|
|
255
268
|
this.knex = knex;
|
|
@@ -273,16 +286,16 @@ export class KnexSchemaBuilder {
|
|
|
273
286
|
}
|
|
274
287
|
}
|
|
275
288
|
async createIfNotExist(entity) {
|
|
276
|
-
const e = await
|
|
277
|
-
if (!await this.knex.schema.hasTable(e
|
|
289
|
+
const e = await dbNamesOf(entity);
|
|
290
|
+
if (!await this.knex.schema.hasTable(e.$entityName)) {
|
|
278
291
|
let cols = new Map();
|
|
279
292
|
for (const f of entity.fields) {
|
|
280
293
|
cols.set(f, {
|
|
281
|
-
name: e.
|
|
282
|
-
readonly:
|
|
294
|
+
name: e.dbNameOf(f),
|
|
295
|
+
readonly: isDbReadonly(f, e)
|
|
283
296
|
});
|
|
284
297
|
}
|
|
285
|
-
await logSql(this.knex.schema.createTable(e
|
|
298
|
+
await logSql(this.knex.schema.createTable(e.$entityName, b => {
|
|
286
299
|
for (const x of entity.fields) {
|
|
287
300
|
if (!cols.get(x).readonly || isAutoIncrement(x)) {
|
|
288
301
|
if (isAutoIncrement(x))
|
|
@@ -298,22 +311,22 @@ export class KnexSchemaBuilder {
|
|
|
298
311
|
}
|
|
299
312
|
}
|
|
300
313
|
async addColumnIfNotExist(entity, c) {
|
|
301
|
-
let e = await
|
|
302
|
-
if (
|
|
314
|
+
let e = await dbNamesOf(entity);
|
|
315
|
+
if (isDbReadonly(c(entity), e))
|
|
303
316
|
return;
|
|
304
317
|
let col = c(entity);
|
|
305
|
-
let colName = e.
|
|
306
|
-
if (!await this.knex.schema.hasColumn(e
|
|
307
|
-
await this.knex.schema.alterTable(e
|
|
318
|
+
let colName = e.dbNameOf(col);
|
|
319
|
+
if (!await this.knex.schema.hasColumn(e.$entityName, colName)) {
|
|
320
|
+
await this.knex.schema.alterTable(e.$entityName, b => {
|
|
308
321
|
buildColumn(col, colName, b);
|
|
309
322
|
});
|
|
310
323
|
}
|
|
311
324
|
}
|
|
312
325
|
async verifyAllColumns(entity) {
|
|
313
|
-
let e = await
|
|
326
|
+
let e = await dbNamesOf(entity);
|
|
314
327
|
try {
|
|
315
328
|
for (const col of entity.fields) {
|
|
316
|
-
if (
|
|
329
|
+
if (isDbReadonly(col, e)) {
|
|
317
330
|
await this.addColumnIfNotExist(entity, () => col);
|
|
318
331
|
}
|
|
319
332
|
}
|
|
@@ -377,7 +390,7 @@ function logSql(who) {
|
|
|
377
390
|
return who;
|
|
378
391
|
}
|
|
379
392
|
export async function createKnexDataProvider(config, autoCreateTables = true) {
|
|
380
|
-
let k = knex(config);
|
|
393
|
+
let k = (await import('knex')).default(config);
|
|
381
394
|
let result = new KnexDataProvider(k);
|
|
382
395
|
if (autoCreateTables)
|
|
383
396
|
await new KnexSchemaBuilder(k).verifyStructureOfAllEntities(new Remult(result));
|
package/esm/remult-mongo.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { MongoClient, Db } from 'mongodb';
|
|
2
|
-
import { DataProvider, EntityDataProvider, EntityMetadata } from '.';
|
|
1
|
+
import type { MongoClient, Db } from 'mongodb';
|
|
2
|
+
import { DataProvider, EntityDataProvider, EntityFilter, EntityMetadata, Remult, Repository } from '.';
|
|
3
3
|
export declare class MongoDataProvider implements DataProvider {
|
|
4
4
|
private db;
|
|
5
5
|
private client;
|
|
6
6
|
constructor(db: Db, client: MongoClient);
|
|
7
|
+
static getDb(remult?: Remult): Db;
|
|
7
8
|
getEntityDataProvider(entity: EntityMetadata<any>): EntityDataProvider;
|
|
8
9
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
9
10
|
}
|
|
11
|
+
export declare function mongoCondition<entityType>(repo: Repository<entityType>, condition: EntityFilter<entityType>): Promise<{
|
|
12
|
+
$and: any[];
|
|
13
|
+
} | {
|
|
14
|
+
$and?: undefined;
|
|
15
|
+
}>;
|
package/esm/remult-mongo.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { CompoundIdField, Filter } from '.';
|
|
2
|
-
import {
|
|
2
|
+
import { dbNamesOf } from './src/filter/filter-consumer-bridge-to-sql-request';
|
|
3
|
+
import { remult as remultContext } from './src/remult-proxy';
|
|
3
4
|
export class MongoDataProvider {
|
|
4
5
|
constructor(db, client) {
|
|
5
6
|
this.db = db;
|
|
6
7
|
this.client = client;
|
|
7
8
|
}
|
|
9
|
+
static getDb(remult) {
|
|
10
|
+
const r = (remult || remultContext).dataProvider;
|
|
11
|
+
if (!r.db)
|
|
12
|
+
throw "the data provider is not a MongoDataProvider";
|
|
13
|
+
return r.db;
|
|
14
|
+
}
|
|
8
15
|
getEntityDataProvider(entity) {
|
|
9
16
|
return new MongoEntityDataProvider(this.db, entity);
|
|
10
17
|
}
|
|
@@ -33,7 +40,7 @@ class MongoEntityDataProvider {
|
|
|
33
40
|
translateFromJson(row, nameProvider) {
|
|
34
41
|
let result = {};
|
|
35
42
|
for (const col of this.entity.fields) {
|
|
36
|
-
let val = row[nameProvider.
|
|
43
|
+
let val = row[nameProvider.dbNameOf(col)];
|
|
37
44
|
if (isNull(val))
|
|
38
45
|
val = null;
|
|
39
46
|
result[col.key] = col.valueConverter.fromDb(val);
|
|
@@ -46,7 +53,7 @@ class MongoEntityDataProvider {
|
|
|
46
53
|
let val = col.valueConverter.toDb(row[col.key]);
|
|
47
54
|
if (val === null)
|
|
48
55
|
val = NULL;
|
|
49
|
-
result[nameProvider.
|
|
56
|
+
result[nameProvider.dbNameOf(col)] = val;
|
|
50
57
|
}
|
|
51
58
|
return result;
|
|
52
59
|
}
|
|
@@ -73,7 +80,7 @@ class MongoEntityDataProvider {
|
|
|
73
80
|
if (options.orderBy) {
|
|
74
81
|
op.sort = {};
|
|
75
82
|
for (const s of options.orderBy.Segments) {
|
|
76
|
-
op.sort[e.
|
|
83
|
+
op.sort[e.dbNameOf(s.field)] = s.isDescending ? -1 : 1;
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
86
|
return await Promise.all(await collection.find(where, op).map(x => this.translateFromJson(x, e)).toArray());
|
|
@@ -116,8 +123,8 @@ class MongoEntityDataProvider {
|
|
|
116
123
|
return await this.translateFromJson(await collection.findOne({ _id: r.insertedId }), e);
|
|
117
124
|
}
|
|
118
125
|
async collection() {
|
|
119
|
-
const e = await
|
|
120
|
-
const collection = this.db.collection(e
|
|
126
|
+
const e = await dbNamesOf(this.entity);
|
|
127
|
+
const collection = this.db.collection(e.$entityName);
|
|
121
128
|
return { e, collection };
|
|
122
129
|
}
|
|
123
130
|
}
|
|
@@ -171,7 +178,7 @@ class FilterConsumerBridgeToMongo {
|
|
|
171
178
|
}
|
|
172
179
|
isIn(col, val) {
|
|
173
180
|
this.result.push(() => ({
|
|
174
|
-
[this.nameProvider.
|
|
181
|
+
[this.nameProvider.dbNameOf(col)]: {
|
|
175
182
|
$in: val.map(x => col.valueConverter.toDb(x))
|
|
176
183
|
}
|
|
177
184
|
}));
|
|
@@ -203,7 +210,7 @@ class FilterConsumerBridgeToMongo {
|
|
|
203
210
|
}
|
|
204
211
|
add(col, val, operator) {
|
|
205
212
|
this.result.push(() => ({
|
|
206
|
-
[this.nameProvider.
|
|
213
|
+
[this.nameProvider.dbNameOf(col)]: { [operator]: isNull(val) ? val : col.valueConverter.toDb(val) }
|
|
207
214
|
}));
|
|
208
215
|
}
|
|
209
216
|
databaseCustom(databaseCustom) {
|
|
@@ -219,3 +226,10 @@ class FilterConsumerBridgeToMongo {
|
|
|
219
226
|
// })());
|
|
220
227
|
}
|
|
221
228
|
}
|
|
229
|
+
export async function mongoCondition(repo, condition) {
|
|
230
|
+
var b = new FilterConsumerBridgeToMongo(await dbNamesOf(repo.metadata));
|
|
231
|
+
b._addWhere = false;
|
|
232
|
+
await (await (repo.translateWhereToFilter(condition))).__applyToConsumer(b);
|
|
233
|
+
let r = await b.resolveWhere();
|
|
234
|
+
return r;
|
|
235
|
+
}
|
|
@@ -30,6 +30,7 @@ export interface RemultServer {
|
|
|
30
30
|
getRemult(req: GenericRequest): Promise<Remult>;
|
|
31
31
|
openApiDoc(options: {
|
|
32
32
|
title: string;
|
|
33
|
+
version?: string;
|
|
33
34
|
}): any;
|
|
34
35
|
registerRouter(r: GenericRouter): void;
|
|
35
36
|
handle(req: GenericRequest, gRes?: GenericResponse): Promise<ServerHandleResponse | undefined>;
|