remult 0.22.12 → 0.22.13-exp.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/SseSubscriptionServer.d.ts +1 -2
  2. package/assign.js +1 -2
  3. package/esm/SseSubscriptionServer.d.ts +1 -2
  4. package/esm/internals.js +7 -5
  5. package/esm/migrations/compare-migration-snapshots.js +61 -0
  6. package/esm/migrations/generate-migrations.js +68 -0
  7. package/esm/migrations/index.js +2 -0
  8. package/esm/migrations/migrate.js +85 -0
  9. package/esm/migrations/migration-types.js +36 -0
  10. package/esm/migrations/update-migrations-ts-file.js +115 -0
  11. package/esm/package.json +3 -0
  12. package/esm/remult-better-sqlite3.js +47 -0
  13. package/esm/remult-bun-sqlite.js +41 -0
  14. package/esm/remult-duckdb.js +116 -0
  15. package/esm/remult-hapi.js +114 -0
  16. package/esm/remult-hono.js +104 -0
  17. package/esm/remult-next.d.ts +0 -1
  18. package/esm/remult-nuxt.js +54 -0
  19. package/esm/remult-solid-start.js +97 -0
  20. package/esm/remult-sql-js.js +41 -0
  21. package/esm/remult-sqlite-core.js +109 -0
  22. package/esm/remult-sqlite3.js +61 -0
  23. package/esm/remult-turso.js +59 -0
  24. package/esm/server/get-remult-admin-html.js +3 -0
  25. package/esm/server/initDataProviderOrJson.js +6 -0
  26. package/esm/server/remult-admin.js +89 -0
  27. package/esm/server/remult-api-server.js +1158 -0
  28. package/esm/src/data-providers/json-entity-opfs-storage.js +26 -0
  29. package/esm/src/data-providers/sql-database.js +9 -9
  30. package/esm/src/isOfType.js +9 -0
  31. package/esm/src/live-query/SubscriptionServer.js +2 -2
  32. package/esm/src/remult-static.js +43 -0
  33. package/esm/src/remult3/Fields.js +169 -29
  34. package/esm/src/remult3/IdEntity.js +2 -2
  35. package/esm/src/remult3/RepositoryImplementation.js +2 -2
  36. package/esm/src/remult3/addValidator.js +15 -0
  37. package/esm/src/remult3/classDescribers.js +35 -0
  38. package/esm/src/remult3/relation-loader.js +22 -11
  39. package/esm/src/remult3/relationInfoMember.js +113 -1
  40. package/esm/src/remult3/repository-internals.js +1 -1
  41. package/esm/src/valueConverters.js +1 -1
  42. package/graphql.js +2 -3
  43. package/internals.d.ts +15 -7
  44. package/internals.js +16 -13
  45. package/live-query/data-provider-live-query-storage.js +6 -6
  46. package/migrations/compare-migration-snapshots.d.ts +27 -0
  47. package/migrations/compare-migration-snapshots.js +164 -0
  48. package/migrations/generate-migrations.d.ts +21 -0
  49. package/migrations/generate-migrations.js +103 -0
  50. package/migrations/index.d.ts +3 -0
  51. package/migrations/index.js +7 -0
  52. package/migrations/migrate.d.ts +27 -0
  53. package/migrations/migrate.js +170 -0
  54. package/migrations/migration-types.d.ts +48 -0
  55. package/migrations/migration-types.js +88 -0
  56. package/migrations/update-migrations-ts-file.d.ts +1 -0
  57. package/migrations/update-migrations-ts-file.js +140 -0
  58. package/myLog.js +1 -2
  59. package/package.json +1 -1
  60. package/postgres/postgres-data-provider.js +4 -4
  61. package/postgres/schema-builder.js +3 -3
  62. package/remult-better-sqlite3.d.ts +12 -0
  63. package/remult-better-sqlite3.js +64 -0
  64. package/remult-bun-sqlite.d.ts +11 -0
  65. package/remult-bun-sqlite.js +56 -0
  66. package/remult-duckdb.d.ts +9 -0
  67. package/remult-duckdb.js +155 -0
  68. package/remult-express.js +1 -2
  69. package/remult-fastify.js +1 -2
  70. package/remult-fresh.js +1 -2
  71. package/remult-hapi.d.ts +6 -0
  72. package/remult-hapi.js +127 -0
  73. package/remult-hono.d.ts +7 -0
  74. package/remult-hono.js +115 -0
  75. package/remult-knex/index.js +3 -3
  76. package/remult-next.d.ts +0 -1
  77. package/remult-next.js +2 -3
  78. package/remult-nuxt.d.ts +6 -0
  79. package/remult-nuxt.js +78 -0
  80. package/remult-solid-start.d.ts +12 -0
  81. package/remult-solid-start.js +133 -0
  82. package/remult-sql-js.d.ts +5 -0
  83. package/remult-sql-js.js +73 -0
  84. package/remult-sqlite-core.d.ts +24 -0
  85. package/remult-sqlite-core.js +227 -0
  86. package/remult-sqlite3.d.ts +5 -0
  87. package/remult-sqlite3.js +76 -0
  88. package/remult-sveltekit.js +80 -83
  89. package/remult-turso.d.ts +8 -0
  90. package/remult-turso.js +100 -0
  91. package/server/expressBridge.js +2 -2
  92. package/server/get-remult-admin-html.d.ts +1 -0
  93. package/server/get-remult-admin-html.js +6 -0
  94. package/server/index.js +2 -2
  95. package/server/initAsyncHooks.js +1 -2
  96. package/server/initDataProvider.js +1 -2
  97. package/server/initDataProviderOrJson.d.ts +2 -0
  98. package/server/initDataProviderOrJson.js +16 -0
  99. package/server/remult-admin.d.ts +43 -0
  100. package/server/remult-admin.js +117 -0
  101. package/server/remult-api-server.d.ts +180 -0
  102. package/server/remult-api-server.js +1626 -0
  103. package/src/buildRestDataProvider.js +8 -8
  104. package/src/column-interfaces.js +1 -2
  105. package/src/column.js +2 -2
  106. package/src/context.js +4 -4
  107. package/src/data-api.js +3 -3
  108. package/src/data-interfaces.js +1 -2
  109. package/src/data-providers/array-entity-data-provider.js +7 -7
  110. package/src/data-providers/json-entity-opfs-storage.d.ts +5 -0
  111. package/src/data-providers/json-entity-opfs-storage.js +74 -0
  112. package/src/data-providers/rest-data-provider.js +4 -4
  113. package/src/data-providers/sql-database.js +9 -9
  114. package/src/filter/filter-consumer-bridge-to-sql-request.js +3 -3
  115. package/src/filter/filter-interfaces.js +4 -4
  116. package/src/isOfType.d.ts +2 -0
  117. package/src/isOfType.js +13 -0
  118. package/src/live-query/SubscriptionServer.js +95 -97
  119. package/src/remult-static.d.ts +26 -0
  120. package/src/remult-static.js +50 -0
  121. package/src/remult3/DecoratorReplacer.js +1 -2
  122. package/src/remult3/Fields.d.ts +73 -48
  123. package/src/remult3/Fields.js +195 -35
  124. package/src/remult3/IdEntity.d.ts +1 -1
  125. package/src/remult3/IdEntity.js +4 -4
  126. package/src/remult3/RepositoryImplementation.js +69 -71
  127. package/src/remult3/__updateEntityBasedOnWhere.js +1 -2
  128. package/src/remult3/addValidator.d.ts +2 -0
  129. package/src/remult3/addValidator.js +19 -0
  130. package/src/remult3/classDescribers.d.ts +16 -0
  131. package/src/remult3/classDescribers.js +40 -0
  132. package/src/remult3/columnInfo.d.ts +3 -3
  133. package/src/remult3/entity.js +1 -2
  134. package/src/remult3/getEntityRef.js +4 -4
  135. package/src/remult3/relation-loader-types.d.ts +2 -2
  136. package/src/remult3/relation-loader.d.ts +4 -4
  137. package/src/remult3/relation-loader.js +79 -53
  138. package/src/remult3/relationInfoMember.d.ts +29 -3
  139. package/src/remult3/relationInfoMember.js +145 -4
  140. package/src/remult3/repository-internals.d.ts +17 -11
  141. package/src/remult3/repository-internals.js +3 -3
  142. package/src/resultCompoundIdFilter.js +1 -2
  143. package/src/server-action.js +5 -5
  144. package/src/validators.js +14 -6
  145. package/src/valueConverters.js +1 -1
  146. package/esm/internals.d.ts +0 -7
  147. package/esm/src/remult3/Fields.d.ts +0 -145
  148. package/esm/src/remult3/IdEntity.d.ts +0 -4
  149. package/esm/src/remult3/columnInfo.d.ts +0 -6
  150. package/esm/src/remult3/relation-loader-types.d.ts +0 -7
  151. package/esm/src/remult3/relation-loader.d.ts +0 -40
  152. package/esm/src/remult3/relationInfoMember.d.ts +0 -4
  153. package/esm/src/remult3/repository-internals.d.ts +0 -14
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { GenericResponse } from './server/index';
3
2
  import type { Remult } from './src/context';
