remult 0.22.6-exp.1 → 0.22.6-exp.3

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 (105) hide show
  1. package/async-hooks.d.ts +26 -0
  2. package/async-hooks.js +34 -0
  3. package/esm/async-hooks.js +31 -0
  4. package/esm/internals.js +3 -1
  5. package/esm/migrations/generate-migrations.js +5 -1
  6. package/esm/remult-d1-http.js +32 -0
  7. package/esm/remult-d1.js +90 -0
  8. package/esm/remult-duckdb.js +82 -38
  9. package/esm/remult-hapi.js +11 -8
  10. package/esm/remult-hono.js +19 -15
  11. package/esm/remult-nuxt.js +11 -6
  12. package/esm/remult-solid-start.js +12 -7
  13. package/esm/remult-sqlite-core.js +33 -5
  14. package/esm/remult-sqlite3.js +5 -0
  15. package/esm/server/get-remult-admin-html.js +1 -1
  16. package/esm/server/module.js +38 -0
  17. package/esm/server/remult-admin.js +91 -60
  18. package/esm/server/remult-api-server.js +124 -50
  19. package/esm/server/test-api-data-provider.js +107 -0
  20. package/esm/src/CompoundIdField.js +1 -0
  21. package/esm/src/data-api.js +4 -2
  22. package/esm/src/data-providers/json-entity-indexed-db-data-provider.js +64 -0
  23. package/esm/src/data-providers/rest-data-provider-using-fetch.js +78 -0
  24. package/esm/src/data-providers/retry.js +25 -0
  25. package/esm/src/data-providers/sql-relations.js +125 -0
  26. package/esm/src/filter/entityDbName.js +18 -0
  27. package/esm/src/filter/fieldDbName.js +40 -0
  28. package/esm/src/remult-static.js +3 -1
  29. package/esm/src/remult3/Fields.js +84 -34
  30. package/esm/src/remult3/IdEntity.js +1 -1
  31. package/esm/src/remult3/QueryResultImpl.js +147 -0
  32. package/esm/src/remult3/SubscribableImp.js +26 -0
  33. package/esm/src/remult3/entity.js +11 -7
  34. package/esm/src/remult3/getEntityRef.js +2 -0
  35. package/esm/src/remult3/relationInfoMember.js +4 -2
  36. package/esm/src/server-action.d.ts +7 -0
  37. package/esm/src/server-action.js +8 -2
  38. package/esm/src/standard-schema/StandardSchemaV1.js +1 -0
  39. package/esm/src/standard-schema/index.js +74 -0
  40. package/internals.d.ts +5 -3
  41. package/internals.js +7 -1
  42. package/migrations/generate-migrations.js +5 -1
  43. package/package.json +1 -1
  44. package/remult-d1-http.d.ts +16 -0
  45. package/remult-d1-http.js +46 -0
  46. package/remult-d1.d.ts +27 -0
  47. package/remult-d1.js +128 -0
  48. package/remult-duckdb.d.ts +4 -3
  49. package/remult-duckdb.js +87 -42
  50. package/remult-hapi.d.ts +3 -1
  51. package/remult-hapi.js +10 -10
  52. package/remult-hono.d.ts +3 -1
  53. package/remult-hono.js +21 -16
  54. package/remult-nuxt.d.ts +3 -1
  55. package/remult-nuxt.js +13 -7
  56. package/remult-solid-start.d.ts +3 -1
  57. package/remult-solid-start.js +14 -8
  58. package/remult-sqlite-core.d.ts +2 -1
  59. package/remult-sqlite-core.js +116 -29
  60. package/remult-sqlite3.d.ts +2 -0
  61. package/remult-sqlite3.js +16 -0
  62. package/server/get-remult-admin-html.js +1 -1
  63. package/server/initDataProviderOrJson.d.ts +1 -1
  64. package/server/module.d.ts +26 -0
  65. package/server/module.js +40 -0
  66. package/server/remult-admin.d.ts +15 -5
  67. package/server/remult-admin.js +77 -44
  68. package/server/remult-api-server.d.ts +43 -5
  69. package/server/remult-api-server.js +163 -69
  70. package/server/test-api-data-provider.d.ts +9 -0
  71. package/server/test-api-data-provider.js +174 -0
  72. package/src/CompoundIdField.d.ts +1 -0
  73. package/src/CompoundIdField.js +1 -0
  74. package/src/data-api.js +4 -2
  75. package/src/data-providers/json-entity-indexed-db-data-provider.d.ts +10 -0
  76. package/src/data-providers/json-entity-indexed-db-data-provider.js +119 -0
  77. package/src/data-providers/rest-data-provider-using-fetch.d.ts +13 -0
  78. package/src/data-providers/rest-data-provider-using-fetch.js +119 -0
  79. package/src/data-providers/retry.d.ts +1 -0
  80. package/src/data-providers/retry.js +44 -0
  81. package/src/data-providers/sql-relations.d.ts +40 -0
  82. package/src/data-providers/sql-relations.js +167 -0
  83. package/src/filter/entityDbName.d.ts +2 -0
  84. package/src/filter/entityDbName.js +32 -0
  85. package/src/filter/fieldDbName.d.ts +3 -0
  86. package/src/filter/fieldDbName.js +58 -0
  87. package/src/remult-static.d.ts +3 -1
  88. package/src/remult-static.js +3 -1
  89. package/src/remult3/Fields.d.ts +57 -5
  90. package/src/remult3/Fields.js +86 -44
  91. package/src/remult3/IdEntity.js +1 -1
  92. package/src/remult3/QueryResultImpl.d.ts +16 -0
  93. package/src/remult3/QueryResultImpl.js +268 -0
  94. package/src/remult3/SubscribableImp.d.ts +11 -0
  95. package/src/remult3/SubscribableImp.js +35 -0
  96. package/src/remult3/entity.d.ts +1 -1
  97. package/src/remult3/entity.js +11 -7
  98. package/src/remult3/getEntityRef.js +2 -0
  99. package/src/remult3/relationInfoMember.js +4 -2
  100. package/src/server-action.d.ts +7 -0
  101. package/src/server-action.js +19 -2
  102. package/src/standard-schema/StandardSchemaV1.d.ts +56 -0
  103. package/src/standard-schema/StandardSchemaV1.js +2 -0
  104. package/src/standard-schema/index.d.ts +22 -0
  105. package/src/standard-schema/index.js +110 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Initializes and enables async context tracking for the server.
