remult 0.18.1-exp.30 → 0.18.1-exp.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/live-query/data-provider-live-query-storage.d.ts +6 -3
- package/esm/live-query/data-provider-live-query-storage.js +15 -11
- package/esm/postgres/postgres-data-provider.d.ts +1 -1
- package/esm/postgres/postgres-data-provider.js +7 -5
- package/esm/postgres/schema-builder.d.ts +1 -0
- package/esm/postgres/schema-builder.js +16 -4
- package/esm/remult-knex/index.d.ts +4 -2
- package/esm/remult-knex/index.js +22 -13
- package/esm/server/expressBridge.d.ts +6 -0
- package/esm/server/expressBridge.js +20 -9
- package/esm/src/data-interfaces.d.ts +6 -1
- package/esm/src/data-providers/rest-data-provider.d.ts +1 -1
- package/esm/src/data-providers/rest-data-provider.js +1 -1
- package/esm/src/data-providers/sql-database.d.ts +1 -0
- package/esm/src/data-providers/sql-database.js +4 -0
- package/esm/src/data-providers/web-sql-data-provider.d.ts +1 -0
- package/esm/src/data-providers/web-sql-data-provider.js +5 -0
- package/esm/src/remult3/RepositoryImplementation.js +1 -1
- package/esm/src/sql-command.d.ts +1 -0
- package/esm/src/tests/testHelper.spec.d.ts +1 -1
- package/esm/src/tests/testHelper.spec.js +1 -1
- package/index.d.ts +1 -0
- package/index.js +3 -1
- package/live-query/data-provider-live-query-storage.d.ts +6 -3
- package/live-query/data-provider-live-query-storage.js +40 -10
- package/package.json +2 -10
- package/postgres/postgres-data-provider.d.ts +1 -1
- package/postgres/postgres-data-provider.js +41 -36
- package/postgres/schema-builder.d.ts +1 -0
- package/postgres/schema-builder.js +82 -38
- package/remult-knex/index.d.ts +4 -2
- package/remult-knex/index.js +67 -49
- package/server/expressBridge.d.ts +6 -0
- package/server/expressBridge.js +91 -51
- package/src/data-interfaces.d.ts +6 -1
- package/src/data-providers/rest-data-provider.d.ts +1 -1
- package/src/data-providers/rest-data-provider.js +1 -1
- package/src/data-providers/sql-database.d.ts +1 -0
- package/src/data-providers/sql-database.js +15 -0
- package/src/data-providers/web-sql-data-provider.d.ts +1 -0
- package/src/data-providers/web-sql-data-provider.js +39 -3
- package/src/remult3/RepositoryImplementation.js +1 -1
- package/src/sql-command.d.ts +1 -0
- package/src/tests/testHelper.spec.d.ts +1 -1
- package/src/tests/testHelper.spec.js +1 -1
package/esm/index.d.ts
CHANGED
|
@@ -26,3 +26,4 @@ export { ValueConverters } from './src/valueConverters';
|
|
|
26
26
|
export { remult } from './src/remult-proxy';
|
|
27
27
|
export { SubscriptionServer, LiveQueryStorage, StoredQuery, InMemoryLiveQueryStorage } from "./src/live-query/SubscriptionServer";
|
|
28
28
|
export { SubscriptionListener, SubscriptionClientConnection, SubscriptionClient, SubscriptionChannel, LiveQueryChange, Unsubscribe } from './src/live-query/SubscriptionChannel';
|
|
29
|
+
export { DataProviderLiveQueryStorage } from './live-query/data-provider-live-query-storage';
|
package/esm/index.js
CHANGED
|
@@ -24,3 +24,4 @@ export { remult } from './src/remult-proxy';
|
|
|
24
24
|
//export { getId } from './src/remult3/getId';
|
|
25
25
|
export { InMemoryLiveQueryStorage } from "./src/live-query/SubscriptionServer";
|
|
26
26
|
export { SubscriptionChannel } from './src/live-query/SubscriptionChannel';
|
|
27
|
+
export { DataProviderLiveQueryStorage } from './live-query/data-provider-live-query-storage';
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Remult } from "../src/context";
|
|
2
|
+
import { CanEnsureSchema, DataProvider } from "../src/data-interfaces";
|
|
2
3
|
import { LiveQueryStorage, StoredQuery } from "../src/live-query/SubscriptionServer";
|
|
3
4
|
import { Repository } from "../src/remult3";
|
|
4
|
-
export declare class DataProviderLiveQueryStorage implements LiveQueryStorage {
|
|
5
|
+
export declare class DataProviderLiveQueryStorage implements LiveQueryStorage, CanEnsureSchema {
|
|
5
6
|
repo: Promise<Repository<LiveQueryStorageEntity>>;
|
|
7
|
+
dataProvider: Promise<DataProvider>;
|
|
6
8
|
constructor(dataProvider: DataProvider | Promise<DataProvider> | (() => Promise<DataProvider | undefined>));
|
|
9
|
+
ensureSchema(remult: Remult): Promise<void>;
|
|
7
10
|
add({ id, entityKey, data }: StoredQuery): void;
|
|
8
11
|
remove(queryId: string): void;
|
|
9
12
|
forEach(entityKey: string, callback: (args: {
|
|
@@ -16,6 +19,6 @@ declare class LiveQueryStorageEntity {
|
|
|
16
19
|
id: string;
|
|
17
20
|
entityKey: string;
|
|
18
21
|
data: any;
|
|
19
|
-
|
|
22
|
+
lastUsedIso: string;
|
|
20
23
|
}
|
|
21
24
|
export {};
|
|
@@ -4,13 +4,17 @@ import { Remult } from "../src/context";
|
|
|
4
4
|
import { Entity, Fields } from "../src/remult3";
|
|
5
5
|
export class DataProviderLiveQueryStorage {
|
|
6
6
|
constructor(dataProvider) {
|
|
7
|
-
this.
|
|
7
|
+
this.dataProvider = initDataProvider(dataProvider);
|
|
8
|
+
this.repo = this.dataProvider.then(dp => new Remult(dp).repo(LiveQueryStorageEntity));
|
|
9
|
+
}
|
|
10
|
+
async ensureSchema(remult) {
|
|
11
|
+
await (await this.dataProvider).ensureSchema([(await this.repo).metadata], "Live query storage");
|
|
8
12
|
}
|
|
9
|
-
//TODO - consider case where query id already exists (reconnect)
|
|
10
13
|
add({ id, entityKey, data }) {
|
|
11
|
-
this.repo.then(repo =>
|
|
12
|
-
id,
|
|
13
|
-
|
|
14
|
+
this.repo.then(async (repo) => {
|
|
15
|
+
const q = await repo.findId(id, { createIfNotFound: true });
|
|
16
|
+
await repo.save({ ...q, entityKey, data });
|
|
17
|
+
});
|
|
14
18
|
}
|
|
15
19
|
remove(queryId) {
|
|
16
20
|
this.repo.then(repo => repo.delete(queryId)).catch(() => { });
|
|
@@ -19,9 +23,9 @@ export class DataProviderLiveQueryStorage {
|
|
|
19
23
|
const repo = await this.repo;
|
|
20
24
|
let d = new Date();
|
|
21
25
|
d.setMinutes(d.getMinutes() - 5);
|
|
26
|
+
const iso = d.toISOString();
|
|
22
27
|
for (const query of await repo.find({ where: { entityKey } })) {
|
|
23
|
-
|
|
24
|
-
if (query.lastUsed < d)
|
|
28
|
+
if (query.lastUsedIso < iso)
|
|
25
29
|
await repo.delete(query);
|
|
26
30
|
else {
|
|
27
31
|
await callback({
|
|
@@ -36,7 +40,7 @@ export class DataProviderLiveQueryStorage {
|
|
|
36
40
|
async keepAliveAndReturnUnknownQueryIds(queryIds) {
|
|
37
41
|
const repo = await this.repo;
|
|
38
42
|
for (const query of await repo.find({ where: { id: queryIds } })) {
|
|
39
|
-
query.
|
|
43
|
+
query.lastUsedIso = new Date().toISOString();
|
|
40
44
|
await repo.save(query);
|
|
41
45
|
queryIds = queryIds.filter(x => x !== query.id);
|
|
42
46
|
}
|
|
@@ -47,7 +51,7 @@ let LiveQueryStorageEntity = class LiveQueryStorageEntity {
|
|
|
47
51
|
constructor() {
|
|
48
52
|
this.id = '';
|
|
49
53
|
this.entityKey = '';
|
|
50
|
-
this.
|
|
54
|
+
this.lastUsedIso = new Date().toISOString();
|
|
51
55
|
}
|
|
52
56
|
};
|
|
53
57
|
__decorate([
|
|
@@ -63,9 +67,9 @@ __decorate([
|
|
|
63
67
|
__metadata("design:type", Object)
|
|
64
68
|
], LiveQueryStorageEntity.prototype, "data", void 0);
|
|
65
69
|
__decorate([
|
|
66
|
-
Fields.
|
|
70
|
+
Fields.string(),
|
|
67
71
|
__metadata("design:type", Object)
|
|
68
|
-
], LiveQueryStorageEntity.prototype, "
|
|
72
|
+
], LiveQueryStorageEntity.prototype, "lastUsedIso", void 0);
|
|
69
73
|
LiveQueryStorageEntity = __decorate([
|
|
70
74
|
Entity(undefined, {
|
|
71
75
|
dbName: 'remult_live_query_storage'
|
|
@@ -16,6 +16,7 @@ export declare class PostgresDataProvider implements SqlImplementation {
|
|
|
16
16
|
getLimitSqlSyntax(limit: number, offset: number): string;
|
|
17
17
|
createCommand(): SqlCommand;
|
|
18
18
|
constructor(pool: PostgresPool);
|
|
19
|
+
ensureSchema(entities: EntityMetadata<any>[], caption?: string): Promise<void>;
|
|
19
20
|
transaction(action: (dataProvider: SqlImplementation) => Promise<void>): Promise<void>;
|
|
20
21
|
}
|
|
21
22
|
export interface PostgresCommandSource {
|
|
@@ -25,6 +26,5 @@ export declare function createPostgresConnection(options?: {
|
|
|
25
26
|
connectionString?: string;
|
|
26
27
|
sslInDev?: boolean;
|
|
27
28
|
configuration?: "heroku" | PoolConfig;
|
|
28
|
-
autoCreateTables?: boolean;
|
|
29
29
|
}): Promise<SqlDatabase>;
|
|
30
30
|
export declare function preparePostgresQueueStorage(sql: SqlDatabase): Promise<import("../server/expressBridge").EntityQueueStorage>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Pool } from 'pg';
|
|
2
2
|
import { Remult } from '../src/context';
|
|
3
|
-
import { PostgresSchemaBuilder
|
|
3
|
+
import { PostgresSchemaBuilder } from './schema-builder';
|
|
4
4
|
import { SqlDatabase } from '../src/data-providers/sql-database';
|
|
5
5
|
export class PostgresDataProvider {
|
|
6
6
|
constructor(pool) {
|
|
@@ -22,6 +22,11 @@ export class PostgresDataProvider {
|
|
|
22
22
|
createCommand() {
|
|
23
23
|
return new PostgresBridgeToSQLCommand(this.pool);
|
|
24
24
|
}
|
|
25
|
+
async ensureSchema(entities, caption) {
|
|
26
|
+
var db = new SqlDatabase(this);
|
|
27
|
+
var sb = new PostgresSchemaBuilder(db);
|
|
28
|
+
await sb.ensureSchema(entities, caption);
|
|
29
|
+
}
|
|
25
30
|
async transaction(action) {
|
|
26
31
|
let client = await this.pool.connect();
|
|
27
32
|
try {
|
|
@@ -92,8 +97,6 @@ export async function createPostgresConnection(options) {
|
|
|
92
97
|
const db = new SqlDatabase(new PostgresDataProvider(new Pool(config)));
|
|
93
98
|
let remult = new Remult();
|
|
94
99
|
remult.dataProvider = (db);
|
|
95
|
-
if (options.autoCreateTables === undefined || options.autoCreateTables)
|
|
96
|
-
await verifyStructureOfAllEntities(db, remult);
|
|
97
100
|
return db;
|
|
98
101
|
}
|
|
99
102
|
export async function preparePostgresQueueStorage(sql) {
|
|
@@ -101,7 +104,6 @@ export async function preparePostgresQueueStorage(sql) {
|
|
|
101
104
|
c.dataProvider = (sql);
|
|
102
105
|
let JobsInQueueEntity = (await import('../server/expressBridge')).JobsInQueueEntity;
|
|
103
106
|
let e = c.repo(JobsInQueueEntity);
|
|
104
|
-
await
|
|
105
|
-
await new PostgresSchemaBuilder(sql).verifyAllColumns(e.metadata);
|
|
107
|
+
await sql.ensureSchema([e.metadata], "Queue storage");
|
|
106
108
|
return new (await import('../server/expressBridge')).EntityQueueStorage(c.repo(JobsInQueueEntity));
|
|
107
109
|
}
|
|
@@ -7,6 +7,7 @@ export declare function verifyStructureOfAllEntities(db: SqlDatabase, remult: Re
|
|
|
7
7
|
export declare class PostgresSchemaBuilder {
|
|
8
8
|
private pool;
|
|
9
9
|
verifyStructureOfAllEntities(remult?: Remult): Promise<void>;
|
|
10
|
+
ensureSchema(entities: EntityMetadata<any>[], caption?: string): Promise<void>;
|
|
10
11
|
createIfNotExist(entity: EntityMetadata): Promise<void>;
|
|
11
12
|
addColumnIfNotExist<T extends EntityMetadata>(entity: T, c: ((e: T) => FieldMetadata)): Promise<void>;
|
|
12
13
|
verifyAllColumns<T extends EntityMetadata>(entity: T): Promise<void>;
|
|
@@ -47,18 +47,30 @@ export class PostgresSchemaBuilder {
|
|
|
47
47
|
if (!remult) {
|
|
48
48
|
remult = RemultProxy.defaultRemult;
|
|
49
49
|
}
|
|
50
|
-
if (PostgresSchemaBuilder.logToConsole)
|
|
51
|
-
console.time("Postgres Auto create tables and columns");
|
|
52
50
|
const completed = new Set();
|
|
51
|
+
const entities = [];
|
|
53
52
|
for (const entityClass of [...allEntities].reverse()) {
|
|
54
53
|
let entity = remult.repo(entityClass).metadata;
|
|
55
54
|
let e = await dbNamesOf(entity);
|
|
56
55
|
if (completed.has(e.$entityName))
|
|
57
56
|
continue;
|
|
58
57
|
completed.add(e.$entityName);
|
|
58
|
+
entities.push(entity);
|
|
59
|
+
}
|
|
60
|
+
await this.ensureSchema(entities);
|
|
61
|
+
}
|
|
62
|
+
async ensureSchema(entities, caption) {
|
|
63
|
+
//TODO - discuss this console log
|
|
64
|
+
let desc = "Ensure postgres schema";
|
|
65
|
+
if (caption)
|
|
66
|
+
desc += " - " + caption;
|
|
67
|
+
if (PostgresSchemaBuilder.logToConsole)
|
|
68
|
+
console.time(desc);
|
|
69
|
+
for (const entity of entities) {
|
|
70
|
+
let e = await dbNamesOf(entity);
|
|
59
71
|
try {
|
|
60
72
|
if (!entity.options.sqlExpression) {
|
|
61
|
-
if (
|
|
73
|
+
if (e.$entityName.toLowerCase().indexOf('from ') < 0) {
|
|
62
74
|
await this.createIfNotExist(entity);
|
|
63
75
|
await this.verifyAllColumns(entity);
|
|
64
76
|
}
|
|
@@ -69,7 +81,7 @@ export class PostgresSchemaBuilder {
|
|
|
69
81
|
}
|
|
70
82
|
}
|
|
71
83
|
if (PostgresSchemaBuilder.logToConsole)
|
|
72
|
-
console.timeEnd(
|
|
84
|
+
console.timeEnd(desc);
|
|
73
85
|
}
|
|
74
86
|
async createIfNotExist(entity) {
|
|
75
87
|
var c = this.pool.createCommand();
|
|
@@ -11,12 +11,14 @@ export declare class KnexDataProvider implements DataProvider {
|
|
|
11
11
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
12
12
|
static rawFilter(build: CustomKnexFilterBuilderFunction): EntityFilter<any>;
|
|
13
13
|
static filterToRaw<entityType>(entity: RepositoryOverloads<entityType>, condition: EntityFilter<entityType>): Promise<(knex: any) => void>;
|
|
14
|
-
|
|
14
|
+
supportsRawFilter?: boolean;
|
|
15
|
+
ensureSchema(entities: EntityMetadata<any>[], caption?: string): Promise<void>;
|
|
15
16
|
}
|
|
16
17
|
export declare type CustomKnexFilterBuilderFunction = () => Promise<(builder: Knex.QueryBuilder) => void>;
|
|
17
18
|
export declare class KnexSchemaBuilder {
|
|
18
19
|
private knex;
|
|
19
20
|
verifyStructureOfAllEntities(remult?: Remult): Promise<void>;
|
|
21
|
+
ensureSchema(entities: EntityMetadata<any>[], caption?: string): Promise<void>;
|
|
20
22
|
createIfNotExist(entity: EntityMetadata): Promise<void>;
|
|
21
23
|
addColumnIfNotExist<T extends EntityMetadata>(entity: T, c: ((e: T) => FieldMetadata)): Promise<void>;
|
|
22
24
|
verifyAllColumns<T extends EntityMetadata>(entity: T): Promise<void>;
|
|
@@ -24,4 +26,4 @@ export declare class KnexSchemaBuilder {
|
|
|
24
26
|
constructor(knex: Knex);
|
|
25
27
|
}
|
|
26
28
|
export declare function buildColumn(x: FieldMetadata, dbName: string, b: Knex.CreateTableBuilder): void;
|
|
27
|
-
export declare function createKnexDataProvider(config: Knex.Config
|
|
29
|
+
export declare function createKnexDataProvider(config: Knex.Config): Promise<KnexDataProvider>;
|
package/esm/remult-knex/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { customDatabaseFilterToken, Filter } from "../src/filter/filter-interfaces";
|
|
2
2
|
import { dbNamesOf, isDbReadonly } from "../src/filter/filter-consumer-bridge-to-sql-request";
|
|
3
|
-
import { allEntities
|
|
3
|
+
import { allEntities } from "../src/context";
|
|
4
4
|
import { isAutoIncrement, getRepository } from "../src/remult3";
|
|
5
5
|
import { ValueConverters } from "../src/valueConverters";
|
|
6
6
|
import { CompoundIdField } from '../src/column';
|
|
@@ -45,6 +45,10 @@ export class KnexDataProvider {
|
|
|
45
45
|
let r = await b.resolveWhere();
|
|
46
46
|
return knex => r.forEach(y => y(knex));
|
|
47
47
|
}
|
|
48
|
+
async ensureSchema(entities, caption) {
|
|
49
|
+
var sb = new KnexSchemaBuilder(this.knex);
|
|
50
|
+
await sb.ensureSchema(entities, caption);
|
|
51
|
+
}
|
|
48
52
|
}
|
|
49
53
|
class KnexEntityDataProvider {
|
|
50
54
|
constructor(entity, knex) {
|
|
@@ -279,24 +283,31 @@ export class KnexSchemaBuilder {
|
|
|
279
283
|
async verifyStructureOfAllEntities(remult) {
|
|
280
284
|
if (!remult)
|
|
281
285
|
remult = RemultProxy.defaultRemult;
|
|
286
|
+
const entities = allEntities.map(x => remult.repo(x).metadata);
|
|
287
|
+
this.ensureSchema(entities);
|
|
288
|
+
}
|
|
289
|
+
async ensureSchema(entities, caption) {
|
|
290
|
+
let desc = "ensure knex schema";
|
|
291
|
+
if (caption)
|
|
292
|
+
desc += " - " + caption;
|
|
282
293
|
if (KnexSchemaBuilder.logToConsole)
|
|
283
|
-
console.time(
|
|
284
|
-
for (const entity of
|
|
285
|
-
let
|
|
294
|
+
console.time(desc);
|
|
295
|
+
for (const entity of entities) {
|
|
296
|
+
let e = await dbNamesOf(entity);
|
|
286
297
|
try {
|
|
287
|
-
if (!
|
|
288
|
-
if (
|
|
289
|
-
await this.createIfNotExist(
|
|
290
|
-
await this.verifyAllColumns(
|
|
298
|
+
if (!entity.options.sqlExpression) {
|
|
299
|
+
if (e.$entityName.toLowerCase().indexOf('from ') < 0) {
|
|
300
|
+
await this.createIfNotExist(entity);
|
|
301
|
+
await this.verifyAllColumns(entity);
|
|
291
302
|
}
|
|
292
303
|
}
|
|
293
304
|
}
|
|
294
305
|
catch (err) {
|
|
295
|
-
console.error("failed verify structure of " +
|
|
306
|
+
console.error("failed verify structure of " + e.$entityName + " ", err);
|
|
296
307
|
}
|
|
297
308
|
}
|
|
298
309
|
if (KnexSchemaBuilder.logToConsole)
|
|
299
|
-
console.timeEnd(
|
|
310
|
+
console.timeEnd(desc);
|
|
300
311
|
}
|
|
301
312
|
async createIfNotExist(entity) {
|
|
302
313
|
const e = await dbNamesOf(entity);
|
|
@@ -405,10 +416,8 @@ function logSql(who) {
|
|
|
405
416
|
console.info(who.toSQL());
|
|
406
417
|
return who;
|
|
407
418
|
}
|
|
408
|
-
export async function createKnexDataProvider(config
|
|
419
|
+
export async function createKnexDataProvider(config) {
|
|
409
420
|
let k = (await import('knex')).default(config);
|
|
410
421
|
let result = new KnexDataProvider(k);
|
|
411
|
-
if (autoCreateTables)
|
|
412
|
-
await new KnexSchemaBuilder(k).verifyStructureOfAllEntities(new Remult(result));
|
|
413
422
|
return result;
|
|
414
423
|
}
|
|
@@ -19,6 +19,12 @@ export interface RemultServerOptions<RequestType extends GenericRequest> {
|
|
|
19
19
|
toJson: (request: RequestType) => any;
|
|
20
20
|
fromJson: (request: any) => RequestType;
|
|
21
21
|
};
|
|
22
|
+
/** Will create tables and columns in supporting databases. default: true
|
|
23
|
+
*
|
|
24
|
+
* @description
|
|
25
|
+
* when set to true, it'll create entities that do not exist, and add columns that are missing.
|
|
26
|
+
*/
|
|
27
|
+
ensureSchema?: boolean;
|
|
22
28
|
getUser?: (request: RequestType) => Promise<UserInfo | undefined>;
|
|
23
29
|
initApi?: (remult: Remult) => void | Promise<void>;
|
|
24
30
|
logApiEndPoints?: boolean;
|
|
@@ -27,19 +27,30 @@ export function createRemultServerCore(options) {
|
|
|
27
27
|
options.queueStorage = new InMemoryQueueStorage();
|
|
28
28
|
}
|
|
29
29
|
let dataProvider = initDataProvider(options.dataProvider);
|
|
30
|
+
if (options.ensureSchema === undefined)
|
|
31
|
+
options.ensureSchema = true;
|
|
30
32
|
RemultAsyncLocalStorage.enable();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
dataProvider = dataProvider.then(async (dp) => {
|
|
34
|
+
var remult = new Remult(dp);
|
|
35
|
+
await new Promise((res) => {
|
|
36
|
+
RemultAsyncLocalStorage.instance.run(remult, async () => {
|
|
37
|
+
if (options.ensureSchema) {
|
|
38
|
+
if (dp.ensureSchema) {
|
|
39
|
+
const entitiesMetadata = options.entities.map(e => remult.repo(e).metadata);
|
|
40
|
+
await dp.ensureSchema(entitiesMetadata);
|
|
41
|
+
for (const item of [options.liveQueryStorage, options.queueStorage]) {
|
|
42
|
+
if (item?.ensureSchema)
|
|
43
|
+
await item.ensureSchema(remult);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (options.initApi)
|
|
36
48
|
await options.initApi(remult);
|
|
37
|
-
|
|
38
|
-
});
|
|
49
|
+
res({});
|
|
39
50
|
});
|
|
40
|
-
return dp;
|
|
41
51
|
});
|
|
42
|
-
|
|
52
|
+
return dp;
|
|
53
|
+
});
|
|
43
54
|
if (!options.requestSerializer) {
|
|
44
55
|
options.requestSerializer = {
|
|
45
56
|
toJson: x => {
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { Sort } from './sort';
|
|
2
2
|
import { Filter } from './filter/filter-interfaces';
|
|
3
3
|
import { EntityMetadata, OmitEB } from './remult3';
|
|
4
|
+
import type { Remult } from './context';
|
|
4
5
|
export interface DataProvider {
|
|
5
6
|
getEntityDataProvider(entity: EntityMetadata): EntityDataProvider;
|
|
6
7
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
7
|
-
|
|
8
|
+
supportsRawFilter?: boolean;
|
|
9
|
+
ensureSchema?(entities: EntityMetadata[], caption?: string): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export interface CanEnsureSchema {
|
|
12
|
+
ensureSchema(remult: Remult): Promise<void>;
|
|
8
13
|
}
|
|
9
14
|
export interface EntityDataProvider {
|
|
10
15
|
count(where: Filter): Promise<number>;
|
|
@@ -8,7 +8,7 @@ export declare class RestDataProvider implements DataProvider {
|
|
|
8
8
|
constructor(apiProvider: () => ApiClient);
|
|
9
9
|
getEntityDataProvider(entity: EntityMetadata): RestEntityDataProvider;
|
|
10
10
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
11
|
-
|
|
11
|
+
supportsRawFilter: boolean;
|
|
12
12
|
}
|
|
13
13
|
export declare class RestEntityDataProvider implements EntityDataProvider {
|
|
14
14
|
private url;
|
|
@@ -5,7 +5,7 @@ import { actionInfo } from '../server-action';
|
|
|
5
5
|
export class RestDataProvider {
|
|
6
6
|
constructor(apiProvider) {
|
|
7
7
|
this.apiProvider = apiProvider;
|
|
8
|
-
this.
|
|
8
|
+
this.supportsRawFilter = true;
|
|
9
9
|
}
|
|
10
10
|
getEntityDataProvider(entity) {
|
|
11
11
|
return new RestEntityDataProvider(() => {
|
|
@@ -8,6 +8,7 @@ export declare class SqlDatabase implements DataProvider {
|
|
|
8
8
|
static getDb(remult?: Remult): SqlDatabase;
|
|
9
9
|
createCommand(): SqlCommand;
|
|
10
10
|
execute(sql: string): Promise<SqlResult>;
|
|
11
|
+
ensureSchema(entities: EntityMetadata<any>[], caption?: string): Promise<void>;
|
|
11
12
|
getEntityDataProvider(entity: EntityMetadata): EntityDataProvider;
|
|
12
13
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
13
14
|
static rawFilter(build: CustomSqlFilterBuilderFunction): EntityFilter<any>;
|
|
@@ -26,6 +26,10 @@ export class SqlDatabase {
|
|
|
26
26
|
_getSourceSql() {
|
|
27
27
|
return this.sql;
|
|
28
28
|
}
|
|
29
|
+
async ensureSchema(entities, caption) {
|
|
30
|
+
if (this.sql.ensureSchema)
|
|
31
|
+
await this.sql.ensureSchema(entities, caption);
|
|
32
|
+
}
|
|
29
33
|
getEntityDataProvider(entity) {
|
|
30
34
|
return new ActualSQLServerDataProvider(entity, this, async (dbName) => {
|
|
31
35
|
if (this.createdEntities.indexOf(dbName.$entityName) < 0) {
|
|
@@ -11,6 +11,7 @@ export declare class WebSqlDataProvider implements SqlImplementation, __RowsOfDa
|
|
|
11
11
|
static getDb(remult?: Remult): any;
|
|
12
12
|
getLimitSqlSyntax(limit: number, offset: number): string;
|
|
13
13
|
entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
|
|
14
|
+
ensureSchema(entities: EntityMetadata<any>[]): Promise<void>;
|
|
14
15
|
dropTable(entity: EntityMetadata): Promise<void>;
|
|
15
16
|
createTable(entity: EntityMetadata<any>): Promise<void>;
|
|
16
17
|
createCommand(): SqlCommand;
|
|
@@ -23,6 +23,11 @@ export class WebSqlDataProvider {
|
|
|
23
23
|
async entityIsUsedForTheFirstTime(entity) {
|
|
24
24
|
await this.createTable(entity);
|
|
25
25
|
}
|
|
26
|
+
async ensureSchema(entities) {
|
|
27
|
+
for (const entity of entities) {
|
|
28
|
+
await this.createTable(entity);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
26
31
|
async dropTable(entity) {
|
|
27
32
|
let e = await dbNamesOf(entity);
|
|
28
33
|
let sql = 'drop table if exists ' + e.$entityName;
|
|
@@ -394,7 +394,7 @@ export class RepositoryImplementation {
|
|
|
394
394
|
};
|
|
395
395
|
}
|
|
396
396
|
let r = await Filter.fromEntityFilter(this.metadata, where);
|
|
397
|
-
if (r && !this.dataProvider.
|
|
397
|
+
if (r && !this.dataProvider.supportsRawFilter) {
|
|
398
398
|
r = await Filter.translateCustomWhere(r, this.metadata, this.remult);
|
|
399
399
|
}
|
|
400
400
|
return r;
|
package/esm/src/sql-command.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export interface SqlImplementation {
|
|
|
4
4
|
createCommand(): SqlCommand;
|
|
5
5
|
transaction(action: (sql: SqlImplementation) => Promise<void>): Promise<void>;
|
|
6
6
|
entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
|
|
7
|
+
ensureSchema?(entities: EntityMetadata[], caption?: string): Promise<void>;
|
|
7
8
|
}
|
|
8
9
|
export interface SqlCommand extends SqlCommandWithParameters {
|
|
9
10
|
execute(sql: string): Promise<SqlResult>;
|
|
@@ -31,6 +31,6 @@ export declare class MockRestDataProvider implements DataProvider {
|
|
|
31
31
|
constructor(remult: Remult);
|
|
32
32
|
getEntityDataProvider(metadata: EntityMetadata<any>): EntityDataProvider;
|
|
33
33
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
34
|
-
|
|
34
|
+
supportsRawFilter: boolean;
|
|
35
35
|
}
|
|
36
36
|
export declare function createMockHttpDataProvider(dataApi: DataApi<any>): import("../data-interfaces").RestDataProviderHttpProvider;
|
|
@@ -154,7 +154,7 @@ function urlToReq(url) {
|
|
|
154
154
|
export class MockRestDataProvider {
|
|
155
155
|
constructor(remult) {
|
|
156
156
|
this.remult = remult;
|
|
157
|
-
this.
|
|
157
|
+
this.supportsRawFilter = true;
|
|
158
158
|
}
|
|
159
159
|
getEntityDataProvider(metadata) {
|
|
160
160
|
let dataApi = new DataApi(this.remult.repo(metadata.entityType), this.remult);
|
package/index.d.ts
CHANGED
|
@@ -26,3 +26,4 @@ export { ValueConverters } from './src/valueConverters';
|
|
|
26
26
|
export { remult } from './src/remult-proxy';
|
|
27
27
|
export { SubscriptionServer, LiveQueryStorage, StoredQuery, InMemoryLiveQueryStorage } from "./src/live-query/SubscriptionServer";
|
|
28
28
|
export { SubscriptionListener, SubscriptionClientConnection, SubscriptionClient, SubscriptionChannel, LiveQueryChange, Unsubscribe } from './src/live-query/SubscriptionChannel';
|
|
29
|
+
export { DataProviderLiveQueryStorage } from './live-query/data-provider-live-query-storage';
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SubscriptionChannel = exports.InMemoryLiveQueryStorage = exports.remult = exports.ValueConverters = exports.Validators = exports.UrlBuilder = exports.Filter = exports.CompoundIdField = exports.OneToMany = exports.Sort = exports.IdEntity = exports.EventSource = exports.isBackend = exports.Remult = exports.Allow = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.JsonDataProvider = exports.dbNamesOf = exports.CustomSqlFilterBuilder = exports.SqlDatabase = exports.WebSqlDataProvider = exports.ArrayEntityDataProvider = exports.InMemoryDataProvider = exports.RestDataProvider = exports.describeClass = exports.CaptionTransformer = exports.ValueListInfo = exports.getValueList = exports.ValueListFieldType = exports.getEntityRef = exports.getFields = exports.FieldType = exports.ControllerBase = exports.EntityBase = exports.Entity = exports.Fields = exports.Field = void 0;
|
|
3
|
+
exports.DataProviderLiveQueryStorage = exports.SubscriptionChannel = exports.InMemoryLiveQueryStorage = exports.remult = exports.ValueConverters = exports.Validators = exports.UrlBuilder = exports.Filter = exports.CompoundIdField = exports.OneToMany = exports.Sort = exports.IdEntity = exports.EventSource = exports.isBackend = exports.Remult = exports.Allow = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.JsonDataProvider = exports.dbNamesOf = exports.CustomSqlFilterBuilder = exports.SqlDatabase = exports.WebSqlDataProvider = exports.ArrayEntityDataProvider = exports.InMemoryDataProvider = exports.RestDataProvider = exports.describeClass = exports.CaptionTransformer = exports.ValueListInfo = exports.getValueList = exports.ValueListFieldType = exports.getEntityRef = exports.getFields = exports.FieldType = exports.ControllerBase = exports.EntityBase = exports.Entity = exports.Fields = exports.Field = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Public API Surface of remult
|
|
6
6
|
*/
|
|
@@ -66,3 +66,5 @@ var SubscriptionServer_1 = require("./src/live-query/SubscriptionServer");
|
|
|
66
66
|
Object.defineProperty(exports, "InMemoryLiveQueryStorage", { enumerable: true, get: function () { return SubscriptionServer_1.InMemoryLiveQueryStorage; } });
|
|
67
67
|
var SubscriptionChannel_1 = require("./src/live-query/SubscriptionChannel");
|
|
68
68
|
Object.defineProperty(exports, "SubscriptionChannel", { enumerable: true, get: function () { return SubscriptionChannel_1.SubscriptionChannel; } });
|
|
69
|
+
var data_provider_live_query_storage_1 = require("./live-query/data-provider-live-query-storage");
|
|
70
|
+
Object.defineProperty(exports, "DataProviderLiveQueryStorage", { enumerable: true, get: function () { return data_provider_live_query_storage_1.DataProviderLiveQueryStorage; } });
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Remult } from "../src/context";
|
|
2
|
+
import { CanEnsureSchema, DataProvider } from "../src/data-interfaces";
|
|
2
3
|
import { LiveQueryStorage, StoredQuery } from "../src/live-query/SubscriptionServer";
|
|
3
4
|
import { Repository } from "../src/remult3";
|
|
4
|
-
export declare class DataProviderLiveQueryStorage implements LiveQueryStorage {
|
|
5
|
+
export declare class DataProviderLiveQueryStorage implements LiveQueryStorage, CanEnsureSchema {
|
|
5
6
|
repo: Promise<Repository<LiveQueryStorageEntity>>;
|
|
7
|
+
dataProvider: Promise<DataProvider>;
|
|
6
8
|
constructor(dataProvider: DataProvider | Promise<DataProvider> | (() => Promise<DataProvider | undefined>));
|
|
9
|
+
ensureSchema(remult: Remult): Promise<void>;
|
|
7
10
|
add({ id, entityKey, data }: StoredQuery): void;
|
|
8
11
|
remove(queryId: string): void;
|
|
9
12
|
forEach(entityKey: string, callback: (args: {
|
|
@@ -16,6 +19,6 @@ declare class LiveQueryStorageEntity {
|
|
|
16
19
|
id: string;
|
|
17
20
|
entityKey: string;
|
|
18
21
|
data: any;
|
|
19
|
-
|
|
22
|
+
lastUsedIso: string;
|
|
20
23
|
}
|
|
21
24
|
export {};
|
|
@@ -7,15 +7,44 @@ var context_1 = require("../src/context");
|
|
|
7
7
|
var remult3_1 = require("../src/remult3");
|
|
8
8
|
var DataProviderLiveQueryStorage = /** @class */ (function () {
|
|
9
9
|
function DataProviderLiveQueryStorage(dataProvider) {
|
|
10
|
-
this.
|
|
10
|
+
this.dataProvider = initDataProvider_1.initDataProvider(dataProvider);
|
|
11
|
+
this.repo = this.dataProvider.then(function (dp) {
|
|
11
12
|
return new context_1.Remult(dp).repo(LiveQueryStorageEntity);
|
|
12
13
|
});
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
DataProviderLiveQueryStorage.prototype.ensureSchema = function (remult) {
|
|
16
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
return tslib_1.__generator(this, function (_c) {
|
|
19
|
+
switch (_c.label) {
|
|
20
|
+
case 0: return [4 /*yield*/, this.dataProvider];
|
|
21
|
+
case 1:
|
|
22
|
+
_b = (_a = (_c.sent())).ensureSchema;
|
|
23
|
+
return [4 /*yield*/, this.repo];
|
|
24
|
+
case 2: return [4 /*yield*/, _b.apply(_a, [[(_c.sent()).metadata], "Live query storage"])];
|
|
25
|
+
case 3:
|
|
26
|
+
_c.sent();
|
|
27
|
+
return [2 /*return*/];
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
};
|
|
15
32
|
DataProviderLiveQueryStorage.prototype.add = function (_a) {
|
|
33
|
+
var _this = this;
|
|
16
34
|
var id = _a.id, entityKey = _a.entityKey, data = _a.data;
|
|
17
|
-
this.repo.then(function (repo) { return
|
|
18
|
-
|
|
35
|
+
this.repo.then(function (repo) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
36
|
+
var q;
|
|
37
|
+
return tslib_1.__generator(this, function (_a) {
|
|
38
|
+
switch (_a.label) {
|
|
39
|
+
case 0: return [4 /*yield*/, repo.findId(id, { createIfNotFound: true })];
|
|
40
|
+
case 1:
|
|
41
|
+
q = _a.sent();
|
|
42
|
+
return [4 /*yield*/, repo.save(tslib_1.__assign(tslib_1.__assign({}, q), { entityKey: entityKey, data: data }))];
|
|
43
|
+
case 2:
|
|
44
|
+
_a.sent();
|
|
45
|
+
return [2 /*return*/];
|
|
46
|
+
}
|
|
47
|
+
});
|
|
19
48
|
}); });
|
|
20
49
|
};
|
|
21
50
|
DataProviderLiveQueryStorage.prototype.remove = function (queryId) {
|
|
@@ -23,7 +52,7 @@ var DataProviderLiveQueryStorage = /** @class */ (function () {
|
|
|
23
52
|
};
|
|
24
53
|
DataProviderLiveQueryStorage.prototype.forEach = function (entityKey, callback) {
|
|
25
54
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
26
|
-
var repo, d, _loop_1, _a, _b, query, e_1_1;
|
|
55
|
+
var repo, d, iso, _loop_1, _a, _b, query, e_1_1;
|
|
27
56
|
var e_1, _c;
|
|
28
57
|
var _this = this;
|
|
29
58
|
return tslib_1.__generator(this, function (_d) {
|
|
@@ -33,11 +62,12 @@ var DataProviderLiveQueryStorage = /** @class */ (function () {
|
|
|
33
62
|
repo = _d.sent();
|
|
34
63
|
d = new Date();
|
|
35
64
|
d.setMinutes(d.getMinutes() - 5);
|
|
65
|
+
iso = d.toISOString();
|
|
36
66
|
_loop_1 = function (query) {
|
|
37
67
|
return tslib_1.__generator(this, function (_a) {
|
|
38
68
|
switch (_a.label) {
|
|
39
69
|
case 0:
|
|
40
|
-
if (!(query.
|
|
70
|
+
if (!(query.lastUsedIso < iso)) return [3 /*break*/, 2];
|
|
41
71
|
return [4 /*yield*/, repo.delete(query)];
|
|
42
72
|
case 1:
|
|
43
73
|
_a.sent();
|
|
@@ -109,7 +139,7 @@ var DataProviderLiveQueryStorage = /** @class */ (function () {
|
|
|
109
139
|
return tslib_1.__generator(this, function (_a) {
|
|
110
140
|
switch (_a.label) {
|
|
111
141
|
case 0:
|
|
112
|
-
query.
|
|
142
|
+
query.lastUsedIso = new Date().toISOString();
|
|
113
143
|
return [4 /*yield*/, repo.save(query)];
|
|
114
144
|
case 1:
|
|
115
145
|
_a.sent();
|
|
@@ -158,7 +188,7 @@ var LiveQueryStorageEntity = /** @class */ (function () {
|
|
|
158
188
|
function LiveQueryStorageEntity() {
|
|
159
189
|
this.id = '';
|
|
160
190
|
this.entityKey = '';
|
|
161
|
-
this.
|
|
191
|
+
this.lastUsedIso = new Date().toISOString();
|
|
162
192
|
}
|
|
163
193
|
tslib_1.__decorate([
|
|
164
194
|
remult3_1.Fields.string(),
|
|
@@ -173,9 +203,9 @@ var LiveQueryStorageEntity = /** @class */ (function () {
|
|
|
173
203
|
tslib_1.__metadata("design:type", Object)
|
|
174
204
|
], LiveQueryStorageEntity.prototype, "data", void 0);
|
|
175
205
|
tslib_1.__decorate([
|
|
176
|
-
remult3_1.Fields.
|
|
206
|
+
remult3_1.Fields.string(),
|
|
177
207
|
tslib_1.__metadata("design:type", Object)
|
|
178
|
-
], LiveQueryStorageEntity.prototype, "
|
|
208
|
+
], LiveQueryStorageEntity.prototype, "lastUsedIso", void 0);
|
|
179
209
|
LiveQueryStorageEntity = tslib_1.__decorate([
|
|
180
210
|
remult3_1.Entity(undefined, {
|
|
181
211
|
dbName: 'remult_live_query_storage'
|