remult 0.25.5-exp.9 → 0.25.6-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 (48) hide show
  1. package/esm/graphql.js +24 -17
  2. package/esm/index.js +1 -0
  3. package/esm/package.json +1 -1
  4. package/esm/remult-fastify.js +3 -0
  5. package/esm/remult-hapi.js +3 -0
  6. package/esm/remult-knex/index.js +18 -6
  7. package/esm/remult-next.js +8 -0
  8. package/esm/remult-nuxt.js +3 -0
  9. package/esm/remult-sveltekit.js +63 -42
  10. package/esm/server/expressBridge.js +28 -0
  11. package/esm/server/get-remult-admin-html.js +3 -0
  12. package/esm/server/remult-admin.js +92 -0
  13. package/esm/src/data-providers/array-entity-data-provider.js +0 -1
  14. package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +16 -2
  15. package/esm/src/remult3/Fields.js +7 -1
  16. package/esm/src/remult3/RepositoryImplementation.js +1 -2
  17. package/esm/src/remult3/remult3.js +28 -3
  18. package/esm/src/server-action.js +3 -1
  19. package/graphql.js +40 -33
  20. package/index.d.ts +1 -0
  21. package/index.js +3 -1
  22. package/package.json +1 -1
  23. package/remult-fastify.js +3 -0
  24. package/remult-hapi.js +3 -0
  25. package/remult-knex/index.d.ts +3 -1
  26. package/remult-knex/index.js +70 -50
  27. package/remult-next.js +8 -0
  28. package/remult-nuxt.js +3 -0
  29. package/remult-sveltekit.d.ts +5 -1
  30. package/remult-sveltekit.js +85 -56
  31. package/server/expressBridge.d.ts +13 -1
  32. package/server/expressBridge.js +42 -0
  33. package/server/get-remult-admin-html.d.ts +1 -0
  34. package/server/get-remult-admin-html.js +7 -0
  35. package/server/remult-admin.d.ts +36 -0
  36. package/server/remult-admin.js +121 -0
  37. package/src/data-providers/array-entity-data-provider.d.ts +13 -0
  38. package/src/data-providers/array-entity-data-provider.js +0 -1
  39. package/src/data-providers/sql-database.d.ts +2 -2
  40. package/src/filter/filter-consumer-bridge-to-sql-request.js +28 -13
  41. package/src/remult3/Fields.d.ts +1 -0
  42. package/src/remult3/Fields.js +7 -1
  43. package/src/remult3/RepositoryImplementation.d.ts +2 -0
  44. package/src/remult3/RepositoryImplementation.js +1 -2
  45. package/src/remult3/remult3.d.ts +1 -1
  46. package/src/remult3/remult3.js +28 -3
  47. package/src/server-action.js +3 -1
  48. package/src/sql-command.d.ts +4 -2
package/esm/graphql.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getRelationFieldInfo } from './internals.js';
2
- import { Remult, remult } from './index.js';
2
+ import { CompoundIdField, Remult, remult } from './index.js';
3
3
  import { DataApi } from './src/data-api.js';
4
4
  import { getRepositoryInternals } from './src/remult3/repository-internals.js';
5
5
  const v2ConnectionAndPagination = false;
@@ -369,9 +369,12 @@ export function remultGraphql(options) {
369
369
  });
370
370
  currentType.mutation.delete.payload = upsertTypes(deletePayload);
371
371
  const deletedResultKey = `id`;
372
+ const type = meta.idMetadata.field instanceof CompoundIdField
373
+ ? 'String'
374
+ : getGraphqlBaseType(meta.idMetadata.field);
372
375
  currentType.mutation.delete.payload.fields.push({
373
376
  key: deletedResultKey,
374
- value: 'ID',
377
+ value: `${type}`,
375
378
  }, argErrorDetail, argClientMutationId);
