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.
Files changed (47) hide show
  1. package/esm/index.d.ts +1 -0
  2. package/esm/index.js +1 -0
  3. package/esm/live-query/data-provider-live-query-storage.d.ts +6 -3
  4. package/esm/live-query/data-provider-live-query-storage.js +15 -11
  5. package/esm/postgres/postgres-data-provider.d.ts +1 -1
  6. package/esm/postgres/postgres-data-provider.js +7 -5
  7. package/esm/postgres/schema-builder.d.ts +1 -0
  8. package/esm/postgres/schema-builder.js +16 -4
  9. package/esm/remult-knex/index.d.ts +4 -2
  10. package/esm/remult-knex/index.js +22 -13
  11. package/esm/server/expressBridge.d.ts +6 -0
  12. package/esm/server/expressBridge.js +20 -9
  13. package/esm/src/data-interfaces.d.ts +6 -1
  14. package/esm/src/data-providers/rest-data-provider.d.ts +1 -1
  15. package/esm/src/data-providers/rest-data-provider.js +1 -1
  16. package/esm/src/data-providers/sql-database.d.ts +1 -0
  17. package/esm/src/data-providers/sql-database.js +4 -0
  18. package/esm/src/data-providers/web-sql-data-provider.d.ts +1 -0
  19. package/esm/src/data-providers/web-sql-data-provider.js +5 -0
  20. package/esm/src/remult3/RepositoryImplementation.js +1 -1
  21. package/esm/src/sql-command.d.ts +1 -0
  22. package/esm/src/tests/testHelper.spec.d.ts +1 -1
  23. package/esm/src/tests/testHelper.spec.js +1 -1
  24. package/index.d.ts +1 -0
  25. package/index.js +3 -1
  26. package/live-query/data-provider-live-query-storage.d.ts +6 -3
  27. package/live-query/data-provider-live-query-storage.js +40 -10
  28. package/package.json +2 -10
  29. package/postgres/postgres-data-provider.d.ts +1 -1
  30. package/postgres/postgres-data-provider.js +41 -36
  31. package/postgres/schema-builder.d.ts +1 -0
  32. package/postgres/schema-builder.js +82 -38
  33. package/remult-knex/index.d.ts +4 -2
  34. package/remult-knex/index.js +67 -49
  35. package/server/expressBridge.d.ts +6 -0
  36. package/server/expressBridge.js +91 -51
  37. package/src/data-interfaces.d.ts +6 -1
  38. package/src/data-providers/rest-data-provider.d.ts +1 -1
  39. package/src/data-providers/rest-data-provider.js +1 -1
  40. package/src/data-providers/sql-database.d.ts +1 -0
  41. package/src/data-providers/sql-database.js +15 -0
  42. package/src/data-providers/web-sql-data-provider.d.ts +1 -0
  43. package/src/data-providers/web-sql-data-provider.js +39 -3
  44. package/src/remult3/RepositoryImplementation.js +1 -1
  45. package/src/sql-command.d.ts +1 -0
  46. package/src/tests/testHelper.spec.d.ts +1 -1
  47. 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 { DataProvider } from "../src/data-interfaces";
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
- lastUsed: Date;
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.repo = initDataProvider(dataProvider).then(dp => new Remult(dp).repo(LiveQueryStorageEntity));
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 => repo.insert({
12
- id, entityKey, data
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
- //TODO - has timezone issues - if two servers are connected from two timezones this will fail!
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.lastUsed = new Date();
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.lastUsed = new Date();
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.date(),
70
+ Fields.string(),
67
71
  __metadata("design:type", Object)
68
- ], LiveQueryStorageEntity.prototype, "lastUsed", void 0);
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, verifyStructureOfAllEntities } from './schema-builder';
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 new PostgresSchemaBuilder(sql).createIfNotExist(e.metadata);
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 ((await e.$entityName).toLowerCase().indexOf('from ') < 0) {
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("Postgres Auto create tables and columns");
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
- supportsrawFilter?: boolean;
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, autoCreateTables?: boolean): Promise<KnexDataProvider>;
29
+ export declare function createKnexDataProvider(config: Knex.Config): Promise<KnexDataProvider>;
@@ -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, Remult } from "../src/context";
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("Knex Auto create tables and columns");
284
- for (const entity of allEntities) {
285
- let metadata = remult.repo(entity).metadata;
294
+ console.time(desc);
295
+ for (const entity of entities) {
296
+ let e = await dbNamesOf(entity);
286
297
  try {
287
- if (!metadata.options.sqlExpression) {
288
- if ((await metadata.getDbName()).toLowerCase().indexOf('from ') < 0) {
289
- await this.createIfNotExist(metadata);
290
- await this.verifyAllColumns(metadata);
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 " + await metadata.getDbName() + " ", err);
306
+ console.error("failed verify structure of " + e.$entityName + " ", err);
296
307
  }
297
308
  }
298
309
  if (KnexSchemaBuilder.logToConsole)
299
- console.timeEnd("Knex Auto create tables and columns");
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, autoCreateTables = true) {
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
- if (options.initApi) {
32
- dataProvider = dataProvider.then(async (dp) => {
33
- var remult = new Remult(dp);
34
- await new Promise((res) => {
35
- RemultAsyncLocalStorage.instance.run(remult, async () => {
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
- res({});
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
- supportsrawFilter?: boolean;
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
- supportsrawFilter: boolean;
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.supportsrawFilter = true;
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.supportsrawFilter) {
397
+ if (r && !this.dataProvider.supportsRawFilter) {
398
398
  r = await Filter.translateCustomWhere(r, this.metadata, this.remult);
399
399
  }
400
400
  return r;
@@ -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
- supportsrawFilter: boolean;
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.supportsrawFilter = true;
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 { DataProvider } from "../src/data-interfaces";
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
- lastUsed: Date;
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.repo = initDataProvider_1.initDataProvider(dataProvider).then(function (dp) {
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
- //TODO - consider case where query id already exists (reconnect)
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 repo.insert({
18
- id: id, entityKey: entityKey, data: data
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.lastUsed < d)) return [3 /*break*/, 2];
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.lastUsed = new Date();
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.lastUsed = new Date();
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.date(),
206
+ remult3_1.Fields.string(),
177
207
  tslib_1.__metadata("design:type", Object)
178
- ], LiveQueryStorageEntity.prototype, "lastUsed", void 0);
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'