4
3
  import type { SubscriptionServer } from './src/live-query/SubscriptionServer';
@@ -19,7 +18,7 @@ export declare class clientConnection {
19
18
  close(): void;
20
19
  closed: boolean;
21
20
  write(eventData: string, eventType?: string): void;
22
- connectionId: any;
21
+ connectionId: string;
23
22
  constructor(response: GenericResponse & ResponseRequiredForSSE);
24
23
  sendLiveMessage(): void;
25
24
  }
package/assign.js CHANGED
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.assign = void 0;
3
+ exports.assign = assign;
4
4
  function assign(item, valuesToSet) {
5
5
  if (valuesToSet)
6
6
  Object.assign(item, valuesToSet);
7
7
  return item;
8
8
  }
9
- exports.assign = assign;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { GenericResponse } from './server/index';
3
2
  import type { Remult } from './src/context';
4
3
  import type { SubscriptionServer } from './src/live-query/SubscriptionServer';
@@ -19,7 +18,7 @@ export declare class clientConnection {
19
18
  close(): void;
20
19
  closed: boolean;
21
20
  write(eventData: string, eventType?: string): void;
22
- connectionId: any;
21
+ connectionId: string;
23
22
  constructor(response: GenericResponse & ResponseRequiredForSSE);
24
23
  sendLiveMessage(): void;
25
24
  }