376
379
  root[deleteResolverKey] = handleMutationWithErrors(async (dApi, response, setResult, arg1, req) => {
377
380
  await dApi.delete({
@@ -388,21 +391,7 @@ export function remultGraphql(options) {
388
391
  const ri = getRelationFieldInfo(f);
389
392
  if (f.options.includeInApi === false)
390
393
  continue;
391
- let type = 'String';
392
- switch (f.valueType) {
393
- case Boolean:
394
- type = 'Boolean';
395
- break;
396
- case Number:
397
- {
398
- if (f.valueConverter?.fieldTypeInDb === 'integer' ||
399
- f.valueConverter?.fieldTypeInDb === 'autoincrement')
400
- type = 'Int';
401
- else
402
- type = 'Float';
403
- }
404
- break;
405
- }
394
+ const type = getGraphqlBaseType(f);
406
395
  currentType.query.resultProcessors.push((r) => {
407
396
  r[nodeIdKey] = () => getMetaType(meta) + ':' + meta.idMetadata.getId(r);
408
397
  });
@@ -828,6 +817,24 @@ function fieldFormat(field) {
828
817
  }
829
818
  return `${strComment} ${key_value}`;
830
819
  }
820
+ function getGraphqlBaseType(field) {
821
+ let type = 'String';
822
+ switch (field.valueType) {
823
+ case Boolean:
824
+ type = 'Boolean';
825
+ break;
826
+ case Number:
827
+ {
828
+ if (field.valueConverter?.fieldTypeInDb === 'integer' ||
829
+ field.valueConverter?.fieldTypeInDb === 'autoincrement')
830
+ type = 'Int';
831
+ else
832
+ type = 'Float';
833
+ }
834
+ break;
835
+ }
836
+ return type;
837
+ }
831
838
  function getMetaType(entityMeta) {
832
839
  return entityMeta.entityType.name;
833
840
  }
package/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider.js';
1
2
  export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation.js';
2
3
  export { Entity } from './src/remult3/entity.js';
3
4
  export { getEntityRef } from './src/remult3/getEntityRef.js';
package/esm/package.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "type": "module"
2
+ "type": "module"
3
3
  }
@@ -10,6 +10,9 @@ export function remultFastify(options) {
10
10
  end() {
11
11
  res.send();
12
12
  },
13
+ send(html) {
14
+ res.type('text/html').send(html);
15
+ },
13
16
  json(data) {
14
17
  res.send(data);
15
18
  },
@@ -29,6 +29,9 @@ export function remultHapi(options) {
29
29
  end() {
30
30
  res(h.response().code(status));
31
31
  },
32
+ send(html) {
33
+ res(h.response(html).code(status));
34
+ },
32
35
  json(data) {
33
36
  res(h.response(data).code(status));
34
37
  },
@@ -19,6 +19,7 @@ export class KnexDataProvider {
19
19
  throw 'the data provider is not an KnexDataProvider';
20
20
  return r.knex;
21
21
  }
22
+ wrapIdentifier = (x) => this.knex.ref(x) + '';
22
23
  getEntityDataProvider(entity) {
23
24
  if (!supportsJsonLoadingAndSaving(this.knex))
24
25
  for (const f of entity.fields.toArray()) {
@@ -31,6 +32,17 @@ export class KnexDataProvider {
31
32
  };
32
33
  }
33
34
  }
35
+ else if (this.knex.client.config.client === 'mysql2') {
36
+ for (const f of entity.fields.toArray()) {
37
+ if (f.valueConverter.fieldTypeInDb === 'json') {
38
+ //@ts-ignore
39
+ f.valueConverter = {
40
+ ...f.valueConverter,
41
+ toDb: ValueConverters.JsonString.toDb,
42
+ };
43
+ }
44
+ }
45
+ }
34
46
  return new KnexEntityDataProvider(entity, this.knex);
35
47
  }
36
48
  async transaction(action) {
@@ -53,7 +65,7 @@ export class KnexDataProvider {
53
65
  }
54
66
  static async filterToRaw(entity, condition) {
55
67
  const repo = getRepository(entity);
56
- var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata));
68
+ var b = new FilterConsumerBridgeToKnexRequest(await dbNamesOf(repo.metadata, (x) => x));
57
69
  b._addWhere = false;
58
70
  await (await getRepositoryInternals(repo).translateWhereToFilter(condition)).__applyToConsumer(b);
59
71
  let r = await b.resolveWhere();
@@ -139,7 +151,7 @@ class KnexEntityDataProvider {
139
151
  });
140
152
  }
141
153
  async init() {
142
- const r = (await dbNamesOf(this.entity));
154
+ const r = (await dbNamesOf(this.entity, (x) => x));
143
155
  return {
144
156
  $dbNameOf: (f) => {
145
157
  let fm = f;
@@ -336,7 +348,7 @@ export class KnexSchemaBuilder {
336
348
  }
337
349
  async ensureSchema(entities) {
338
350
  for (const entity of entities) {
339
- let e = await dbNamesOf(entity);
351
+ let e = await dbNamesOf(entity, (x) => x);
340
352
  try {
341
353
  if (!entity.options.sqlExpression) {
342
354
  if (e.$entityName.toLowerCase().indexOf('from ') < 0) {
@@ -352,7 +364,7 @@ export class KnexSchemaBuilder {
352
364
  }
353
365
  }
354
366
  async createIfNotExist(entity) {
355
- const e = await dbNamesOf(entity);
367
+ const e = await dbNamesOf(entity, (x) => x);
356
368
  if (!(await this.knex.schema.hasTable(e.$entityName))) {
357
369
  let cols = new Map();
358
370
  for (const f of entity.fields) {
@@ -377,7 +389,7 @@ export class KnexSchemaBuilder {
377
389
  }
378
390
  }
379
391
  async addColumnIfNotExist(entity, c) {
380
- let e = await dbNamesOf(entity);
392
+ let e = await dbNamesOf(entity, (x) => x);
381
393
  if (shouldNotCreateField(c(entity), e))
382
394
  return;
383
395
  let col = c(entity);
@@ -389,7 +401,7 @@ export class KnexSchemaBuilder {
389
401
  }
390
402
  }
391
403
  async verifyAllColumns(entity) {
392
- let e = await dbNamesOf(entity);
404
+ let e = await dbNamesOf(entity, (x) => x);
393
405
  try {
394
406
  for (const col of entity.fields.toArray()) {
395
407
  if (!shouldNotCreateField(col, e)) {
@@ -57,6 +57,7 @@ export function remultNextApp(options) {
57
57
  const response = {
58
58
  end: () => { },
59
59
  json: () => { },
60
+ send: () => { },
60
61
  status: () => {
61
62
  return response;
62
63
  },
@@ -91,6 +92,13 @@ export function remultNextApp(options) {
91
92
  return sseResponse;
92
93
  }
93
94
  if (responseFromRemultHandler) {
95
+ if (responseFromRemultHandler.html)
96
+ return new Response(responseFromRemultHandler.html, {
97
+ status: responseFromRemultHandler.statusCode,
98
+ headers: {
99
+ 'Content-Type': 'text/html',
100
+ },
101
+ });
94
102
  return new Response(JSON.stringify(responseFromRemultHandler.data), {
95
103
  status: responseFromRemultHandler.statusCode,
96
104
  });
@@ -17,6 +17,7 @@ export function remultNuxt(options) {
17
17
  let sse = false;
18
18
  const response = {
19
19
  end: () => { },
20
+ send: () => { },
20
21
  json: () => { },
21
22
  status: () => {
22
23
  return response;
@@ -38,6 +39,8 @@ export function remultNuxt(options) {
38
39
  if (r) {
39
40
  if (r.statusCode !== 200)
40
41
  setResponseStatus(event, r.statusCode);
42
+ if (r.html)
43
+ return r.html;
41
44
  return r.data;
42
45
  }
43
46
  };
@@ -12,51 +12,68 @@ export function remultSveltekit(options) {
12
12
  }),
13
13
  getRequestBody: (event) => event.request.json(),
14
14
  });
15
- const handler = async ({ event, resolve }) => {
16
- if (event.url.pathname.startsWith(options.rootPath)) {
17
- let sseResponse = undefined;
18
- event.locals['_tempOnClose'] = () => { };
19
- const response = {
20
- end: () => { },
21
- json: () => { },
22
- status: () => {
23
- return response;
24
- },
25
- write: () => { },
26
- writeHead: (status, headers) => {
27
- if (status === 200 && headers) {
28
- const contentType = headers['Content-Type'];
29
- if (contentType === 'text/event-stream') {
30
- const messages = [];
31
- response.write = (x) => messages.push(x);
32
- const stream = new ReadableStream({
33
- start: (controller) => {
34
- for (const message of messages) {
35
- controller.enqueue(message);
36
- }
37
- response.write = (data) => {
38
- controller.enqueue(data);
39
- };
40
- },
41
- cancel: () => {
42
- response.write = () => { };
43
- event.locals['_tempOnClose']();
44
- },
45
- });
46
- sseResponse = new Response(stream, { headers });
47
- }
15
+ const serverHandler = async (event) => {
16
+ let sseResponse = undefined;
17
+ event.locals['_tempOnClose'] = () => { };
18
+ const response = {
19
+ end: () => { },
20
+ json: () => { },
21
+ send: () => { },
22
+ status: () => {
23
+ return response;
24
+ },
25
+ write: () => { },
26
+ writeHead: (status, headers) => {
27
+ if (status === 200 && headers) {
28
+ const contentType = headers['Content-Type'];
29
+ if (contentType === 'text/event-stream') {
30
+ const messages = [];
31
+ response.write = (x) => messages.push(x);
32
+ const stream = new ReadableStream({
33
+ start: (controller) => {
34
+ for (const message of messages) {
35
+ controller.enqueue(message);
36
+ }
37
+ response.write = (data) => {
38
+ controller.enqueue(data);
39
+ };
40
+ },
41
+ cancel: () => {
42
+ response.write = () => { };
43
+ event.locals['_tempOnClose']();
44
+ },
45
+ });
46
+ sseResponse = new Response(stream, { headers });
48
47
  }
49
- },
50
- };
51
- const responseFromRemultHandler = await result.handle(event, response);
52
- if (sseResponse !== undefined) {
53
- return sseResponse;
54
- }
55
- if (responseFromRemultHandler) {
56
- return new Response(JSON.stringify(responseFromRemultHandler.data), {
48
+ }
49
+ },
50
+ };
51
+ const responseFromRemultHandler = await result.handle(event, response);
52
+ if (sseResponse !== undefined) {
53
+ return sseResponse;
54
+ }
55
+ if (responseFromRemultHandler) {
56
+ if (responseFromRemultHandler.html)
57
+ return new Response(responseFromRemultHandler.html, {
57
58
  status: responseFromRemultHandler.statusCode,
59
+ headers: {
60
+ 'Content-Type': 'text/html',
61
+ },
58
62
  });
59
- }
63
+ const res = new Response(JSON.stringify(responseFromRemultHandler.data), {
64
+ status: responseFromRemultHandler.statusCode,
65
+ });
66
+ return res;
67
+ }
68
+ return new Response('Not Found', {
69
+ status: 404,
70
+ });
71
+ };
72
+ const handler = async ({ event, resolve }) => {
73
+ if (event.url.pathname.startsWith(options.rootPath)) {
74
+ const result = await serverHandler(event);
75
+ if (result != null && result?.status != 404)
76
+ return result;
60
77
  }
61
78
  return new Promise((res) => {
62
79
  result.withRemult(event, undefined, async () => {
@@ -70,5 +87,9 @@ export function remultSveltekit(options) {
70
87
  withRemult(request, what) {
71
88
  return result.withRemultAsync(request, what);
72
89
  },
90
+ GET: serverHandler,
91
+ PUT: serverHandler,
92
+ POST: serverHandler,
93
+ DELETE: serverHandler,
73
94
  });
74
95
  }
@@ -12,6 +12,7 @@ import { Action, classBackendMethodsArray } from '../src/server-action.js';
12
12
  import { serverActionField } from '../src/server-action-info.js';
13
13
  import { initDataProvider } from './initDataProvider.js';
14
14
  import { remultStatic } from '../src/remult-static.js';
15
+ import remultAdminHtml from './remult-admin.js';
15
16
  export function createRemultServerCore(options, serverCoreOptions) {
16
17
  if (!options) {
17
18
  options = {};
@@ -194,6 +195,18 @@ export class RemultServerImplementation {
194
195
  },
195
196
  doWork: undefined,
196
197
  }, r);
198
+ if (this.options.admin !== undefined && this.options.admin !== false) {
199
+ r.route(this.options.rootPath + '/admin*').get(this.process(async (remult, req, res, orig, origResponse) => {
200
+ if (remult.isAllowed(this.options.admin))
201
+ origResponse.send(remultAdminHtml({
202
+ remult: remult,
203
+ entities: this.options.entities,
204
+ baseUrl: this.options.rootPath + '/admin',
205
+ }));
206
+ else
207
+ res.notFound();
208
+ }));
209
+ }
197
210
  if (this.options.subscriptionServer instanceof SseSubscriptionServer) {
198
211
  const streamPath = this.options.rootPath + '/' + streamUrl;
199
212
  r.route(streamPath).get(this.process(async (remult, req, res, origReq, origRes) => {
@@ -814,6 +827,7 @@ export class RouteImplementation {
814
827
  this.coreOptions = coreOptions;
815
828
  }
816
829
  map = new Map();
830
+ starRoutes = [];
817
831
  route(path) {
818
832
  //consider using:
819
833
  //* https://raw.githubusercontent.com/cmorten/opine/main/src/utils/pathToRegex.ts
@@ -821,6 +835,8 @@ export class RouteImplementation {
821
835
  let r = path.toLowerCase();
822
836
  let m = new Map();
823
837
  this.map.set(r, m);
838
+ if (path.endsWith('*'))
839
+ this.starRoutes.push({ route: r.substring(0, r.length - 1), handler: m });
824
840
  const route = {
825
841
  get: (h) => {
826
842
  m.set('get', h);
@@ -864,6 +880,11 @@ export class RouteImplementation {
864
880
  gRes.json(data);
865
881
  res({ statusCode: this.statusCode, data });
866
882
  }
883
+ send(html) {
884
+ if (gRes !== undefined)
885
+ gRes.send(html);
886
+ res({ statusCode: this.statusCode, html });
887
+ }
867
888
  status(statusCode) {
868
889
  if (gRes !== undefined)
869
890
  gRes.status(statusCode);
@@ -913,6 +934,13 @@ export class RouteImplementation {
913
934
  }
914
935
  let lowerPath = path.toLowerCase();
915
936
  let m = this.map.get(lowerPath);
937
+ if (!m)
938
+ for (const route of this.starRoutes) {
939
+ if (lowerPath.startsWith(route.route)) {
940
+ m = route.handler;
941
+ break;
942
+ }
943
+ }
916
944
  if (m) {
917
945
  let h = m.get(req.method.toLowerCase());
918
946
  if (h) {