remult 0.18.1-exp.2 → 0.18.1-exp.21
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 +28 -5
- package/esm/index.d.ts +4 -3
- package/esm/index.js +4 -2
- package/esm/live-query/ably.d.ts +6 -6
- package/esm/live-query/ably.js +5 -5
- package/esm/postgres/postgres-data-provider.d.ts +3 -1
- package/esm/postgres/postgres-data-provider.js +11 -1
- package/esm/postgres/schema-builder.d.ts +1 -1
- package/esm/postgres/schema-builder.js +43 -27
- package/esm/remult-express.d.ts +4 -22
- package/esm/remult-express.js +30 -28
- package/esm/remult-fastify.js +1 -1
- package/esm/remult-fresh.js +2 -2
- package/esm/remult-knex/index.d.ts +7 -31
- package/esm/remult-knex/index.js +71 -42
- package/esm/remult-mongo.d.ts +9 -2
- package/esm/remult-mongo.js +24 -8
- package/esm/remult-next.d.ts +11 -0
- package/esm/remult-next.js +27 -0
- package/esm/server/expressBridge.d.ts +20 -52
- package/esm/server/expressBridge.js +55 -29
- package/esm/server/index.d.ts +3 -1
- package/esm/server/index.js +6 -1
- package/esm/src/column-interfaces.d.ts +44 -8
- package/esm/src/context.d.ts +31 -19
- package/esm/src/context.js +35 -42
- package/esm/src/data-api.js +17 -4
- package/esm/src/data-interfaces.d.ts +1 -1
- package/esm/src/data-providers/array-entity-data-provider.d.ts +1 -1
- package/esm/src/data-providers/array-entity-data-provider.js +1 -1
- package/esm/src/data-providers/rest-data-provider.d.ts +4 -15
- package/esm/src/data-providers/rest-data-provider.js +38 -23
- package/esm/src/data-providers/sql-database.d.ts +6 -3
- package/esm/src/data-providers/sql-database.js +57 -16
- package/esm/src/data-providers/web-sql-data-provider.d.ts +2 -0
- package/esm/src/data-providers/web-sql-data-provider.js +17 -8
- package/esm/src/entity.d.ts +2 -2
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.d.ts +16 -16
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +29 -21
- package/esm/src/filter/filter-interfaces.d.ts +5 -5
- package/esm/src/filter/filter-interfaces.js +31 -26
- package/esm/src/live-query/LiveQueryClient.d.ts +1 -19
- package/esm/src/live-query/LiveQueryClient.js +81 -50
- package/esm/src/live-query/SseSubscriptionClient.d.ts +4 -0
- package/esm/src/live-query/{EventSourceLiveQueryProvider.js → SseSubscriptionClient.js} +7 -6
- package/esm/src/live-query/SubscriptionChannel.d.ts +41 -0
- package/esm/src/live-query/{LiveQuerySubscriber.js → SubscriptionChannel.js} +40 -22
- package/esm/src/live-query/SubscriptionServer.d.ts +38 -0
- package/esm/src/live-query/{LiveQueryPublisher.js → SubscriptionServer.js} +60 -73
- package/esm/src/remult-proxy.js +44 -1
- package/esm/src/remult3/RepositoryImplementation.d.ts +8 -2
- package/esm/src/remult3/RepositoryImplementation.js +94 -30
- package/esm/src/remult3/remult3.d.ts +59 -6
- package/esm/src/remult3/remult3.js +1 -0
- package/esm/src/server-action.d.ts +1 -1
- package/esm/src/shared-tests/db-tests-setup.d.ts +1 -1
- package/esm/src/shared-tests/db-tests-setup.js +4 -3
- package/esm/src/shared-tests/db-tests.db-tests.js +55 -9
- package/esm/src/sql-command.d.ts +4 -2
- package/esm/src/tests/entityForCustomFilter.d.ts +6 -6
- package/esm/src/tests/entityForCustomFilter.js +20 -21
- package/esm/src/tests/frontend-database-tests-setup.spec.js +1 -2
- package/esm/src/tests/testHelper.spec.d.ts +2 -2
- package/esm/src/tests/testHelper.spec.js +1 -2
- package/esm/src/valueConverters.js +17 -7
- package/index.d.ts +4 -3
- package/index.js +7 -3
- package/live-query/ably.d.ts +6 -6
- package/live-query/ably.js +12 -12
- package/package.json +18 -9
- package/postgres/postgres-data-provider.d.ts +3 -1
- package/postgres/postgres-data-provider.js +13 -3
- package/postgres/schema-builder.d.ts +1 -1
- package/postgres/schema-builder.js +64 -50
- package/remult-express.d.ts +4 -22
- package/remult-express.js +39 -47
- package/remult-fastify.js +2 -2
- package/remult-fresh.js +1 -1
- package/remult-knex/index.d.ts +7 -31
- package/remult-knex/index.js +100 -53
- package/remult-mongo.d.ts +9 -2
- package/remult-mongo.js +39 -7
- package/remult-next.d.ts +11 -0
- package/remult-next.js +73 -0
- package/server/JsonEntityFileStorage.js +2 -2
- package/server/expressBridge.d.ts +20 -52
- package/server/expressBridge.js +68 -41
- package/server/index.d.ts +3 -1
- package/server/index.js +7 -2
- package/src/column-interfaces.d.ts +44 -8
- package/src/context.d.ts +31 -19
- package/src/context.js +39 -50
- package/src/data-api.js +18 -5
- package/src/data-interfaces.d.ts +1 -1
- package/src/data-providers/array-entity-data-provider.d.ts +1 -1
- package/src/data-providers/array-entity-data-provider.js +1 -1
- package/src/data-providers/rest-data-provider.d.ts +4 -15
- package/src/data-providers/rest-data-provider.js +48 -24
- package/src/data-providers/sql-database.d.ts +6 -3
- package/src/data-providers/sql-database.js +75 -15
- package/src/data-providers/web-sql-data-provider.d.ts +2 -0
- package/src/data-providers/web-sql-data-provider.js +16 -7
- package/src/entity.d.ts +2 -2
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +16 -16
- package/src/filter/filter-consumer-bridge-to-sql-request.js +59 -50
- package/src/filter/filter-interfaces.d.ts +5 -5
- package/src/filter/filter-interfaces.js +31 -26
- package/src/live-query/LiveQueryClient.d.ts +1 -19
- package/src/live-query/LiveQueryClient.js +117 -64
- package/src/live-query/SseSubscriptionClient.d.ts +4 -0
- package/src/live-query/{EventSourceLiveQueryProvider.js → SseSubscriptionClient.js} +13 -12
- package/src/live-query/SubscriptionChannel.d.ts +41 -0
- package/src/live-query/{LiveQuerySubscriber.js → SubscriptionChannel.js} +51 -47
- package/src/live-query/SubscriptionServer.d.ts +38 -0
- package/src/live-query/SubscriptionServer.js +237 -0
- package/src/remult-proxy.js +137 -2
- package/src/remult3/RepositoryImplementation.d.ts +8 -2
- package/src/remult3/RepositoryImplementation.js +121 -34
- package/src/remult3/remult3.d.ts +59 -6
- package/src/remult3/remult3.js +1 -0
- package/src/server-action.d.ts +1 -1
- package/src/shared-tests/db-tests-setup.d.ts +1 -1
- package/src/shared-tests/db-tests-setup.js +5 -4
- package/src/shared-tests/db-tests.db-tests.js +101 -8
- package/src/sql-command.d.ts +4 -2
- package/src/tests/entityForCustomFilter.d.ts +6 -6
- package/src/tests/entityForCustomFilter.js +30 -31
- package/src/tests/frontend-database-tests-setup.spec.js +4 -5
- package/src/tests/testHelper.spec.d.ts +2 -2
- package/src/tests/testHelper.spec.js +4 -5
- package/src/valueConverters.js +17 -7
- package/esm/live-query/index.d.ts +0 -3
- package/esm/live-query/index.js +0 -3
- package/esm/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -5
- package/esm/src/backend-tests/backend-database-test-setup.backend-spec.js +0 -113
- package/esm/src/backend-tests/my-test.backend-spec.d.ts +0 -1
- package/esm/src/backend-tests/my-test.backend-spec.js +0 -59
- package/esm/src/backend-tests/test-http-server.backend-spec.d.ts +0 -6
- package/esm/src/backend-tests/test-http-server.backend-spec.js +0 -171
- package/esm/src/live-query/EventSourceLiveQueryProvider.d.ts +0 -4
- package/esm/src/live-query/LiveQueryPublisher.d.ts +0 -49
- package/esm/src/live-query/LiveQuerySubscriber.d.ts +0 -67
- package/live-query/index.d.ts +0 -3
- package/live-query/index.js +0 -10
- package/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -5
- package/src/backend-tests/backend-database-test-setup.backend-spec.js +0 -231
- package/src/backend-tests/my-test.backend-spec.d.ts +0 -1
- package/src/backend-tests/my-test.backend-spec.js +0 -160
- 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/live-query/EventSourceLiveQueryProvider.d.ts +0 -4
- package/src/live-query/LiveQueryPublisher.d.ts +0 -49
- package/src/live-query/LiveQueryPublisher.js +0 -248
- package/src/live-query/LiveQuerySubscriber.d.ts +0 -67
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { UrlBuilder } from '../../urlBuilder';
|
|
2
2
|
import { customUrlToken, Filter } from '../filter/filter-interfaces';
|
|
3
3
|
import { buildRestDataProvider, retry } from "../buildRestDataProvider";
|
|
4
|
+
import { actionInfo } from '../server-action';
|
|
4
5
|
export class RestDataProvider {
|
|
5
6
|
constructor(apiProvider) {
|
|
6
7
|
this.apiProvider = apiProvider;
|
|
7
|
-
this.
|
|
8
|
+
this.supportsrawFilter = true;
|
|
8
9
|
}
|
|
9
10
|
getEntityDataProvider(entity) {
|
|
10
11
|
return new RestEntityDataProvider(() => {
|
|
@@ -20,6 +21,7 @@ export class RestDataProvider {
|
|
|
20
21
|
throw new Error("Method not implemented.");
|
|
21
22
|
}
|
|
22
23
|
}
|
|
24
|
+
//@internal
|
|
23
25
|
export function findOptionsToJson(options, meta) {
|
|
24
26
|
return {
|
|
25
27
|
limit: options.limit,
|
|
@@ -28,6 +30,7 @@ export function findOptionsToJson(options, meta) {
|
|
|
28
30
|
orderBy: options.orderBy
|
|
29
31
|
};
|
|
30
32
|
}
|
|
33
|
+
//@internal
|
|
31
34
|
export function findOptionsFromJson(json, meta) {
|
|
32
35
|
let r = {};
|
|
33
36
|
for (const key of ["limit", "page", "where", "orderBy"]) {
|
|
@@ -62,29 +65,14 @@ export class RestEntityDataProvider {
|
|
|
62
65
|
return result;
|
|
63
66
|
}
|
|
64
67
|
async count(where) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let filterObject;
|
|
68
|
-
if (where) {
|
|
69
|
-
filterObject = where.toJson();
|
|
70
|
-
if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
|
|
71
|
-
filterObject = undefined;
|
|
72
|
-
}
|
|
73
|
-
if (filterObject)
|
|
74
|
-
return this.http().post(url.url, filterObject).then(r => +(r.count));
|
|
75
|
-
else
|
|
76
|
-
return this.http().get(url.url).then(r => +(r.count));
|
|
68
|
+
const { run } = this.buildFindRequest({ where });
|
|
69
|
+
return run("count").then(r => +r.count);
|
|
77
70
|
}
|
|
78
71
|
find(options) {
|
|
79
|
-
let {
|
|
80
|
-
|
|
81
|
-
url.add("__action", "get");
|
|
82
|
-
return this.http().post(url.url, filterObject).then(x => x.map(y => this.translateFromJson(y)));
|
|
83
|
-
}
|
|
84
|
-
else
|
|
85
|
-
return this.http().get(url.url).then(x => x.map(y => this.translateFromJson(y)));
|
|
86
|
-
;
|
|
72
|
+
let { run } = this.buildFindRequest(options);
|
|
73
|
+
return run().then(x => x.map(y => this.translateFromJson(y)));
|
|
87
74
|
}
|
|
75
|
+
//@internal
|
|
88
76
|
buildFindRequest(options) {
|
|
89
77
|
let url = new UrlBuilder(this.url());
|
|
90
78
|
let filterObject;
|
|
@@ -113,7 +101,34 @@ export class RestEntityDataProvider {
|
|
|
113
101
|
if (options.page)
|
|
114
102
|
url.add('_page', options.page);
|
|
115
103
|
}
|
|
116
|
-
|
|
104
|
+
const run = (action) => {
|
|
105
|
+
let u = new UrlBuilder(url.url);
|
|
106
|
+
if (!action && filterObject) {
|
|
107
|
+
action = "get";
|
|
108
|
+
}
|
|
109
|
+
if (action)
|
|
110
|
+
u.add("__action", action);
|
|
111
|
+
if (filterObject) {
|
|
112
|
+
return this.http().post(u.url, filterObject);
|
|
113
|
+
}
|
|
114
|
+
else
|
|
115
|
+
return this.http().get(u.url);
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
createKey: () => JSON.stringify({ url, filterObject }),
|
|
119
|
+
run,
|
|
120
|
+
subscribe: async () => {
|
|
121
|
+
const result = await run("liveQuery");
|
|
122
|
+
return {
|
|
123
|
+
...result,
|
|
124
|
+
unsubscribe: async () => {
|
|
125
|
+
return actionInfo.runActionWithoutBlockingUI(() => this.http().post(this.url() + "?__action=endLiveQuery", {
|
|
126
|
+
id: result.queryChannel
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
};
|
|
117
132
|
}
|
|
118
133
|
update(id, data) {
|
|
119
134
|
let result = {};
|
|
@@ -211,7 +226,7 @@ export function addFilterToUrlAndReturnTrueIfSuccessful(filter, url) {
|
|
|
211
226
|
if (Object.prototype.hasOwnProperty.call(filter, key)) {
|
|
212
227
|
const element = filter[key];
|
|
213
228
|
if (Array.isArray(element)) {
|
|
214
|
-
if (key.endsWith("
|
|
229
|
+
if (key.endsWith(".in"))
|
|
215
230
|
url.add(key, JSON.stringify(element));
|
|
216
231
|
else
|
|
217
232
|
element.forEach(e => url.add(key, e));
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { EntityDataProvider, DataProvider } from "../data-interfaces";
|
|
2
|
-
import { SqlCommand, SqlImplementation, SqlResult } from "../sql-command";
|
|
2
|
+
import { SqlCommand, SqlCommandWithParameters, SqlImplementation, SqlResult } from "../sql-command";
|
|
3
3
|
import { CustomSqlFilterBuilderFunction } from "../filter/filter-consumer-bridge-to-sql-request";
|
|
4
|
-
import { EntityMetadata, EntityFilter } from "../remult3";
|
|
4
|
+
import { EntityMetadata, EntityFilter, RepositoryOverloads } from "../remult3";
|
|
5
|
+
import { Remult } from "../context";
|
|
5
6
|
export declare class SqlDatabase implements DataProvider {
|
|
6
7
|
private sql;
|
|
8
|
+
static getDb(remult?: Remult): SqlDatabase;
|
|
7
9
|
createCommand(): SqlCommand;
|
|
8
10
|
execute(sql: string): Promise<SqlResult>;
|
|
9
11
|
getEntityDataProvider(entity: EntityMetadata): EntityDataProvider;
|
|
10
12
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
11
|
-
static
|
|
13
|
+
static rawFilter(build: CustomSqlFilterBuilderFunction): EntityFilter<any>;
|
|
14
|
+
static filterToRaw<entityType>(repo: RepositoryOverloads<entityType>, condition: EntityFilter<entityType>, sqlCommand?: SqlCommandWithParameters): Promise<string>;
|
|
12
15
|
static LogToConsole: boolean;
|
|
13
16
|
static durationThreshold: number;
|
|
14
17
|
constructor(sql: SqlImplementation);
|
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
import { CompoundIdField } from "../column";
|
|
2
|
-
import { FilterConsumerBridgeToSqlRequest,
|
|
2
|
+
import { dbNamesOf, FilterConsumerBridgeToSqlRequest, isDbReadonly } from "../filter/filter-consumer-bridge-to-sql-request";
|
|
3
3
|
import { customDatabaseFilterToken, Filter } from '../filter/filter-interfaces';
|
|
4
4
|
import { Sort } from '../sort';
|
|
5
|
+
import { getRepository } from "../remult3";
|
|
6
|
+
import { RemultProxy } from "../remult-proxy";
|
|
5
7
|
// @dynamic
|
|
6
8
|
export class SqlDatabase {
|
|
7
9
|
constructor(sql) {
|
|
8
10
|
this.sql = sql;
|
|
9
11
|
this.createdEntities = [];
|
|
10
12
|
}
|
|
13
|
+
static getDb(remult) {
|
|
14
|
+
const r = (remult || RemultProxy.defaultRemult).dataProvider;
|
|
15
|
+
if (!r.createCommand)
|
|
16
|
+
throw "the data provider is not an SqlDatabase";
|
|
17
|
+
return r;
|
|
18
|
+
}
|
|
11
19
|
createCommand() {
|
|
12
20
|
return new LogSQLCommand(this.sql.createCommand(), SqlDatabase.LogToConsole);
|
|
13
21
|
}
|
|
14
22
|
async execute(sql) {
|
|
15
23
|
return await this.createCommand().execute(sql);
|
|
16
24
|
}
|
|
25
|
+
/* @internal*/
|
|
26
|
+
_getSourceSql() {
|
|
27
|
+
return this.sql;
|
|
28
|
+
}
|
|
17
29
|
getEntityDataProvider(entity) {
|
|
18
30
|
return new ActualSQLServerDataProvider(entity, this, async (dbName) => {
|
|
19
|
-
if (this.createdEntities.indexOf(dbName
|
|
20
|
-
this.createdEntities.push(dbName
|
|
31
|
+
if (this.createdEntities.indexOf(dbName.$entityName) < 0) {
|
|
32
|
+
this.createdEntities.push(dbName.$entityName);
|
|
21
33
|
await this.sql.entityIsUsedForTheFirstTime(entity);
|
|
22
34
|
}
|
|
23
35
|
}, this.sql);
|
|
@@ -48,13 +60,25 @@ export class SqlDatabase {
|
|
|
48
60
|
}
|
|
49
61
|
});
|
|
50
62
|
}
|
|
51
|
-
|
|
63
|
+
//TODO - change to "rawFilter" (in all databases and docs)
|
|
64
|
+
static rawFilter(build) {
|
|
52
65
|
return {
|
|
53
66
|
[customDatabaseFilterToken]: {
|
|
54
67
|
buildSql: build
|
|
55
68
|
}
|
|
56
69
|
};
|
|
57
70
|
}
|
|
71
|
+
//TODO - filter to raw
|
|
72
|
+
static async filterToRaw(repo, condition, sqlCommand) {
|
|
73
|
+
if (!sqlCommand) {
|
|
74
|
+
sqlCommand = new myDummySQLCommand();
|
|
75
|
+
}
|
|
76
|
+
const r = getRepository(repo);
|
|
77
|
+
var b = new FilterConsumerBridgeToSqlRequest(sqlCommand, await dbNamesOf(r.metadata));
|
|
78
|
+
b._addWhere = false;
|
|
79
|
+
await (await (r.translateWhereToFilter(condition))).__applyToConsumer(b);
|
|
80
|
+
return await b.resolveWhere();
|
|
81
|
+
}
|
|
58
82
|
}
|
|
59
83
|
SqlDatabase.LogToConsole = false;
|
|
60
84
|
SqlDatabase.durationThreshold = 0;
|
|
@@ -95,13 +119,13 @@ class ActualSQLServerDataProvider {
|
|
|
95
119
|
this.strategy = strategy;
|
|
96
120
|
}
|
|
97
121
|
async init() {
|
|
98
|
-
let dbNameProvider = await
|
|
122
|
+
let dbNameProvider = await dbNamesOf(this.entity);
|
|
99
123
|
await this.iAmUsed(dbNameProvider);
|
|
100
124
|
return dbNameProvider;
|
|
101
125
|
}
|
|
102
126
|
async count(where) {
|
|
103
127
|
let e = await this.init();
|
|
104
|
-
let select = 'select count(*) count from ' + e
|
|
128
|
+
let select = 'select count(*) count from ' + e.$entityName;
|
|
105
129
|
let r = this.sql.createCommand();
|
|
106
130
|
if (where) {
|
|
107
131
|
let wc = new FilterConsumerBridgeToSqlRequest(r, e);
|
|
@@ -116,7 +140,7 @@ class ActualSQLServerDataProvider {
|
|
|
116
140
|
let e = await this.init();
|
|
117
141
|
let { colKeys, select } = this.buildSelect(e);
|
|
118
142
|
select = 'select ' + select;
|
|
119
|
-
select += '\n from ' + e
|
|
143
|
+
select += '\n from ' + e.$entityName;
|
|
120
144
|
let r = this.sql.createCommand();
|
|
121
145
|
if (options) {
|
|
122
146
|
if (options.where) {
|
|
@@ -147,7 +171,7 @@ class ActualSQLServerDataProvider {
|
|
|
147
171
|
}
|
|
148
172
|
else
|
|
149
173
|
select += ', ';
|
|
150
|
-
select += e
|
|
174
|
+
select += e.$dbNameOf(c.field);
|
|
151
175
|
if (c.isDescending)
|
|
152
176
|
select += ' desc';
|
|
153
177
|
}
|
|
@@ -189,7 +213,7 @@ class ActualSQLServerDataProvider {
|
|
|
189
213
|
else {
|
|
190
214
|
if (colKeys.length > 0)
|
|
191
215
|
select += ', ';
|
|
192
|
-
select += e
|
|
216
|
+
select += e.$dbNameOf(x);
|
|
193
217
|
colKeys.push(x);
|
|
194
218
|
}
|
|
195
219
|
}
|
|
@@ -200,12 +224,12 @@ class ActualSQLServerDataProvider {
|
|
|
200
224
|
let r = this.sql.createCommand();
|
|
201
225
|
let f = new FilterConsumerBridgeToSqlRequest(r, e);
|
|
202
226
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
203
|
-
let statement = 'update ' + e
|
|
227
|
+
let statement = 'update ' + e.$entityName + ' set ';
|
|
204
228
|
let added = false;
|
|
205
229
|
for (const x of this.entity.fields) {
|
|
206
230
|
if (x instanceof CompoundIdField) {
|
|
207
231
|
}
|
|
208
|
-
if (
|
|
232
|
+
if (isDbReadonly(x, e)) { }
|
|
209
233
|
else if (data[x.key] !== undefined) {
|
|
210
234
|
let v = x.valueConverter.toDb(data[x.key]);
|
|
211
235
|
if (v !== undefined) {
|
|
@@ -213,7 +237,7 @@ class ActualSQLServerDataProvider {
|
|
|
213
237
|
added = true;
|
|
214
238
|
else
|
|
215
239
|
statement += ', ';
|
|
216
|
-
statement += e
|
|
240
|
+
statement += e.$dbNameOf(x) + ' = ' + r.addParameterAndReturnSqlToken(v);
|
|
217
241
|
}
|
|
218
242
|
}
|
|
219
243
|
}
|
|
@@ -229,7 +253,7 @@ class ActualSQLServerDataProvider {
|
|
|
229
253
|
let r = this.sql.createCommand();
|
|
230
254
|
let f = new FilterConsumerBridgeToSqlRequest(r, e);
|
|
231
255
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
232
|
-
let statement = 'delete from ' + e
|
|
256
|
+
let statement = 'delete from ' + e.$entityName;
|
|
233
257
|
statement += await f.resolveWhere();
|
|
234
258
|
return r.execute(statement).then(() => { });
|
|
235
259
|
}
|
|
@@ -240,7 +264,7 @@ class ActualSQLServerDataProvider {
|
|
|
240
264
|
let vals = '';
|
|
241
265
|
let added = false;
|
|
242
266
|
for (const x of this.entity.fields) {
|
|
243
|
-
if (
|
|
267
|
+
if (isDbReadonly(x, e)) { }
|
|
244
268
|
else {
|
|
245
269
|
let v = x.valueConverter.toDb(data[x.key]);
|
|
246
270
|
if (v != undefined) {
|
|
@@ -250,15 +274,32 @@ class ActualSQLServerDataProvider {
|
|
|
250
274
|
cols += ', ';
|
|
251
275
|
vals += ', ';
|
|
252
276
|
}
|
|
253
|
-
cols += e
|
|
277
|
+
cols += e.$dbNameOf(x);
|
|
254
278
|
vals += r.addParameterAndReturnSqlToken(v);
|
|
255
279
|
}
|
|
256
280
|
}
|
|
257
281
|
}
|
|
258
|
-
let statement = `insert into ${e
|
|
282
|
+
let statement = `insert into ${e.$entityName} (${cols}) values (${vals})`;
|
|
259
283
|
let { colKeys, select } = this.buildSelect(e);
|
|
260
284
|
statement += ' returning ' + select;
|
|
261
285
|
return await r.execute(statement).then(sql => this.buildResultRow(colKeys, sql.rows[0], sql));
|
|
262
286
|
}
|
|
263
287
|
}
|
|
264
288
|
ActualSQLServerDataProvider.LogToConsole = false;
|
|
289
|
+
class myDummySQLCommand {
|
|
290
|
+
execute(sql) {
|
|
291
|
+
throw new Error("Method not implemented.");
|
|
292
|
+
}
|
|
293
|
+
addParameterAndReturnSqlToken(val) {
|
|
294
|
+
if (val === null)
|
|
295
|
+
return "null";
|
|
296
|
+
if (val instanceof Date)
|
|
297
|
+
val = val.toISOString();
|
|
298
|
+
if (typeof (val) == "string") {
|
|
299
|
+
if (val == undefined)
|
|
300
|
+
val = '';
|
|
301
|
+
return '\'' + val.replace(/'/g, '\'\'') + '\'';
|
|
302
|
+
}
|
|
303
|
+
return val.toString();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { __RowsOfDataForTesting } from "../__RowsOfDataForTesting";
|
|
2
2
|
import { SqlCommand, SqlImplementation } from "../sql-command";
|
|
3
3
|
import { EntityMetadata } from "../remult3";
|
|
4
|
+
import { Remult } from "../context";
|
|
4
5
|
export declare class WebSqlDataProvider implements SqlImplementation, __RowsOfDataForTesting {
|
|
5
6
|
private databaseName;
|
|
6
7
|
rows: {
|
|
7
8
|
[tableName: string]: any;
|
|
8
9
|
};
|
|
9
10
|
constructor(databaseName: string, databaseSize?: number);
|
|
11
|
+
static getDb(remult?: Remult): any;
|
|
10
12
|
getLimitSqlSyntax(limit: number, offset: number): string;
|
|
11
13
|
entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
|
|
12
14
|
dropTable(entity: EntityMetadata): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isAutoIncrement } from "../remult3";
|
|
2
2
|
import { SqlDatabase } from "./sql-database";
|
|
3
|
-
import {
|
|
3
|
+
import { dbNamesOf, isDbReadonly } from "../filter/filter-consumer-bridge-to-sql-request";
|
|
4
4
|
//SqlDatabase.LogToConsole = true;
|
|
5
5
|
export class WebSqlDataProvider {
|
|
6
6
|
constructor(databaseName, databaseSize = 2 * 1024 * 1024) {
|
|
@@ -8,6 +8,15 @@ export class WebSqlDataProvider {
|
|
|
8
8
|
//@ts-ignore
|
|
9
9
|
this.db = window.openDatabase(databaseName, '1.0', databaseName, databaseSize);
|
|
10
10
|
}
|
|
11
|
+
// return instance of websql.Database class - see @types/websql
|
|
12
|
+
static getDb(remult) {
|
|
13
|
+
const sql = SqlDatabase.getDb(remult);
|
|
14
|
+
const me = sql._getSourceSql();
|
|
15
|
+
if (!me.db) {
|
|
16
|
+
throw "the data provider is not a WebSqlDataProvider";
|
|
17
|
+
}
|
|
18
|
+
return me.db;
|
|
19
|
+
}
|
|
11
20
|
getLimitSqlSyntax(limit, offset) {
|
|
12
21
|
return ' limit ' + limit + ' offset ' + offset;
|
|
13
22
|
}
|
|
@@ -15,34 +24,34 @@ export class WebSqlDataProvider {
|
|
|
15
24
|
await this.createTable(entity);
|
|
16
25
|
}
|
|
17
26
|
async dropTable(entity) {
|
|
18
|
-
let e = await
|
|
19
|
-
let sql = 'drop table if exists ' + e
|
|
27
|
+
let e = await dbNamesOf(entity);
|
|
28
|
+
let sql = 'drop table if exists ' + e.$entityName;
|
|
20
29
|
if (SqlDatabase.LogToConsole)
|
|
21
30
|
console.info(sql);
|
|
22
31
|
await this.createCommand().execute(sql);
|
|
23
32
|
}
|
|
24
33
|
async createTable(entity) {
|
|
25
34
|
let result = '';
|
|
26
|
-
let e = await
|
|
35
|
+
let e = await dbNamesOf(entity);
|
|
27
36
|
for (const x of entity.fields) {
|
|
28
|
-
if (!
|
|
37
|
+
if (!isDbReadonly(x, e) || isAutoIncrement(x)) {
|
|
29
38
|
if (result.length != 0)
|
|
30
39
|
result += ',';
|
|
31
40
|
result += '\r\n ';
|
|
32
41
|
if (isAutoIncrement(x)) {
|
|
33
42
|
if (x.key != entity.idMetadata.field.key)
|
|
34
43
|
throw "in web sql, autoincrement is only allowed for primary key";
|
|
35
|
-
result += e
|
|
44
|
+
result += e.$dbNameOf(x) + ' integer primary key autoincrement';
|
|
36
45
|
}
|
|
37
46
|
else {
|
|
38
|
-
result += this.addColumnSqlSyntax(x, e
|
|
47
|
+
result += this.addColumnSqlSyntax(x, e.$dbNameOf(x));
|
|
39
48
|
if (x.key == entity.idMetadata.field.key) {
|
|
40
49
|
result += ' primary key';
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
52
|
}
|
|
44
53
|
}
|
|
45
|
-
let sql = 'create table if not exists ' + e
|
|
54
|
+
let sql = 'create table if not exists ' + e.$entityName + ' (' + result + '\r\n)';
|
|
46
55
|
if (SqlDatabase.LogToConsole)
|
|
47
56
|
console.log(sql);
|
|
48
57
|
await this.createCommand().execute(sql);
|
package/esm/src/entity.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Allowed, AllowedForInstance } from "./context";
|
|
2
2
|
import { FieldMetadata as FieldMetadata } from './column-interfaces';
|
|
3
|
-
import { EntityOrderBy, FieldsMetadata, EntityFilter, EntityRef } from "./remult3";
|
|
3
|
+
import { EntityOrderBy, FieldsMetadata, EntityFilter, EntityRef, EntityMetadata } from "./remult3";
|
|
4
4
|
export interface EntityOptions<entityType = any> {
|
|
5
5
|
/**A human readable name for the entity */
|
|
6
6
|
caption?: string;
|
|
@@ -67,7 +67,7 @@ export interface EntityOptions<entityType = any> {
|
|
|
67
67
|
*/
|
|
68
68
|
dbName?: string;
|
|
69
69
|
/** For entities that are based on SQL expressions instead of a physical table or view*/
|
|
70
|
-
sqlExpression?: string | ((entity:
|
|
70
|
+
sqlExpression?: string | ((entity: EntityMetadata<entityType>) => string | Promise<string>);
|
|
71
71
|
/** An arrow function that identifies the `id` column to use for this entity
|
|
72
72
|
* @example
|
|
73
73
|
* //Single column id
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SqlCommandWithParameters } from "../sql-command";
|
|
2
2
|
import { Filter, FilterConsumer } from './filter-interfaces';
|
|
3
3
|
import { FieldMetadata } from "../column-interfaces";
|
|
4
|
-
import {
|
|
4
|
+
import { EntityFilter, OmitEB } from "../remult3/remult3";
|
|
5
|
+
import { EntityMetadataOverloads, RepositoryOverloads } from "../remult3";
|
|
5
6
|
export declare class FilterConsumerBridgeToSqlRequest implements FilterConsumer {
|
|
6
7
|
private r;
|
|
7
8
|
private nameProvider;
|
|
@@ -9,7 +10,7 @@ export declare class FilterConsumerBridgeToSqlRequest implements FilterConsumer
|
|
|
9
10
|
_addWhere: boolean;
|
|
10
11
|
promises: Promise<void>[];
|
|
11
12
|
resolveWhere(): Promise<string>;
|
|
12
|
-
constructor(r:
|
|
13
|
+
constructor(r: SqlCommandWithParameters, nameProvider: EntityDbNamesBase);
|
|
13
14
|
custom(key: string, customItem: any): void;
|
|
14
15
|
or(orElements: Filter[]): void;
|
|
15
16
|
isNull(col: FieldMetadata): void;
|
|
@@ -32,19 +33,18 @@ export interface CustomSqlFilterObject {
|
|
|
32
33
|
}
|
|
33
34
|
export declare class CustomSqlFilterBuilder {
|
|
34
35
|
private r;
|
|
35
|
-
constructor(r:
|
|
36
|
+
constructor(r: SqlCommandWithParameters);
|
|
36
37
|
sql: string;
|
|
37
38
|
addParameterAndReturnSqlToken<valueType>(val: valueType, field?: FieldMetadata<valueType>): string;
|
|
39
|
+
filterToRaw<entityType>(repo: RepositoryOverloads<entityType>, condition: EntityFilter<entityType>): Promise<string>;
|
|
38
40
|
}
|
|
39
|
-
export declare function
|
|
40
|
-
export declare
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
isDbReadonly(x: FieldMetadata): boolean;
|
|
50
|
-
}
|
|
41
|
+
export declare function isDbReadonly<entityType>(field: FieldMetadata, dbNames: EntityDbNames<entityType>): boolean;
|
|
42
|
+
export declare type EntityDbNamesBase = {
|
|
43
|
+
$entityName: string;
|
|
44
|
+
$dbNameOf(field: FieldMetadata<any> | string): string;
|
|
45
|
+
toString(): string;
|
|
46
|
+
};
|
|
47
|
+
export declare type EntityDbNames<entityType> = {
|
|
48
|
+
[Properties in keyof Required<OmitEB<entityType>>]: string;
|
|
49
|
+
} & EntityDbNamesBase;
|
|
50
|
+
export declare function dbNamesOf<entityType>(repo: EntityMetadataOverloads<entityType>): Promise<EntityDbNames<entityType>>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getEntityMetadata } from "../remult3";
|
|
2
|
+
import { SqlDatabase } from "../data-providers/sql-database";
|
|
1
3
|
export class FilterConsumerBridgeToSqlRequest {
|
|
2
4
|
constructor(r, nameProvider) {
|
|
3
5
|
this.r = r;
|
|
@@ -44,15 +46,15 @@ export class FilterConsumerBridgeToSqlRequest {
|
|
|
44
46
|
})());
|
|
45
47
|
}
|
|
46
48
|
isNull(col) {
|
|
47
|
-
this.promises.push((async () => this.addToWhere(this.nameProvider
|
|
49
|
+
this.promises.push((async () => this.addToWhere(this.nameProvider.$dbNameOf(col) + ' is null'))());
|
|
48
50
|
}
|
|
49
51
|
isNotNull(col) {
|
|
50
|
-
this.promises.push((async () => this.addToWhere(this.nameProvider
|
|
52
|
+
this.promises.push((async () => this.addToWhere(this.nameProvider.$dbNameOf(col) + ' is not null'))());
|
|
51
53
|
}
|
|
52
54
|
isIn(col, val) {
|
|
53
55
|
this.promises.push((async () => {
|
|
54
56
|
if (val && val.length > 0)
|
|
55
|
-
this.addToWhere(this.nameProvider
|
|
57
|
+
this.addToWhere(this.nameProvider.$dbNameOf(col) + " in (" + val.map(x => this.r.addParameterAndReturnSqlToken(col.valueConverter.toDb(x))).join(",") + ")");
|
|
56
58
|
else
|
|
57
59
|
this.addToWhere('1 = 0 /*isIn with no values*/');
|
|
58
60
|
})());
|
|
@@ -77,12 +79,12 @@ export class FilterConsumerBridgeToSqlRequest {
|
|
|
77
79
|
}
|
|
78
80
|
containsCaseInsensitive(col, val) {
|
|
79
81
|
this.promises.push((async () => {
|
|
80
|
-
this.addToWhere('lower (' + this.nameProvider
|
|
82
|
+
this.addToWhere('lower (' + this.nameProvider.$dbNameOf(col) + ") like lower ('%" + val.replace(/'/g, '\'\'') + "%')");
|
|
81
83
|
})());
|
|
82
84
|
}
|
|
83
85
|
add(col, val, operator) {
|
|
84
86
|
this.promises.push((async () => {
|
|
85
|
-
let x = this.nameProvider
|
|
87
|
+
let x = this.nameProvider.$dbNameOf(col) + ' ' + operator + ' ' + this.r.addParameterAndReturnSqlToken(col.valueConverter.toDb(val));
|
|
86
88
|
this.addToWhere(x);
|
|
87
89
|
})());
|
|
88
90
|
}
|
|
@@ -117,23 +119,29 @@ export class CustomSqlFilterBuilder {
|
|
|
117
119
|
val = field.valueConverter.toDb(val);
|
|
118
120
|
return this.r.addParameterAndReturnSqlToken(val);
|
|
119
121
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
var result = new dbNameProviderImpl();
|
|
123
|
-
for (const f of meta.fields) {
|
|
124
|
-
result.map.set(f.key, await f.getDbName());
|
|
122
|
+
async filterToRaw(repo, condition) {
|
|
123
|
+
return SqlDatabase.filterToRaw(repo, condition, this);
|
|
125
124
|
}
|
|
126
|
-
result.entityName = await meta.getDbName();
|
|
127
|
-
return result;
|
|
128
125
|
}
|
|
129
|
-
export
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
126
|
+
export function isDbReadonly(field, dbNames) {
|
|
127
|
+
return (field.dbReadOnly || field.isServerExpression || dbNames.$dbNameOf(field) != field.options.dbName);
|
|
128
|
+
}
|
|
129
|
+
export async function dbNamesOf(repo) {
|
|
130
|
+
var meta = getEntityMetadata(repo);
|
|
131
|
+
const result = {
|
|
132
|
+
$entityName: await meta.getDbName(),
|
|
133
|
+
toString: () => result.$entityName,
|
|
134
|
+
$dbNameOf: (field) => {
|
|
135
|
+
var key;
|
|
136
|
+
if (typeof field === "string")
|
|
137
|
+
key = field;
|
|
138
|
+
else
|
|
139
|
+
key = field.key;
|
|
140
|
+
return result[key];
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
for (const field of meta.fields) {
|
|
144
|
+
result[field.key] = await field.getDbName();
|
|
138
145
|
}
|
|
146
|
+
return result;
|
|
139
147
|
}
|
|
@@ -6,8 +6,8 @@ export declare class Filter {
|
|
|
6
6
|
constructor(apply?: (add: FilterConsumer) => void);
|
|
7
7
|
__applyToConsumer(add: FilterConsumer): void;
|
|
8
8
|
static resolve<entityType>(filter: EntityFilter<entityType> | (() => EntityFilter<entityType> | Promise<EntityFilter<entityType>>)): Promise<EntityFilter<entityType>>;
|
|
9
|
-
static createCustom<entityType>(
|
|
10
|
-
static createCustom<entityType, argsType>(
|
|
9
|
+
static createCustom<entityType>(rawFilterTranslator: (unused: never, r: Remult) => EntityFilter<entityType> | Promise<EntityFilter<entityType>>, key?: string): (() => EntityFilter<entityType>) & rawFilterInfo<entityType>;
|
|
10
|
+
static createCustom<entityType, argsType>(rawFilterTranslator: (args: argsType, r: Remult) => EntityFilter<entityType> | Promise<EntityFilter<entityType>>, key?: string): ((y: argsType) => EntityFilter<entityType>) & rawFilterInfo<entityType>;
|
|
11
11
|
static fromEntityFilter<T>(entity: EntityMetadata<T>, whereItem: EntityFilter<T>): Filter;
|
|
12
12
|
toJson(): any;
|
|
13
13
|
static entityFilterToJson<T>(entityDefs: EntityMetadata<T>, where: EntityFilter<T>): any;
|
|
@@ -77,9 +77,9 @@ export declare function entityFilterToJson<T>(entityDefs: EntityMetadata<T>, whe
|
|
|
77
77
|
export declare function buildFilterFromRequestParameters(entity: EntityMetadata, filterInfo: {
|
|
78
78
|
get: (key: string) => any;
|
|
79
79
|
}): EntityFilter<any>;
|
|
80
|
-
export interface
|
|
81
|
-
|
|
80
|
+
export interface rawFilterInfo<entityType> {
|
|
81
|
+
rawFilterInfo: {
|
|
82
82
|
key: string;
|
|
83
|
-
|
|
83
|
+
rawFilterTranslator: (args: any, r: Remult) => (EntityFilter<entityType> | Promise<EntityFilter<entityType>>);
|
|
84
84
|
};
|
|
85
85
|
}
|