3
+ *
4
+ * This should be called before handling any incoming requests or calling `withRemult()`.
5
+ * @example
6
+ * import { remult, repo, withRemult } from 'remult';
7
+ * import { initAsyncHooks } from 'remult/async-hooks';
8
+ *
9
+ * import { Task } from './entities/Task.js';
10
+ *
11
+ * initAsyncHooks();
12
+ *
13
+ * // Thx to the `initAsyncHooks` above,
14
+ * // we have isolated async contexts with multiple `withRemult()`,
15
+ * // without needing to initialize a `remultApi` all the time!
16
+ * withRemult(async () => {
17
+ * remult.user = { id: '42' };
18
+ * repo(Task).find()
19
+ * });
20
+ *
21
+ * withRemult(async () => {
22
+ * remult.user = { id: '21' };
23
+ * repo(Task).find()
24
+ * });
25
+ */
26
+ export declare function initAsyncHooks(): void;
package/async-hooks.js ADDED
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initAsyncHooks = initAsyncHooks;
4
+ var context_js_1 = require("./src/context.js");
5
+ var initAsyncHooks_js_1 = require("./server/initAsyncHooks.js");
6
+ /**
7
+ * Initializes and enables async context tracking for the server.
8
+ *
9
+ * This should be called before handling any incoming requests or calling `withRemult()`.
10
+ * @example
11
+ * import { remult, repo, withRemult } from 'remult';
12
+ * import { initAsyncHooks } from 'remult/async-hooks';
13
+ *
14
+ * import { Task } from './entities/Task.js';
15
+ *
16
+ * initAsyncHooks();
17
+ *
18
+ * // Thx to the `initAsyncHooks` above,
19
+ * // we have isolated async contexts with multiple `withRemult()`,
20
+ * // without needing to initialize a `remultApi` all the time!
21
+ * withRemult(async () => {
22
+ * remult.user = { id: '42' };
23
+ * repo(Task).find()
24
+ * });
25
+ *
26
+ * withRemult(async () => {
27
+ * remult.user = { id: '21' };
28
+ * repo(Task).find()
29
+ * });
30
+ */
31
+ function initAsyncHooks() {
32
+ (0, initAsyncHooks_js_1.initAsyncHooks)();
33
+ context_js_1.RemultAsyncLocalStorage.enable();
34
+ }
@@ -0,0 +1,31 @@
1
+ import { RemultAsyncLocalStorage } from './src/context.js';
2
+ import { initAsyncHooks as _initAsyncHooks } from './server/initAsyncHooks.js';
3
+ /**
4
+ * Initializes and enables async context tracking for the server.
5
+ *
6
+ * This should be called before handling any incoming requests or calling `withRemult()`.
7
+ * @example
8
+ * import { remult, repo, withRemult } from 'remult';
9
+ * import { initAsyncHooks } from 'remult/async-hooks';
10
+ *
11
+ * import { Task } from './entities/Task.js';
12
+ *
13
+ * initAsyncHooks();
14
+ *
15
+ * // Thx to the `initAsyncHooks` above,
16
+ * // we have isolated async contexts with multiple `withRemult()`,
17
+ * // without needing to initialize a `remultApi` all the time!
18
+ * withRemult(async () => {
19
+ * remult.user = { id: '42' };
20
+ * repo(Task).find()
21
+ * });
22
+ *
23
+ * withRemult(async () => {
24
+ * remult.user = { id: '21' };
25
+ * repo(Task).find()
26
+ * });
27
+ */
28
+ export function initAsyncHooks() {
29
+ _initAsyncHooks();
30
+ RemultAsyncLocalStorage.enable();
31
+ }
package/esm/internals.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { remultStatic } from './src/remult-static.js';
2
+ export { sqlRelations, sqlRelationsFilter, } from './src/data-providers/sql-relations.js';
2
3
  export { getRelationInfo, getRelationFieldInfo, } from './src/remult3/relationInfoMember.js';