package/esm/internals.js CHANGED
@@ -1,5 +1,7 @@
1
- export { getRelationInfo } from './src/remult3/relationInfoMember';
2
- export { decorateColumnSettings, controllerRefImpl, getControllerRef, } from './src/remult3/RepositoryImplementation';
3
- export { getEntitySettings } from './src/remult3/getEntityRef';
4
- export { __updateEntityBasedOnWhere } from './src/filter/filter-interfaces';
5
- export { actionInfo } from './src/server-action-info';
1
+ import { remultStatic } from './src/remult-static.js';
2
+ export { getRelationInfo, getRelationFieldInfo, } from './src/remult3/relationInfoMember.js';
3
+ export { decorateColumnSettings, controllerRefImpl, getControllerRef, } from './src/remult3/RepositoryImplementation.js';
4
+ export { getEntitySettings } from './src/remult3/getEntityRef.js';
5
+ export { __updateEntityBasedOnWhere } from './src/filter/filter-interfaces.js';
6
+ export const actionInfo = remultStatic.actionInfo;
7
+ export { flags } from './src/remult3/remult3.js';
@@ -0,0 +1,61 @@
1
+ import { repo } from '../index.js';
2
+ import { dbNamesOf, shouldCreateEntity, shouldNotCreateField, } from '../src/filter/filter-consumer-bridge-to-sql-request.js';
3
+ export async function compareMigrationSnapshot({ entities, snapshot, migrationBuilder, reporter, }) {
4
+ snapshot = JSON.parse(JSON.stringify(snapshot));
5
+ let processedEntities = new Set();
6
+ for (const entity of entities) {
7
+ const meta = repo(entity).metadata;
8
+ const e = await dbNamesOf(meta, (x) => x);
9
+ processedEntities.add(e.$entityName);
10
+ if (shouldCreateEntity(meta, e)) {
11
+ let entitySnapshot = snapshot.entities[e.$entityName];
12
+ let createColumns = true;
13
+ if (!entitySnapshot) {
14
+ createColumns = false;
15
+ reporter('create table ' + e.$entityName);
16
+ await migrationBuilder.createTable(meta);
17
+ entitySnapshot = snapshot.entities[e.$entityName] = {
18
+ key: meta.key,
19
+ className: meta.entityType.name,
20
+ columns: {},
21
+ };
22
+ }
23
+ const processedColumns = new Set();
24
+ for (const field of meta.fields) {
25
+ if (!shouldNotCreateField(field, e)) {
26
+ const columnDbName = e.$dbNameOf(field);
27
+ processedColumns.add(columnDbName);
28
+ const column = entitySnapshot.columns[columnDbName];
29
+ if (!column) {
30
+ if (createColumns) {
31
+ reporter('add column ' + e.$entityName + '.' + columnDbName);
32
+ await migrationBuilder.addColumn(meta, field);
33
+ }
34
+ entitySnapshot.columns[columnDbName] = { key: field.key };
35
+ }
36
+ }
37
+ }
38
+ for (const columnDbName of Object.keys(entitySnapshot.columns)) {
39
+ if (!processedColumns.has(columnDbName)) {
40
+ reporter('remove column ' + e.$entityName + '.' + columnDbName);
41
+ await migrationBuilder.removeColumn(e.$entityName, columnDbName);
42
+ delete entitySnapshot.columns[columnDbName];
43
+ }
44
+ }
45
+ }
46
+ }
47
+ for (const entityDbName of Object.keys(snapshot.entities)) {
48
+ if (!processedEntities.has(entityDbName)) {
49
+ reporter('remove table ' + entityDbName);
50
+ await migrationBuilder.removeTable(entityDbName);
51
+ delete snapshot.entities[entityDbName];
52
+ }
53
+ }
54
+ return snapshot;
55
+ }
56
+ export function emptySnapshot() {
57
+ return {
58
+ version: 1,
59
+ entities: {},
60
+ };
61
+ }
@@ -0,0 +1,68 @@
1
+ import path from 'path';
2
+ import fs from 'fs';
3
+ import { compareMigrationSnapshot, emptySnapshot, } from './compare-migration-snapshots.js';
4
+ import { updateMigrationsFile } from './update-migrations-ts-file.js';
5
+ import { DefaultMigrationBuilder, } from './migration-types.js';
6
+ import { isOfType } from '../src/isOfType.js';
7
+ import { initDataProviderOrJson } from '../server/initDataProviderOrJson.js';
8
+ /**
9
+ * Generates migration scripts based on changes in entities.
10
+ *
11
+ * @param options - Configuration options for generating migrations.
12
+ * @param options.entities - An array of entity classes whose changes will be included in the migration.
13
+ * @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
14
+ * @param options.migrationsFolder - (Optional) The path to the folder where migration scripts will be stored. Default is 'src/migrations'.
15
+ * @param options.snapshotFile - (Optional) The path to the file where the snapshot of the last known state will be stored. Default is 'migrations-snapshot.json' in the `migrationsFolder`.
16
+ * @param options.migrationsTSFile - (Optional) The path to the TypeScript file where the generated migrations will be written. Default is 'migrations.ts' in the `migrationsFolder`.
17
+ * @param options.endConnection - (Optional) Determines whether to close the database connection after generating migrations. Default is false.
18
+ * @see [Migrations](https://remult.dev/docs/migrations.html)
19
+ */
20
+ export async function generateMigrations(options) {
21
+ const migrationDir = options.migrationsFolder || path.join(process.cwd(), 'src/migrations');
22
+ const snapshotFileName = options.snapshotFile || path.join(migrationDir, 'migrations-snapshot.json');
23
+ const migrationsTSFilename = options.migrationsTSFile || path.join(migrationDir, 'migrations.ts');
24
+ const dataProvider = await initDataProviderOrJson(options.dataProvider);
25
+ for (const p of [snapshotFileName, migrationsTSFilename]) {
26
+ if (!fs.existsSync(path.dirname(p))) {
27
+ fs.mkdirSync(path.dirname(p), { recursive: true });
28
+ }
29
+ }
30
+ let snapshot = emptySnapshot();
31
+ if (fs.existsSync(snapshotFileName)) {
32
+ snapshot = JSON.parse(fs.readFileSync(snapshotFileName).toString());
33
+ }
34
+ let hasSql = false;
35
+ let steps = [];
36
+ const code = {
37
+ //https://marketplace.visualstudio.com/items?itemName=qufiwefefwoyn.inline-sql-syntax
38
+ addSql: (sql) => {
39
+ steps.push('await sql(`--sql\n' + sql + '`)');
40
+ hasSql = true;
41
+ },
42
+ addTypescriptCode: (code) => steps.push(code),
43
+ addComment: (comment) => steps.push(comment.indexOf('\n') >= 0 ? `/*${comment}*/` : `// ${comment}`),
44
+ };
45
+ let migrationBuilder = new DefaultMigrationBuilder(code);
46
+ if (isOfType(dataProvider, 'provideMigrationBuilder')) {
47
+ migrationBuilder = new DefaultMigrationBuilder(code, dataProvider.provideMigrationBuilder(code));
48
+ }
49
+ let reporter = (what) => console.log('[generateMigrations] ' + what);
50
+ snapshot = await compareMigrationSnapshot({
51
+ entities: options.entities,
52
+ snapshot,
53
+ reporter,
54
+ migrationBuilder,
55
+ });
56
+ if (steps.length)
57
+ await updateMigrationsFile(migrationsTSFilename, [
58
+ `async (${hasSql ? '{sql}' : ''})=>{\n${steps.join('\n')}\n}`,
59
+ ]);
60
+ else {
61
+ reporter('No changes detected');
62
+ }
63
+ fs.writeFileSync(snapshotFileName, JSON.stringify(snapshot, null, 2));
64
+ if (options.endConnection && isOfType(dataProvider, 'end')) {
65
+ await dataProvider.end();
66
+ }
67
+ return steps.length > 0;
68
+ }
@@ -0,0 +1,2 @@
1
+ export { generateMigrations } from './generate-migrations.js';
2
+ export { migrate } from './migrate.js';
@@ -0,0 +1,85 @@
1
+ import { Entity, IdEntity, Fields, remult, Remult, describeClass, } from '../index.js';
2
+ import { initDataProviderOrJson } from '../server/initDataProviderOrJson.js';
3
+ import { doTransaction } from '../src/context.js';
4
+ import { cast, isOfType } from '../src/isOfType.js';
5
+ /**
6
+ * Applies migration scripts to update the database schema.
7
+ *
8
+ * @param options - Configuration options for applying migrations.
9
+ * @param options.migrations - An object containing the migration scripts, each keyed by a unique identifier.
10
+ * @param options.dataProvider - The data provider instance or a function returning a promise of the data provider.
11
+ * @param options.migrationsTable - (Optional) The name of the table that tracks applied migrations. Default is '__remult_migrations_version'.
12
+ * @param options.endConnection - (Optional) Determines whether to close the database connection after applying migrations. Default is false.
13
+ * @param options.beforeMigration - (Optional) A callback function that is called before each migration is applied. Receives an object with the migration index.
14
+ * @param options.afterMigration - (Optional) A callback function that is called after each migration is applied. Receives an object with the migration index and the duration of the migration.
15
+ * @see [Migrations](https://remult.dev/docs/migrations.html)
16
+ */
17
+ export async function migrate(options) {
18
+ let migrationTableName = options.migrationsTable || '__remult_migrations_version';
19
+ const dataProvider = await initDataProviderOrJson(options.dataProvider);
20
+ const prev = remult.dataProvider;
21
+ remult.dataProvider = dataProvider;
22
+ try {
23
+ class VersionInfo extends IdEntity {
24
+ version = -1;
25
+ }
26
+ describeClass(VersionInfo, Entity(migrationTableName), {
27
+ version: Fields.integer(),
28
+ });
29
+ const steps = Object.entries(options.migrations).sort(([a], [b]) => parseInt(a) - parseInt(b));
30
+ if (dataProvider.ensureSchema) {
31
+ await dataProvider.ensureSchema([
32
+ new Remult(dataProvider).repo(VersionInfo).metadata,
33
+ ]);
34
+ }
35
+ await doTransaction(remult, async (dp) => {
36
+ const repo = new Remult(dataProvider).repo(VersionInfo, dp);
37
+ let v = await repo.findFirst();
38
+ if (!v) {
39
+ v = repo.create();
40
+ v.version = -1;
41
+ }
42
+ for (const [stepText, action] of steps) {
43
+ const step = parseInt(stepText);
44
+ if (step < 0)
45
+ throw new Error('Migration step number must be a non-negative integer');
46
+ if (v.version >= step)
47
+ continue;
48
+ if (options.beforeMigration) {
49
+ await options.beforeMigration({ index: step });
50
+ }
51
+ const startTime = Date.now();
52
+ console.info('Executing migration step ' + step);
53
+ console.time('Completed migration step ' + step);
54
+ try {
55
+ const utils = {
56
+ sql: async (sql) => {
57
+ return await cast(dp, 'execute').execute(sql);
58
+ },
59
+ };
60
+ await action(utils);
61
+ if (options.afterMigration) {
62
+ await options.afterMigration({
63
+ index: step,
64
+ duration: Date.now() - startTime,
65
+ });
66
+ }
67
+ console.timeEnd('Completed migration step ' + step);
68
+ }
69
+ catch (err) {
70
+ console.error('Failed to execute migration step ' + step);
71
+ console.error(err);
72
+ throw err;
73
+ }
74
+ v.version = step;
75
+ await v.save();
76
+ }
77
+ });
78
+ }
79
+ finally {
80
+ remult.dataProvider = prev;
81
+ }
82
+ if (options.endConnection && isOfType(dataProvider, 'end')) {
83
+ await dataProvider.end();
84
+ }
85
+ }
@@ -0,0 +1,36 @@
1
+ export class DefaultMigrationBuilder {
2
+ code;
3
+ wrapped;
4
+ constructor(code, wrapped) {
5
+ this.code = code;
6
+ this.wrapped = wrapped;
7
+ }
8
+ async createTable(meta) {
9
+ if (this.wrapped?.createTable) {
10
+ await this.wrapped.createTable(meta);
11
+ }
12
+ else
13
+ this.code.addComment('TODO: implement create table ' + meta.dbName);
14
+ }
15
+ async addColumn(meta, field) {
16
+ if (this.wrapped?.addColumn) {
17
+ await this.wrapped.addColumn(meta, field);
18
+ }
19
+ else
20
+ this.code.addComment('TODO: implement add column ' + meta.dbName + '.' + field.dbName);
21
+ }
22
+ async removeTable(entityDbName) {
23
+ if (this.wrapped?.removeTable) {
24
+ await this.wrapped.removeTable(entityDbName);
25
+ }
26
+ else
27
+ this.code.addComment('TODO: implement remove table ' + entityDbName);
28
+ }
29
+ async removeColumn(entityName, columnDbName) {
30
+ if (this.wrapped?.removeColumn) {
31
+ await this.wrapped.removeColumn(entityName, columnDbName);
32
+ }
33
+ else
34
+ this.code.addComment('TODO: implement remove column ' + entityName + '.' + columnDbName);
35
+ }
36
+ }
@@ -0,0 +1,115 @@
1
+ // consider replacing with https://www.npmjs.com/package/ts-morph
2
+ export async function updateMigrationsFile(filePath, steps) {
3
+ let ts = await import('typescript');
4
+ //@ts-ignore
5
+ if (ts.default)
6
+ ts = ts.default;
7
+ const fs = await import('fs');
8
+ let maxStep = -1;
9
+ function buildSteps() {
10
+ return steps.map((step) => ts.factory.createPropertyAssignment(ts.factory.createIdentifier((++maxStep).toString()), ts.factory.createIdentifier(step)));
11
+ }
12
+ if (!fs.existsSync(filePath)) {
13
+ fs.writeFileSync(filePath, '');
14
+ }
15
+ const importPath = 'remult/migrations';
16
+ const importName = 'Migrations';
17
+ // Load the file
18
+ const sourceFile = ts.createSourceFile(filePath, fs.readFileSync(filePath).toString(), ts.ScriptTarget.Latest, true);
19
+ let migrationsExportFound = false;
20
+ // Find the "migrations" named export and add the new member
21
+ let updatedSourceFile = ts.transform(sourceFile, [
22
+ (context) => {
23
+ return (node) => {
24
+ const visitor = (node) => {
25
+ if (ts.isVariableStatement(node) &&
26
+ node.declarationList.declarations.length > 0) {
27
+ const declaration = node.declarationList.declarations[0];
28
+ if (ts.isIdentifier(declaration.name) &&
29
+ declaration.name.text === 'migrations' &&
30
+ declaration.initializer &&
31
+ ts.isObjectLiteralExpression(declaration.initializer)) {
32
+ migrationsExportFound = true;
33
+ declaration.initializer.properties.forEach((property) => {
34
+ if (ts.isPropertyAssignment(property)) {
35
+ if (ts.isNumericLiteral(property.name)) {
36
+ const step = parseInt(property.name.text);
37
+ if (step > maxStep) {
38
+ maxStep = step;
39
+ }
40
+ }
41
+ }
42
+ });
43
+ let steps = buildSteps();
44
+ // Found the "migrations" array
45
+ // Update the initializer with the new steps
46
+ const updatedInitializer = ts.factory.updateObjectLiteralExpression(declaration.initializer, [...declaration.initializer.properties, ...steps]);
47
+ // Update the declaration with the new initializer
48
+ const updatedDeclaration = ts.factory.updateVariableDeclaration(declaration, declaration.name, undefined, declaration.type, // Preserve the original type annotation if present
49
+ updatedInitializer);
50
+ return ts.factory.updateVariableStatement(node, node.modifiers, ts.factory.updateVariableDeclarationList(node.declarationList, [
51
+ updatedDeclaration,
52
+ ]));
53
+ }
54
+ }
55
+ return ts.visitEachChild(node, visitor, context);
56
+ };
57
+ return ts.visitNode(node, visitor);
58
+ };
59
+ },
60
+ ]).transformed[0];
61
+ if (!migrationsExportFound) {
62
+ let importFound = false;
63
+ // Check if the import statement already exists
64
+ sourceFile.statements.forEach((statement) => {
65
+ if (ts.isImportDeclaration(statement) &&
66
+ ts.isStringLiteral(statement.moduleSpecifier) &&
67
+ statement.moduleSpecifier.text === `${importPath}`) {
68
+ statement.importClause?.namedBindings?.forEachChild((namedBinding) => {
69
+ if (ts.isImportSpecifier(namedBinding) &&
70
+ namedBinding.name.text === importName) {
71
+ importFound = true;
72
+ }
73
+ });
74
+ }
75
+ });
76
+ // If the import statement doesn't exist, create it
77
+ if (!importFound) {
78
+ updatedSourceFile = ts.factory.updateSourceFile(updatedSourceFile, [
79
+ ts.factory.createExpressionStatement(ts.factory.createIdentifier(`import type { ${importName} } from '${importPath}'`)),
80
+ ...updatedSourceFile.statements,
81
+ ]);
82
+ }
83
+ // Create a new export for migrations if it doesn't exist
84
+ const newMigrationsExport = ts.factory.createVariableStatement([ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
85
+ ts.factory.createVariableDeclaration('migrations', undefined, // You can add a type annotation here if needed
86
+ ts.factory.createTypeReferenceNode(importName, undefined), ts.factory.createObjectLiteralExpression(buildSteps(), false)),
87
+ ], ts.NodeFlags.Const));
88
+ // Add the new export to the end of the file
89
+ updatedSourceFile = ts.factory.updateSourceFile(updatedSourceFile, [
90
+ ...updatedSourceFile.statements,
91
+ newMigrationsExport,
92
+ ]);
93
+ }
94
+ let code = ts.createPrinter().printFile(updatedSourceFile);
95
+ try {
96
+ let prettier;
97
+ try {
98
+ prettier = await import('prettier' + '');
99
+ }
100
+ catch (err) {
101
+ console.warn('error importing prettier,for better formatting run `npm i -D prettier`. Writing raw code to file.');
102
+ }
103
+ if (prettier) {
104
+ let options = await prettier.resolveConfig();
105
+ code = await prettier.format(code, {
106
+ ...options,
107
+ parser: 'typescript',
108
+ });
109
+ }
110
+ }
111
+ catch (err) {
112
+ console.log('error formatting code, writing raw code to file.');
113
+ }
114
+ fs.writeFileSync(filePath, code);
115
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,47 @@
1
+ import { SqliteCoreDataProvider } from './remult-sqlite-core.js';
2
+ export class BetterSqlite3DataProvider extends SqliteCoreDataProvider {
3
+ constructor(db) {
4
+ super(() => new BetterSqlite3Command(db), async () => { db.close(); });
5
+ }
6
+ }
7
+ class BetterSqlite3Command {
8
+ db;
9
+ values = {};
10
+ i = 0;
11
+ constructor(db) {
12
+ this.db = db;
13
+ }
14
+ async execute(sql) {
15
+ const s = this.db.prepare(sql);
16
+ if (s.reader) {
17
+ return new BetterSqlite3SqlResult(s.all(this.values));
18
+ }
19
+ else {
20
+ const result = s.run(this.values);
21
+ return new BetterSqlite3SqlResult([]);
22
+ }
23
+ }
24
+ addParameterAndReturnSqlToken(val) {
25
+ return this.param(val);
26
+ }
27
+ param(val) {
28
+ if (val instanceof Date)
29
+ val = val.valueOf();
30
+ if (typeof val === "boolean")
31
+ val = val ? 1 : 0;
32
+ const key = ':' + (this.i++);
33
+ this.values[key.substring(1)] = (val);
34
+ return key;
35
+ }
36
+ }
37
+ export class BetterSqlite3SqlResult {
38
+ result;
39
+ constructor(result) {
40
+ this.result = result;
41
+ this.rows = result;
42
+ }
43
+ rows;
44
+ getColumnKeyInResultForIndexInSelect(index) {
45
+ return Object.keys(this.result[0])[index];
46
+ }
47
+ }
@@ -0,0 +1,41 @@
1
+ import { SqliteCoreDataProvider } from "./remult-sqlite-core.js";
2
+ export class BunSqliteDataProvider extends SqliteCoreDataProvider {
3
+ constructor(db) {
4
+ super(() => new BunSqliteCommand(db), async () => { db.close(); });
5
+ }
6
+ }
7
+ class BunSqliteCommand {
8
+ db;
9
+ values = {};
10
+ i = 0;
11
+ constructor(db) {
12
+ this.db = db;
13
+ }
14
+ async execute(sql) {
15
+ const s = this.db.query(sql);
16
+ return new BunSqliteSqlResult(s.all(this.values));
17
+ }
18
+ addParameterAndReturnSqlToken(val) {
19
+ return this.param(val);
20
+ }
21
+ param(val) {
22
+ if (val instanceof Date)
23
+ val = val.valueOf();
24
+ if (typeof val === "boolean")
25
+ val = val ? 1 : 0;
26
+ const key = ':' + (this.i++);
27
+ this.values[key] = (val);
28
+ return key;
29
+ }
30
+ }
31
+ class BunSqliteSqlResult {
32
+ result;
33
+ constructor(result) {
34
+ this.result = result;
35
+ this.rows = result;
36
+ }
37
+ rows;
38
+ getColumnKeyInResultForIndexInSelect(index) {
39
+ return Object.keys(this.result[0])[index];
40
+ }
41
+ }
@@ -0,0 +1,116 @@
1
+ import { SqliteCoreDataProvider } from './remult-sqlite-core.js';
2
+ import { ValueConverters, dbNamesOf, } from './index.js';
3
+ import { shouldNotCreateField } from './src/filter/filter-consumer-bridge-to-sql-request.js';
4
+ import { isAutoIncrement } from './src/remult3/RepositoryImplementation.js';
5
+ export class DuckDBDataProvider extends SqliteCoreDataProvider {
6
+ constructor(db) {
7
+ super(() => new DuckDBCommand(db), async () => (await db).close(), false, true);
8
+ }
9
+ wrapIdentifier(name) {
10
+ return `"${name}"`;
11
+ }
12
+ async getCreateTableSql(entity) {
13
+ let result = '';
14
+ let e = await dbNamesOf(entity, this.wrapIdentifier);
15
+ let sql = '';
16
+ for (const x of entity.fields) {
17
+ if (!shouldNotCreateField(x, e) || isAutoIncrement(x)) {
18
+ if (result.length != 0)
19
+ result += ',';
20
+ result += '\r\n ';
21
+ if (isAutoIncrement(x)) {
22
+ const sequenceName = `${entity.dbName}_${x.dbName}_seq`;
23
+ sql += `create sequence if not exists "${sequenceName}";\r\n`;
24
+ result += `${e.$dbNameOf(x)} integer default nextval('${sequenceName}')`;
25
+ }
26
+ else {
27
+ result += this.addColumnSqlSyntax(x, e.$dbNameOf(x), false);
28
+ }
29
+ }
30
+ }
31
+ result += `,\r\n primary key (${entity.idMetadata.fields
32
+ .map((f) => e.$dbNameOf(f))
33
+ .join(',')})`;
34
+ sql +=
35
+ 'create table if not exists ' + e.$entityName + ' (' + result + '\r\n)';
36
+ return sql;
37
+ }
38
+ addColumnSqlSyntax(x, dbName, isAlterColumn) {
39
+ let result = dbName;
40
+ var allowNull = x.allowNull;
41
+ if (allowNull && isAlterColumn) {
42
+ allowNull = false;
43
+ console.log('DuckDB does not support altering columns to allow null on existing tables');
44
+ }
45
+ if (x.valueType == Number) {
46
+ if (!x.valueConverter.fieldTypeInDb)
47
+ result += ' numeric' + (allowNull ? '' : ' default 0 not null');
48
+ else
49
+ result +=
50
+ ' ' +
51
+ x.valueConverter.fieldTypeInDb +
52
+ (x.allowNull || isAlterColumn ? '' : ' default 0 not null');
53
+ }
54
+ else if (x.valueType == Date) {
55
+ if (!x.valueConverter.fieldTypeInDb)
56
+ if (x.valueConverter == ValueConverters.DateOnly)
57
+ result += ' date';
58
+ else
59
+ result += ' timestamp';
60
+ else
61
+ result += ' ' + x.valueConverter.fieldTypeInDb;
62
+ }
63
+ else if (x.valueType == Boolean)
64
+ result +=
65
+ ' boolean' +
66
+ (x.allowNull || isAlterColumn ? '' : ' default false not null');
67
+ else if (x.valueConverter.fieldTypeInDb) {
68
+ result += ' ' + x.valueConverter.fieldTypeInDb;
69
+ if (!(x.allowNull || isAlterColumn) &&
70
+ x.valueConverter.fieldTypeInDb == 'integer') {
71
+ result += ' default 0 not null';
72
+ }
73
+ }
74
+ else
75
+ result +=
76
+ ' varchar' +
77
+ (x.allowNull || isAlterColumn ? '' : " default '' not null");
78
+ return result;
79
+ }
80
+ }
81
+ class DuckDBCommand {
82
+ db;
83
+ values = [];
84
+ constructor(db) {
85
+ this.db = db;
86
+ }
87
+ async execute(sql) {
88
+ return new Promise((resolve, error) => {
89
+ this.db.all(sql, ...this.values, (err, rows) => {
90
+ if (err)
91
+ error(err);
92
+ else
93
+ resolve(new DuckDBSqlResult(rows));
94
+ });
95
+ });
96
+ }
97
+ addParameterAndReturnSqlToken(val) {
98
+ return this.param(val);
99
+ }
100
+ param(val) {
101
+ const key = '?';
102
+ this.values.push(val);
103
+ return key;
104
+ }
105
+ }
106
+ class DuckDBSqlResult {
107
+ result;
108
+ constructor(result) {
109
+ this.result = result;
110
+ this.rows = result;
111
+ }
112
+ rows;
113
+ getColumnKeyInResultForIndexInSelect(index) {
114
+ return Object.keys(this.result[0])[index];
115
+ }
116
+ }