3
- export { decorateColumnSettings, controllerRefImpl, getControllerRef, } from './src/remult3/RepositoryImplementation.js';
4
+ export { decorateColumnSettings, controllerRefImpl, getControllerRef, fieldOptionsEnricher, } from './src/remult3/RepositoryImplementation.js';
4
5
  export { getEntitySettings } from './src/remult3/getEntityRef.js';
5
6
  export { __updateEntityBasedOnWhere } from './src/filter/filter-interfaces.js';
6
7
  export const actionInfo = remultStatic.actionInfo;
8
+ export { isOfType } from './src/isOfType.js';
7
9
  export { flags } from './src/remult3/remult3.js';
@@ -36,7 +36,7 @@ export async function generateMigrations(options) {
36
36
  const code = {
37
37
  //https://marketplace.visualstudio.com/items?itemName=qufiwefefwoyn.inline-sql-syntax
38
38
  addSql: (sql) => {
39
- steps.push('await sql(`--sql\n' + sql + '`)');
39
+ steps.push('await sql(`--sql\n' + escapeForTpl(sql) + '`)');
40
40
  hasSql = true;
41
41
  },
42
42
  addTypescriptCode: (code) => steps.push(code),
@@ -66,3 +66,7 @@ export async function generateMigrations(options) {
66
66
  }
67
67
  return steps.length > 0;
68
68
  }
69
+ function escapeForTpl(str) {
70
+ // escape backticks, dollar-signs and backslashes
71
+ return str.replace(/[`\\$]/g, (m) => "\\" + m);
72
+ }
@@ -0,0 +1,32 @@
1
+ import Cloudflare from 'cloudflare';
2
+ import { SqlDatabase } from './index.js';
3
+ import { D1DataProvider } from './remult-d1.js';
4
+ export { D1DataProvider };
5
+ export function createD1HttpDataProvider(creds) {
6
+ return new SqlDatabase(new D1DataProvider(new D1HttpClient(creds)));
7
+ }
8
+ export class D1HttpClient {
9
+ d1;
10
+ accountId;
11
+ databaseId;
12
+ constructor({ accountId, databaseId, apiToken }) {
13
+ this.d1 = new Cloudflare({ apiToken }).d1.database;
14
+ this.accountId = accountId;
15
+ this.databaseId = databaseId;
16
+ }
17
+ async execute(sql, params = []) {
18
+ return this.d1
19
+ .query(this.databaseId, {
20
+ sql,
21
+ params: params,
22
+ account_id: this.accountId,
23
+ })
24
+ .then(({ result: pages }) => pages.flatMap((page) => page.results));
25
+ // NOTE: d1 query endpoint returns the result as array of object with keys as column names.
26
+ // We're returning that now because the rest of remult seems to expect that.
27
+ // D1 also has a more efficient raw() endpoint that returns {columns: string[], rows: any[][]} that we may want
28
+ // to use eventually, and write code like fromRowToSql()
29
+ // at https://github.com/tursodatabase/libsql-client-ts/blob/main/packages/libsql-client/src/sqlite3.ts#L398
30
+ // to adapt the data
31
+ }
32
+ }
@@ -0,0 +1,90 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ import { SqlDatabase, } from './index.js';
3
+ import { SqliteCoreDataProvider } from './remult-sqlite-core.js';
4
+ export function createD1DataProvider(d1) {
5
+ return new SqlDatabase(new D1DataProvider(new D1BindingClient(d1)));
6
+ }
7
+ export class D1DataProvider extends SqliteCoreDataProvider {
8
+ d1;
9
+ /**
10
+ * For production or local d1 using binding
11
+ *
12
+ * const dataProvider = new SqlDatabase(new D1DataProvider(new D1BindingClient(d1)))
13
+ */
14
+ constructor(d1) {
15
+ super(() => new D1Command(this.d1), async () => {
16
+ // afaik: d1 connection doesn't need closing,
17
+ // so this is just a noop
18
+ });
19
+ this.d1 = d1;
20
+ }
21
+ async transaction(action) {
22
+ // As of June 2025, D1 doesn't support transactions
23
+ // Here we simply run the action without wrapping it in a transaction
24
+ // It means queries in action() will be run individually (this is the same decision prisma made)
25
+ await action(this);
26
+ }
27
+ }
28
+ export class D1BindingClient {
29
+ d1;
30
+ /**
31
+ * Simple d1 client that wraps the d1 binding directly
32
+ *
33
+ * const d1 = new D1BindingClient(env.DB)
34
+ */
35
+ constructor(d1) {
36
+ this.d1 = d1;
37
+ }
38
+ async execute(sql, params = []) {
39
+ // https://developers.cloudflare.com/d1/worker-api/d1-database/
40
+ // https://developers.cloudflare.com/d1/worker-api/prepared-statements/
41
+ //
42
+ // Note: see if we should eventually take advantage of the raw() end point too.
43
+ const { results } = await this.d1
44
+ .prepare(sql)
45
+ .bind(...params)
46
+ .run();
47
+ return results;
48
+ }
49
+ }
50
+ class D1Command {
51
+ d1;
52
+ params = [];
53
+ constructor(d1) {
54
+ this.d1 = d1;
55
+ }
56
+ async execute(sql) {
57
+ const results = await this.d1.execute(sql, this.params);
58
+ return new D1SqlResult(results);
59
+ }
60
+ /** @deprecated use `param` instead*/
61
+ addParameterAndReturnSqlToken(val) {
62
+ return this.param(val);
63
+ }
64
+ param(val) {
65
+ let p;
66
+ if (val instanceof Date)
67
+ p = val.valueOf();
68
+ else if (typeof val === 'boolean')
69
+ p = val ? 1 : 0;
70
+ else
71
+ p = val;
72
+ this.params.push(p);
73
+ // According to https://developers.cloudflare.com/d1/worker-api/prepared-statements/
74
+ // only the ordered "?NNN" and anonymous "?" param types are supported (although :AAAA seems to work too)
75
+ const key = `?${this.params.length}`;
76
+ return key;
77
+ }
78
+ }
79
+ class D1SqlResult {
80
+ rows;
81
+ columns;
82
+ constructor(rows = []) {
83
+ this.rows = rows;
84
+ // NOTE: are we guaranteed that when this is reached, rows is not empty?
85
+ this.columns = rows.length === 0 ? [] : Object.keys(rows[0]);
86
+ }
87
+ getColumnKeyInResultForIndexInSelect(index) {
88
+ return this.columns[index];
89
+ }
90
+ }
@@ -1,10 +1,13 @@
1
+ import { DuckDBTypeId } from '@duckdb/node-api';
1
2
  import { SqliteCoreDataProvider } from './remult-sqlite-core.js';
2
3
  import { ValueConverters, dbNamesOf, } from './index.js';
3
4
  import { shouldNotCreateField } from './src/filter/filter-consumer-bridge-to-sql-request.js';
4
5
  import { isAutoIncrement } from './src/remult3/RepositoryImplementation.js';
5
6
  export class DuckDBDataProvider extends SqliteCoreDataProvider {
6
- constructor(db) {
7
- super(() => new DuckDBCommand(db), async () => (await db).close(), false, true);
7
+ connection;
8
+ constructor(connection) {
9
+ super(() => new DuckDBCommand(this.connection), async () => this.connection.disconnectSync(), false, true);
10
+ this.connection = connection;
8
11
  }
9
12
  wrapIdentifier(name) {
10
13
  return `"${name}"`;
@@ -12,7 +15,8 @@ export class DuckDBDataProvider extends SqliteCoreDataProvider {
12
15
  async getCreateTableSql(entity) {
13
16
  let result = '';
14
17
  let e = await dbNamesOf(entity, this.wrapIdentifier);
15
- let sql = '';
18
+ const createSequenceStatements = [];
19
+ let createTableSql = '';
16
20
  for (const x of entity.fields) {
17
21
  if (!shouldNotCreateField(x, e) || isAutoIncrement(x)) {
18
22
  if (result.length != 0)
@@ -20,7 +24,7 @@ export class DuckDBDataProvider extends SqliteCoreDataProvider {
20
24
  result += '\r\n ';
21
25
  if (isAutoIncrement(x)) {
22
26
  const sequenceName = `${entity.dbName}_${x.dbName}_seq`;
23
- sql += `create sequence if not exists "${sequenceName}";\r\n`;
27
+ createSequenceStatements.push(`create sequence if not exists "${sequenceName}";`);
24
28
  result += `${e.$dbNameOf(x)} integer default nextval('${sequenceName}')`;
25
29
  }
26
30
  else {
@@ -31,15 +35,15 @@ export class DuckDBDataProvider extends SqliteCoreDataProvider {
31
35
  result += `,\r\n primary key (${entity.idMetadata.fields
32
36
  .map((f) => e.$dbNameOf(f))
33
37
  .join(',')})`;
34
- sql +=
38
+ createTableSql =
35
39
  'create table if not exists ' + e.$entityName + ' (' + result + '\r\n)';
36
- return sql;
40
+ return [...createSequenceStatements, createTableSql];
37
41
  }
38
42
  addColumnSqlSyntax(x, dbName, isAlterColumn) {
39
43
  let result = dbName;
40
44
  var allowNull = x.allowNull;
41
- if (allowNull && isAlterColumn) {
42
- allowNull = false;
45
+ if (!allowNull && isAlterColumn) {
46
+ allowNull = true;
43
47
  console.log('DuckDB does not support altering columns to allow null on existing tables');
44
48
  }
45
49
  if (x.valueType == Number) {
@@ -49,7 +53,7 @@ export class DuckDBDataProvider extends SqliteCoreDataProvider {
49
53
  result +=
50
54
  ' ' +
51
55
  x.valueConverter.fieldTypeInDb +
52
- (x.allowNull || isAlterColumn ? '' : ' default 0 not null');
56
+ (allowNull ? '' : ' default 0 not null');
53
57
  }
54
58
  else if (x.valueType == Date) {
55
59
  if (!x.valueConverter.fieldTypeInDb)
@@ -61,56 +65,96 @@ export class DuckDBDataProvider extends SqliteCoreDataProvider {
61
65
  result += ' ' + x.valueConverter.fieldTypeInDb;
62
66
  }
63
67
  else if (x.valueType == Boolean)
64
- result +=
65
- ' boolean' +
66
- (x.allowNull || isAlterColumn ? '' : ' default false not null');
68
+ result += ' boolean' + (allowNull ? '' : ' default false not null');
67
69
  else if (x.valueConverter.fieldTypeInDb) {
68
70
  result += ' ' + x.valueConverter.fieldTypeInDb;
69
- if (!(x.allowNull || isAlterColumn) &&
70
- x.valueConverter.fieldTypeInDb == 'integer') {
71
+ if (!allowNull && x.valueConverter.fieldTypeInDb == 'integer') {
71
72
  result += ' default 0 not null';
72
73
  }
73
74
  }
74
75
  else
75
- result +=
76
- ' varchar' +
77
- (x.allowNull || isAlterColumn ? '' : " default '' not null");
76
+ result += ' varchar' + (allowNull ? '' : " default '' not null");
78
77
  return result;
79
78
  }
80
79
  }
81
80
  class DuckDBCommand {
82
- db;
81
+ connection;
83
82
  values = [];
84
- constructor(db) {
85
- this.db = db;
83
+ constructor(connection) {
84
+ this.connection = connection;
86
85
  }
87
86
  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
- });
87
+ try {
88
+ const result = await this.connection.run(sql, this.values);
89
+ this.values = [];
90
+ return new DuckDBSqlResult(result);
91
+ }
92
+ catch (err) {
93
+ this.values = [];
94
+ throw err;
95
+ }
96
+ }
97
+ addParamInternal(val) {
98
+ if (val === undefined) {
99
+ this.values.push(null);
100
+ }
101
+ else if (val instanceof Date) {
102
+ this.values.push(val.toISOString());
103
+ }
104
+ else {
105
+ this.values.push(val);
106
+ }
107
+ return '?';
96
108
  }
97
109
  addParameterAndReturnSqlToken(val) {
98
- return this.param(val);
110
+ return this.addParamInternal(val);
99
111
  }
100
112
  param(val) {
101
- const key = '?';
102
- this.values.push(val);
103
- return key;
113
+ return this.addParamInternal(val);
104
114
  }
105
115
  }
106
116
  class DuckDBSqlResult {
107
- result;
108
- constructor(result) {
109
- this.result = result;
110
- this.rows = result;
111
- }
117
+ duckDbResult;
112
118
  rows;
119
+ constructor(duckDbResult) {
120
+ this.duckDbResult = duckDbResult;
121
+ this.rows = [];
122
+ const columnNames = this.duckDbResult.columnNames();
123
+ const columnTypes = this.duckDbResult.columnTypes();
124
+ const chunkCount = this.duckDbResult.chunkCount;
125
+ for (let i = 0; i < chunkCount; i++) {
126
+ const chunk = this.duckDbResult.getChunk(i);
127
+ const chunkRowObjects = chunk.getRowObjects(columnNames).map((row) => {
128
+ const convertedRow = {};
129
+ columnNames.forEach((colName, colIndex) => {
130
+ const value = row[colName];
131
+ if (value === null) {
132
+ convertedRow[colName] = null;
133
+ }
134
+ else {
135
+ const colType = columnTypes[colIndex];
136
+ const typeId = colType.typeId;
137
+ if (typeId === DuckDBTypeId.TIMESTAMP) {
138
+ const timestampValue = value;
139
+ const parts = timestampValue.toParts();
140
+ convertedRow[colName] = new Date(Date.UTC(parts.date.year, parts.date.month - 1, parts.date.day, parts.time.hour, parts.time.min, parts.time.sec, Math.floor(parts.time.micros / 1000)));
141
+ }
142
+ else if (typeId === DuckDBTypeId.DATE) {
143
+ const dateValue = value;
144
+ const parts = dateValue.toParts();
145
+ convertedRow[colName] = new Date(Date.UTC(parts.year, parts.month - 1, parts.day));
146
+ }
147
+ else {
148
+ convertedRow[colName] = value;
149
+ }
150
+ }
151
+ });
152
+ return convertedRow;
153
+ });
154
+ this.rows.push(...chunkRowObjects);
155
+ }
156
+ }
113
157
  getColumnKeyInResultForIndexInSelect(index) {
114
- return Object.keys(this.result[0])[index];
158
+ return this.duckDbResult.columnName(index);
115
159
  }
116
160
  }
@@ -1,15 +1,16 @@
1
1
  import { createRemultServer, } from './server/index.js';
2
2
  import { PassThrough } from 'stream';
3
- export function remultHapi(options) {
3
+ export function remultApi(options) {
4
4
  const api = createRemultServer(options, {
5
5
  buildGenericRequestInfo: (req) => ({
6
- method: req.method,
7
- params: req.params,
8
- query: req.query,
9
- url: req.url.pathname,
10
- on: (e, do1) => {
11
- req.raw.req.on('close', do1);
6
+ internal: {
7
+ ...req,
8
+ url: req.url.pathname,
9
+ on: (e, do1) => {
10
+ req.raw.req.on('close', do1);
11
+ },
12
12
  },
13
+ public: { headers: new Headers(req.headers) },
13
14
  }),
14
15
  getRequestBody: async (req) => req.payload,
15
16
  });
@@ -33,7 +34,7 @@ export function remultHapi(options) {
33
34
  res(h.response(html).code(status));
34
35
  },
35
36
  json(data) {
36
- res(h.response(data).code(status));
37
+ res(h.response(data === null ? 'null' : data).code(status));
37
38
  },
38
39
  write(data) {
39
40
  stream.write(data);
@@ -112,3 +113,5 @@ export function remultHapi(options) {
112
113
  withRemult: (req, what) => api.withRemultAsync(req, what),
113
114
  });
114
115
  }
116
+ /** @deprecated use remultApi instead */
117
+ export const remultHapi = remultApi;
@@ -1,27 +1,29 @@
1
1
  import { Hono } from 'hono';
2
2
  import { streamSSE } from 'hono/streaming';
3
3
  import { createRemultServer, } from './server/index.js';
4
- export function remultHono(options) {
4
+ export function remultApi(options) {
5
5
  let app = new Hono();
6
6
  const api = createRemultServer(options, {
7
7
  buildGenericRequestInfo: (c) => {
8
8
  return {
9
- method: c.req.method,
10
- params: c.req.param(),
11
- query: new Proxy(c.req, {
12
- get: (target, prop) => {
13
- const r = c.req.queries(prop);
14
- if (r?.length == 1)
15
- return r[0];
16
- return r;
9
+ internal: {
10
+ method: c.req.method,
11
+ params: c.req.param(),
12
+ query: new Proxy(c.req, {
13
+ get: (target, prop) => {
14
+ const r = c.req.queries(prop);
15
+ if (r?.length == 1)
16
+ return r[0];
17
+ return r;
18
+ },
19
+ }),
20
+ url: c.req.url,
21
+ on: (e, do1) => {
22
+ ;
23
+ c['_tempOnClose'](() => do1());
17
24
  },
18
- }),
19
- url: c.req.url,
20
- on: (e, do1) => {
21
- ;
22
- c['_tempOnClose'](() => do1());
23
- // c.req.on('close', do1)
24
25
  },
26
+ public: { headers: new Headers(c.req.header()) },
25
27
  };
26
28
  },
27
29
  getRequestBody: async (c) => {
@@ -102,3 +104,5 @@ export function remultHono(options) {
102
104
  withRemult: async (c, what) => api.withRemultAsync(c, what),
103
105
  });
104
106
  }
107
+ /** @deprecated use remultApi instead */
108
+ export const remultHono = remultApi;
@@ -1,16 +1,19 @@
1
1
  import { readBody, setResponseStatus } from 'h3';
2
2
  import { createRemultServer } from './server/index.js';
3
- export function remultNuxt(options) {
3
+ export function remultApi(options) {
4
4
  const result = createRemultServer(options, {
5
- buildGenericRequestInfo: (event) => {
6
- return {
5
+ buildGenericRequestInfo: (event) => ({
6
+ internal: {
7
7
  method: event.node.req.method,
8
8
  url: event.node.req.url,
9
9
  on: (a, b) => event.node.req.on('close', () => {
10
10
  b();
11
11
  }),
12
- };
13
- },
12
+ },
13
+ public: {
14
+ headers: new Headers(event.node.req.headers),
15
+ },
16
+ }),
14
17
  getRequestBody: async (event) => await readBody(event),
15
18
  });
16
19
  const handler = async (event) => {
@@ -41,7 +44,7 @@ export function remultNuxt(options) {
41
44
  setResponseStatus(event, r.statusCode);
42
45
  if (r.html)
43
46
  return r.html;
44
- return r.data;
47
+ return r.data == null ? 'null' : r.data;
45
48
  }
46
49
  };
47
50
  return Object.assign(handler, {
@@ -52,3 +55,5 @@ export function remultNuxt(options) {
52
55
  },
53
56
  });
54
57
  }
58
+ /** @deprecated use remultApi instead */
59
+ export const remultNuxt = remultApi;
@@ -1,15 +1,18 @@
1
1
  import { getRequestEvent } from 'solid-js/web';
2
2
  import { createRemultServer } from './server/index.js';
3
- export function remultSolidStart(options) {
3
+ export function remultApi(options) {
4
4
  let result = createRemultServer(options, {
5
5
  buildGenericRequestInfo: (event) => ({
6
- url: event.request.url,
7
- method: event.request.method,
8
- on: (e, do1) => {
9
- if (e === 'close') {
10
- event.locals['_tempOnClose'] = do1;
11
- }
6
+ internal: {
7
+ url: event.request.url,
8
+ method: event.request.method,
9
+ on: (e, do1) => {
10
+ if (e === 'close') {
11
+ event.locals['_tempOnClose'] = do1;
12
+ }
13
+ },
12
14
  },
15
+ public: { headers: new Headers(event.request.headers) },
13
16
  }),
14
17
  getRequestBody: (event) => event.request.json(),
15
18
  });
@@ -95,3 +98,5 @@ export function remultSolidStart(options) {
95
98
  DELETE: serverHandler,
96
99
  });
97
100
  }
101
+ /** @deprecated use remultApi instead */
102
+ export const remultSolidStart = remultApi;
@@ -21,7 +21,7 @@ export class SqliteCoreDataProvider {
21
21
  let self = this;
22
22
  return {
23
23
  createTable: async (entity) => {
24
- builder.addSql(await self.getCreateTableSql(entity));
24
+ await (await self.getCreateTableSql(entity)).map(builder.addSql);
25
25
  },
26
26
  addColumn: async (entity, field) => {
27
27
  let e = await dbNamesOf(entity, this.wrapIdentifier);
@@ -45,6 +45,27 @@ export class SqliteCoreDataProvider {
45
45
  async ensureSchema(entities) {
46
46
  for (const entity of entities) {
47
47
  await this.createTableIfNotExist(entity);
48
+ await this.verifyAllColumns(entity);
49
+ }
50
+ }
51
+ async verifyAllColumns(entity) {
52
+ try {
53
+ let cmd = this.createCommand();
54
+ let e = await dbNamesOf(entity, this.wrapIdentifier);
55
+ let cols = (await cmd.execute(`PRAGMA table_info(${e.$entityName})`)).rows.map((x) => this.wrapIdentifier(x.name.toLocaleLowerCase()));
56
+ for (const col of entity.fields) {
57
+ if (!shouldNotCreateField(col, e)) {
58
+ let colName = e.$dbNameOf(col).toLocaleLowerCase();
59
+ if (!cols.includes(colName)) {
60
+ let sql = `ALTER table ${e.$entityName} ` +
61
+ `add column ${this.addColumnSqlSyntax(col, e.$dbNameOf(col), true)}`;
62
+ await this.createCommand().execute(sql);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ catch (err) {
68
+ console.error(err);
48
69
  }
49
70
  }
50
71
  async dropTable(entity) {
@@ -73,9 +94,9 @@ export class SqliteCoreDataProvider {
73
94
  }
74
95
  async createTableIfNotExist(entity) {
75
96
  let sql = await this.getCreateTableSql(entity);
76
- if (SqlDatabase.LogToConsole)
77
- console.log(sql);
78
- await this.createCommand().execute(sql);
97
+ for (const element of sql) {
98
+ await this.createCommand().execute(element);
99
+ }
79
100
  }
80
101
  supportsJsonColumnType;
81
102
  async getCreateTableSql(entity) {
@@ -99,7 +120,14 @@ export class SqliteCoreDataProvider {
99
120
  }
100
121
  }
101
122
  }
102
- let sql = 'create table if not exists ' + e.$entityName + ' (' + result + '\r\n)';
123
+ let sql = [
124
+ 'create table if not exists ' + e.$entityName + ' (' + result + '\r\n)',
125
+ ];
126
+ if (entity.idMetadata.fields.length > 1) {
127
+ sql.push(`create unique index if not exists ${this.wrapIdentifier(entity.dbName + '_primary_key')} on ${e.$entityName} (${entity.idMetadata.fields
128
+ .map((x) => e.$dbNameOf(x))
129
+ .join(',')})`);
130
+ }
103
131
  return sql;
104
132
  }
105
133
  wrapIdentifier(name) {