remult 3.0.6-next.1 → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm/graphql.js CHANGED
@@ -479,7 +479,7 @@ export function remultGraphql(options) {
479
479
  currentType.fields.push({
480
480
  key: f.key,
481
481
  value: `${getMetaType(ref)}${f.allowNull ? '' : '!'}`,
482
- comment: f.caption,
482
+ comment: f.label,
483
483
  });
484
484
  currentType.query.resultProcessors.push((r, orig) => {
485
485
  r[f.key] = async (args, req, gqlInfo) => {
@@ -524,7 +524,7 @@ export function remultGraphql(options) {
524
524
  currentType.fields.push({
525
525
  key: f.key,
526
526
  value: `${getMetaType(ref)}${f.allowNull ? '' : '!'}`,
527
- comment: f.caption,
527
+ comment: f.label,
528
528
  });
529
529
  const refKey = ref.key;
530
530
  currentType.query.resultProcessors.push((r) => {
@@ -566,7 +566,7 @@ export function remultGraphql(options) {
566
566
  currentType.fields.push({
567
567
  key: f.key,
568
568
  value: `${type}${f.allowNull ? '' : '!'}`,
569
- comment: f.caption,
569
+ comment: f.label,
570
570
  });
571
571
  }
572
572
  // sorting
package/esm/index.js CHANGED
@@ -1,5 +1,11 @@
1
1
  export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-provider.js';
2
- export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation.js';
2
+ export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListInfo, } from './src/remult3/RepositoryImplementation.js';
3
+ import { LabelTransformer } from './src/remult3/RepositoryImplementation.js';
4
+ export { LabelTransformer } from './src/remult3/RepositoryImplementation.js';
5
+ /**
6
+ * @deprecated use `LabelTransformer` instead
7
+ */
8
+ export const CaptionTransformer = LabelTransformer;
3
9
  export { Entity } from './src/remult3/entity.js';
4
10
  export { getEntityRef } from './src/remult3/getEntityRef.js';
5
11
  export { Field, Fields, Relations, } from './src/remult3/Fields.js';
@@ -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
+ }
@@ -8,7 +8,11 @@ export default function remultAdminHtml(options) {
8
8
  return getHtml()
9
9
  .replace('<!--PLACE_HERE_HEAD-->', head)
10
10
  .replace('<!--PLACE_HERE_BODY-->', `<script>
11
- window.optionsFromServer = ${JSON.stringify({ rootPath, requireAuthToken, disableLiveQuery })}
11
+ window.optionsFromServer = ${JSON.stringify({
12
+ rootPath,
13
+ requireAuthToken,
14
+ disableLiveQuery,
15
+ })}
12
16
  </script>`);
13
17
  }
14
18
  export function buildEntityInfo(options) {
@@ -63,7 +67,7 @@ export function buildEntityInfo(options) {
63
67
  where,
64
68
  entityKey: relRepo.metadata.key,
65
69
  key: x.key,
66
- caption: x.caption,
70
+ caption: x.label,
67
71
  });
68
72
  }
69
73
  continue;
@@ -74,7 +78,7 @@ export function buildEntityInfo(options) {
74
78
  readOnly: !x.apiUpdateAllowed(),
75
79
  values: getValueList(x),
76
80
  valFieldKey,
77
- caption: x.caption,
81
+ caption: x.label,
78
82
  relationToOne: relation,
79
83
  inputType: x.inputType,
80
84
  type: x.inputType === InputTypes.json
@@ -95,11 +99,11 @@ export function buildEntityInfo(options) {
95
99
  }
96
100
  if (metadata.apiReadAllowed) {
97
101
  let superKey = metadata.key;
98
- let caption = metadata.caption;
102
+ let caption = metadata.label;
99
103
  const nbOfEntities = entities.filter((e) => e.key === metadata.key).length;
100
104
  if (nbOfEntities > 0) {
101
105
  superKey = metadata.key + '_ext_' + nbOfEntities;
102
- caption = metadata.caption + '*'.repeat(nbOfEntities);
106
+ caption = metadata.label + '*'.repeat(nbOfEntities);
103
107
  }
104
108
  entities.push({
105
109
  superKey,
@@ -46,6 +46,7 @@ export class CompoundIdField {
46
46
  dbReadOnly = false;
47
47
  isServerExpression = false;
48
48
  key = '';
49
+ label = '';
49
50
  caption = '';
50
51
  inputType = '';
51
52
  dbName = '';
@@ -19,7 +19,7 @@ let x = {
19
19
  }),
20
20
  },
21
21
  fieldOptionsEnricher: undefined,
22
- captionTransformer: undefined,
22
+ labelTransformer: undefined,
23
23
  defaultDataProvider: () => undefined,
24
24
  };
25
25
  if ((typeof process !== 'undefined' &&
@@ -1191,7 +1191,7 @@ class rowHelperBase {
1191
1191
  for (const col of this.fieldsMetadata) {
1192
1192
  if (this.errors?.[col.key]) {
1193
1193
  error.message =
1194
- this.fields[col.key].metadata.caption +
1194
+ this.fields[col.key].metadata.label +
1195
1195
  ': ' +
1196
1196
  this.errors[col.key];
1197
1197
  this.error = error.message;
@@ -1950,23 +1950,26 @@ export class FieldRefImplementation {
1950
1950
  return !!!this.error;
1951
1951
  }
1952
1952
  }
1953
- let tempCaptionTransformer = {
1954
- transformCaption: (remult, key, caption, entityMetaData) => caption,
1953
+ let tempLabelTransformer = {
1954
+ transformLabel: (remult, key, label, entityMetaData) => label,
1955
+ set transformCaption(val) {
1956
+ this.transformLabel = val;
1957
+ },
1955
1958
  };
1956
1959
  export const fieldOptionsEnricher = remultStatic.fieldOptionsEnricher || {
1957
1960
  enrichFieldOptions: (options) => options,
1958
1961
  };
1959
- export const CaptionTransformer = remultStatic.captionTransformer ||
1960
- (remultStatic.captionTransformer = tempCaptionTransformer);
1961
- export function buildCaption(caption, key, remult, metaData) {
1962
+ export const LabelTransformer = remultStatic.labelTransformer ||
1963
+ (remultStatic.labelTransformer = tempLabelTransformer);
1964
+ export function buildLabel(label, key, remult, metaData) {
1962
1965
  let result = undefined;
1963
- if (typeof caption === 'function') {
1966
+ if (typeof label === 'function') {
1964
1967
  if (remult)
1965
- result = caption(remult);
1968
+ result = label(remult);
1966
1969
  }
1967
- else if (caption)
1968
- result = caption;
1969
- result = CaptionTransformer.transformCaption(remult, key, result ?? '', metaData);
1970
+ else if (label)
1971
+ result = label;
1972
+ result = LabelTransformer.transformLabel(remult, key, result ?? '', metaData);
1970
1973
  if (result)
1971
1974
  return result;
1972
1975
  if (key)
@@ -1994,7 +1997,7 @@ export class columnDefsImpl {
1994
1997
  catch (err) {
1995
1998
  const error = `${String(prop)} failed for value ${args?.[0]}. Error: ${typeof err === 'string' ? err : err.message}`;
1996
1999
  throw new EntityError({
1997
- message: this.caption + ': ' + error,
2000
+ message: this.label + ': ' + error,
1998
2001
  modelState: {
1999
2002
  [this.key]: error,
2000
2003
  },
@@ -2018,7 +2021,7 @@ export class columnDefsImpl {
2018
2021
  this.dbName = settings.dbName;
2019
2022
  if (this.dbName == undefined)
2020
2023
  this.dbName = settings.key;
2021
- this.caption = buildCaption(settings.caption, settings.key, remult, entityDefs);
2024
+ this.label = buildLabel(settings.label ?? settings.caption, settings.key, remult, entityDefs);
2022
2025
  }
2023
2026
  apiUpdateAllowed(item) {
2024
2027
  if (this.options.allowApiUpdate === undefined)
@@ -2049,7 +2052,10 @@ export class columnDefsImpl {
2049
2052
  readonly = false;
2050
2053
  valueConverter;
2051
2054
  allowNull;
2052
- caption;
2055
+ label;
2056
+ get caption() {
2057
+ return this.label;
2058
+ }
2053
2059
  dbName;
2054
2060
  inputType;
2055
2061
  key;
@@ -2103,7 +2109,7 @@ class EntityFullInfo {
2103
2109
  this.fieldsMetadata.push((r[x.key] = new columnDefsImpl(x, this, remult)));
2104
2110
  }
2105
2111
  this.fields = r;
2106
- this.caption = buildCaption(entityInfo.caption, this.key, remult, this);
2112
+ this.label = buildLabel(entityInfo.label ?? entityInfo.caption, this.key, remult, this);
2107
2113
  if (entityInfo.id) {
2108
2114
  let r = typeof entityInfo.id === 'string'
2109
2115
  ? this.fields.find(entityInfo.id)
@@ -2218,7 +2224,10 @@ class EntityFullInfo {
2218
2224
  };
2219
2225
  fields;
2220
2226
  dbName;
2221
- caption;
2227
+ label;
2228
+ get caption() {
2229
+ return this.label;
2230
+ }
2222
2231
  }
2223
2232
  export function FieldType(...options) {
2224
2233
  return (target, context) => {
@@ -2238,7 +2247,7 @@ export function ValueListFieldType(...options) {
2238
2247
  FieldType((o) => {
2239
2248
  ;
2240
2249
  (o.valueConverter = ValueListInfo.get(type)),
2241
- (o.displayValue = (item, val) => val?.caption);
2250
+ (o.displayValue = (item, val) => val?.label ?? val?.caption);
2242
2251
  o.validate = (entity, ref) => {
2243
2252
  const values = ValueListInfo.get(type).getValues();
2244
2253
  if (ref.value && !values.find((v) => v === ref.value)) {
@@ -2271,8 +2280,7 @@ export class ValueListInfo {
2271
2280
  s.id = member;
2272
2281
  if (typeof s.id === 'number')
2273
2282
  this.isNumeric = true;
2274
- if (s.caption === undefined)
2275
- s.caption = makeTitle(s.id !== undefined ? s.id.toString() : member);
2283
+ setLabelAndCaption(s, member);
2276
2284
  this.byIdMap.set(s.id, s);
2277
2285
  this.values.push(s);
2278
2286
  }
@@ -2287,8 +2295,7 @@ export class ValueListInfo {
2287
2295
  this.values.splice(0, this.values.length, ...op.getValues());
2288
2296
  this.byIdMap.clear();
2289
2297
  this.values.forEach((s) => {
2290
- if (s.caption === undefined && s.id !== undefined)
2291
- s.caption = makeTitle(s.id);
2298
+ setLabelAndCaption(s, '');
2292
2299
  this.byIdMap.set(s.id, s);
2293
2300
  });
2294
2301
  }
@@ -2337,6 +2344,15 @@ export class ValueListInfo {
2337
2344
  inputType;
2338
2345
  }
2339
2346
  const typeCache = new Map();
2347
+ function setLabelAndCaption(s, member) {
2348
+ let label = s.label ?? s.caption;
2349
+ if (label === undefined)
2350
+ label = makeTitle(s.id !== undefined ? s.id.toString() : member);
2351
+ if (s.label === undefined)
2352
+ s.label = label;
2353
+ if (s.caption === undefined)
2354
+ s.caption = label;
2355
+ }
2340
2356
  export function getValueList(type) {
2341
2357
  let meta = type?.metadata;
2342
2358
  if (!meta && isOfType(type, 'options'))
package/graphql.js CHANGED
@@ -586,7 +586,7 @@ function remultGraphql(options) {
586
586
  currentType.fields.push({
587
587
  key: f.key,
588
588
  value: "".concat(getMetaType(ref)).concat(f.allowNull ? '' : '!'),
589
- comment: f.caption,
589
+ comment: f.label,
590
590
  });
591
591
  currentType.query.resultProcessors.push(function (r, orig) {
592
592
  r[f.key] = function (args, req, gqlInfo) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
@@ -661,7 +661,7 @@ function remultGraphql(options) {
661
661
  currentType.fields.push({
662
662
  key: f.key,
663
663
  value: "".concat(getMetaType(ref)).concat(f.allowNull ? '' : '!'),
664
- comment: f.caption,
664
+ comment: f.label,
665
665
  });
666
666
  var refKey_1 = ref.key;
667
667
  currentType.query.resultProcessors.push(function (r) {
@@ -713,7 +713,7 @@ function remultGraphql(options) {
713
713
  currentType.fields.push({
714
714
  key: f.key,
715
715
  value: "".concat(type).concat(f.allowNull ? '' : '!'),
716
- comment: f.caption,
716
+ comment: f.label,
717
717
  });
718
718
  }
719
719
  // sorting
package/index.d.ts CHANGED
@@ -4,7 +4,15 @@ export { ArrayEntityDataProvider } from './src/data-providers/array-entity-data-
4
4
  export type { ClassType } from './classType.js';
5
5
  export { ValidateFieldEvent, MembersOnly, NumericKeys, FieldsMetadata, FieldRef, IdFieldRef, FieldsRef, EntityMetadata, EntityOrderBy, EntityFilter, FindOptions, FindOptionsBase, QueryResult, QueryOptions, UpsertOptions, Repository, GroupByOptions, GroupByResult, FindFirstOptions, ComparisonValueFilter, ValueFilter, IdFilter, ContainsStringValueFilter, EntityRef, SortSegments, Paginator, LiveQuery, LiveQueryChangeInfo, Subscribable, RefSubscriber, RefSubscriberBase, RelationOptions, ObjectMembersOnly, MembersToInclude, RepositoryRelations, EntityIdFields, ClassFieldDecorator, ClassFieldDecoratorContextStub, //n1 consider removing in ts5
6
6
  LifecycleEvent, FieldsRefBase, FieldsRefForEntityBase, RepositoryRelationsForEntityBase, ControllerRefForControllerBase, ControllerRefBase, ControllerRef, EntityRefForEntityBase, IdMetadata, FindFirstOptionsBase, } from './src/remult3/remult3.js';
7
- export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListFieldOptions, ValueListInfo, CaptionTransformer, } from './src/remult3/RepositoryImplementation.js';
7
+ export { EntityBase, ControllerBase, FieldType, getFields, ValueListFieldType, getValueList, ValueListFieldOptions, ValueListInfo, } from './src/remult3/RepositoryImplementation.js';
8
+ export { LabelTransformer } from './src/remult3/RepositoryImplementation.js';
9
+ /**
10
+ * @deprecated use `LabelTransformer` instead
11
+ */
12
+ export declare const CaptionTransformer: {
13
+ transformLabel: (remult: import("./src/context.js").Remult, key: string, label: string, entityMetaData: import("./src/remult3/remult3.js").EntityMetadata<any>) => string;
14
+ transformCaption: (remult: import("./src/context.js").Remult, key: string, label: string, entityMetaData: import("./src/remult3/remult3.js").EntityMetadata<any>) => string;
15
+ };
8
16
  export { Entity } from './src/remult3/entity.js';
9
17
  export { getEntityRef } from './src/remult3/getEntityRef.js';
10
18
  export { Field, Fields, StringFieldOptions, Relations, } from './src/remult3/Fields.js';
package/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SubscriptionChannel = exports.InMemoryLiveQueryStorage = exports.remult = exports.ValueConverters = exports.createValueValidator = exports.createValueValidatorWithArgs = exports.createValidatorWithArgs = exports.createValidator = exports.valueValidator = exports.Validators = exports.UrlBuilder = exports.Filter = exports.CompoundIdField = exports.Sort = exports.EventSource = exports.isBackend = exports.withRemult = exports.Remult = exports.Allow = exports.ForbiddenError = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.JsonEntityIndexedDbStorage = exports.JsonEntityOpfsStorage = exports.JsonDataProvider = exports.dbNamesOf = exports.CustomSqlFilterBuilder = exports.SqlDatabase = exports.InMemoryDataProvider = exports.RestDataProvider = exports.EntityError = exports.describeEntity = exports.describeBackendMethods = exports.describeClass = exports.IdEntity = exports.Relations = exports.Fields = exports.Field = exports.getEntityRef = exports.Entity = exports.CaptionTransformer = exports.ValueListInfo = exports.getValueList = exports.ValueListFieldType = exports.getFields = exports.FieldType = exports.ControllerBase = exports.EntityBase = exports.ArrayEntityDataProvider = void 0;
3
+ exports.InMemoryLiveQueryStorage = exports.remult = exports.ValueConverters = exports.createValueValidator = exports.createValueValidatorWithArgs = exports.createValidatorWithArgs = exports.createValidator = exports.valueValidator = exports.Validators = exports.UrlBuilder = exports.Filter = exports.CompoundIdField = exports.Sort = exports.EventSource = exports.isBackend = exports.withRemult = exports.Remult = exports.Allow = exports.ForbiddenError = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.JsonEntityIndexedDbStorage = exports.JsonEntityOpfsStorage = exports.JsonDataProvider = exports.dbNamesOf = exports.CustomSqlFilterBuilder = exports.SqlDatabase = exports.InMemoryDataProvider = exports.RestDataProvider = exports.EntityError = exports.describeEntity = exports.describeBackendMethods = exports.describeClass = exports.IdEntity = exports.Relations = exports.Fields = exports.Field = exports.getEntityRef = exports.Entity = exports.CaptionTransformer = exports.LabelTransformer = exports.ValueListInfo = exports.getValueList = exports.ValueListFieldType = exports.getFields = exports.FieldType = exports.ControllerBase = exports.EntityBase = exports.ArrayEntityDataProvider = void 0;
4
+ exports.SubscriptionChannel = void 0;
4
5
  exports.repo = repo;
5
6
  var array_entity_data_provider_js_1 = require("./src/data-providers/array-entity-data-provider.js");
6
7
  Object.defineProperty(exports, "ArrayEntityDataProvider", { enumerable: true, get: function () { return array_entity_data_provider_js_1.ArrayEntityDataProvider; } });
@@ -12,7 +13,13 @@ Object.defineProperty(exports, "getFields", { enumerable: true, get: function ()
12
13
  Object.defineProperty(exports, "ValueListFieldType", { enumerable: true, get: function () { return RepositoryImplementation_js_1.ValueListFieldType; } });
13
14
  Object.defineProperty(exports, "getValueList", { enumerable: true, get: function () { return RepositoryImplementation_js_1.getValueList; } });
14
15
  Object.defineProperty(exports, "ValueListInfo", { enumerable: true, get: function () { return RepositoryImplementation_js_1.ValueListInfo; } });
15
- Object.defineProperty(exports, "CaptionTransformer", { enumerable: true, get: function () { return RepositoryImplementation_js_1.CaptionTransformer; } });
16
+ var RepositoryImplementation_js_2 = require("./src/remult3/RepositoryImplementation.js");
17
+ var RepositoryImplementation_js_3 = require("./src/remult3/RepositoryImplementation.js");
18
+ Object.defineProperty(exports, "LabelTransformer", { enumerable: true, get: function () { return RepositoryImplementation_js_3.LabelTransformer; } });
19
+ /**
20
+ * @deprecated use `LabelTransformer` instead
21
+ */
22
+ exports.CaptionTransformer = RepositoryImplementation_js_2.LabelTransformer;
16
23
  var entity_js_1 = require("./src/remult3/entity.js");
17
24
  Object.defineProperty(exports, "Entity", { enumerable: true, get: function () { return entity_js_1.Entity; } });
18
25
  var getEntityRef_js_1 = require("./src/remult3/getEntityRef.js");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "3.0.6-next.1",
3
+ "version": "3.0.6",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -131,6 +131,16 @@
131
131
  "import": "./esm/remult-duckdb.js",
132
132
  "types": "./remult-duckdb.d.ts"
133
133
  },
134
+ "./remult-d1": {
135
+ "require": "./remult-d1.js",
136
+ "import": "./esm/remult-d1.js",
137
+ "types": "./remult-d1.d.ts"
138
+ },
139
+ "./remult-d1-http": {
140
+ "require": "./remult-d1-http.js",
141
+ "import": "./esm/remult-d1-http.js",
142
+ "types": "./remult-d1-http.d.ts"
143
+ },
134
144
  "./remult-bun-sqlite": {
135
145
  "require": "./remult-bun-sqlite.js",
136
146
  "import": "./esm/remult-bun-sqlite.js",
@@ -0,0 +1,16 @@
1
+ import { SqlDatabase } from './index.js';
2
+ import { type D1Client, D1DataProvider, type D1RowObject } from './remult-d1.js';
3
+ export { D1DataProvider };
4
+ type D1Credentials = {
5
+ accountId: string;
6
+ apiToken: string;
7
+ databaseId: string;
8
+ };
9
+ export declare function createD1HttpDataProvider(creds: D1Credentials): SqlDatabase;
10
+ export declare class D1HttpClient implements D1Client {
11
+ private d1;
12
+ private accountId;
13
+ private databaseId;
14
+ constructor({ accountId, databaseId, apiToken }: D1Credentials);
15
+ execute(sql: string, params?: unknown[]): Promise<D1RowObject[]>;
16
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.D1HttpClient = exports.D1DataProvider = void 0;
4
+ exports.createD1HttpDataProvider = createD1HttpDataProvider;
5
+ var tslib_1 = require("tslib");
6
+ var cloudflare_1 = tslib_1.__importDefault(require("cloudflare"));
7
+ var index_js_1 = require("./index.js");
8
+ var remult_d1_js_1 = require("./remult-d1.js");
9
+ Object.defineProperty(exports, "D1DataProvider", { enumerable: true, get: function () { return remult_d1_js_1.D1DataProvider; } });
10
+ function createD1HttpDataProvider(creds) {
11
+ return new index_js_1.SqlDatabase(new remult_d1_js_1.D1DataProvider(new D1HttpClient(creds)));
12
+ }
13
+ var D1HttpClient = /** @class */ (function () {
14
+ function D1HttpClient(_a) {
15
+ var accountId = _a.accountId, databaseId = _a.databaseId, apiToken = _a.apiToken;
16
+ this.d1 = new cloudflare_1.default({ apiToken: apiToken }).d1.database;
17
+ this.accountId = accountId;
18
+ this.databaseId = databaseId;
19
+ }
20
+ D1HttpClient.prototype.execute = function (sql_1) {
21
+ return tslib_1.__awaiter(this, arguments, void 0, function (sql, params) {
22
+ if (params === void 0) { params = []; }
23
+ return tslib_1.__generator(this, function (_a) {
24
+ return [2 /*return*/, this.d1
25
+ .query(this.databaseId, {
26
+ sql: sql,
27
+ params: params,
28
+ account_id: this.accountId,
29
+ })
30
+ .then(function (_a) {
31
+ var pages = _a.result;
32
+ return pages.flatMap(function (page) { return page.results; });
33
+ })
34
+ // NOTE: d1 query endpoint returns the result as array of object with keys as column names.
35
+ // We're returning that now because the rest of remult seems to expect that.
36
+ // D1 also has a more efficient raw() endpoint that returns {columns: string[], rows: any[][]} that we may want
37
+ // to use eventually, and write code like fromRowToSql()
38
+ // at https://github.com/tursodatabase/libsql-client-ts/blob/main/packages/libsql-client/src/sqlite3.ts#L398
39
+ // to adapt the data
40
+ ];
41
+ });
42
+ });
43
+ };
44
+ return D1HttpClient;
45
+ }());
46
+ exports.D1HttpClient = D1HttpClient;
package/remult-d1.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { SqlDatabase, type SqlImplementation } from './index.js';
2
+ import { SqliteCoreDataProvider } from './remult-sqlite-core.js';
3
+ export declare function createD1DataProvider(d1: D1Database): SqlDatabase;
4
+ export declare class D1DataProvider extends SqliteCoreDataProvider {
5
+ private d1;
6
+ /**
7
+ * For production or local d1 using binding
8
+ *
9
+ * const dataProvider = new SqlDatabase(new D1DataProvider(new D1BindingClient(d1)))
10
+ */
11
+ constructor(d1: D1Client);
12
+ transaction(action: (sql: SqlImplementation) => Promise<void>): Promise<void>;
13
+ }
14
+ export type D1RowObject = Record<string, unknown>;
15
+ export interface D1Client {
16
+ execute(sql: string, params?: unknown[]): Promise<D1RowObject[]>;
17
+ }
18
+ export declare class D1BindingClient implements D1Client {
19
+ private d1;
20
+ /**
21
+ * Simple d1 client that wraps the d1 binding directly
22
+ *
23
+ * const d1 = new D1BindingClient(env.DB)
24
+ */
25
+ constructor(d1: D1Database);
26
+ execute(sql: string, params?: unknown[]): Promise<D1RowObject[]>;
27
+ }
package/remult-d1.js ADDED
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ /// <reference types="@cloudflare/workers-types" />
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.D1BindingClient = exports.D1DataProvider = void 0;
5
+ exports.createD1DataProvider = createD1DataProvider;
6
+ var tslib_1 = require("tslib");
7
+ var index_js_1 = require("./index.js");
8
+ var remult_sqlite_core_js_1 = require("./remult-sqlite-core.js");
9
+ function createD1DataProvider(d1) {
10
+ return new index_js_1.SqlDatabase(new D1DataProvider(new D1BindingClient(d1)));
11
+ }
12
+ var D1DataProvider = /** @class */ (function (_super) {
13
+ tslib_1.__extends(D1DataProvider, _super);
14
+ /**
15
+ * For production or local d1 using binding
16
+ *
17
+ * const dataProvider = new SqlDatabase(new D1DataProvider(new D1BindingClient(d1)))
18
+ */
19
+ function D1DataProvider(d1) {
20
+ var _this = _super.call(this, function () { return new D1Command(_this.d1); }, function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
21
+ return tslib_1.__generator(this, function (_a) {
22
+ return [2 /*return*/];
23
+ });
24
+ }); }) || this;
25
+ _this.d1 = d1;
26
+ return _this;
27
+ }
28
+ D1DataProvider.prototype.transaction = function (action) {
29
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
30
+ return tslib_1.__generator(this, function (_a) {
31
+ switch (_a.label) {
32
+ case 0:
33
+ // As of June 2025, D1 doesn't support transactions
34
+ // Here we simply run the action without wrapping it in a transaction
35
+ // It means queries in action() will be run individually (this is the same decision prisma made)
36
+ return [4 /*yield*/, action(this)];
37
+ case 1:
38
+ // As of June 2025, D1 doesn't support transactions
39
+ // Here we simply run the action without wrapping it in a transaction
40
+ // It means queries in action() will be run individually (this is the same decision prisma made)
41
+ _a.sent();
42
+ return [2 /*return*/];
43
+ }
44
+ });
45
+ });
46
+ };
47
+ return D1DataProvider;
48
+ }(remult_sqlite_core_js_1.SqliteCoreDataProvider));
49
+ exports.D1DataProvider = D1DataProvider;
50
+ var D1BindingClient = /** @class */ (function () {
51
+ /**
52
+ * Simple d1 client that wraps the d1 binding directly
53
+ *
54
+ * const d1 = new D1BindingClient(env.DB)
55
+ */
56
+ function D1BindingClient(d1) {
57
+ this.d1 = d1;
58
+ }
59
+ D1BindingClient.prototype.execute = function (sql_1) {
60
+ return tslib_1.__awaiter(this, arguments, void 0, function (sql, params) {
61
+ var results;
62
+ var _a;
63
+ if (params === void 0) { params = []; }
64
+ return tslib_1.__generator(this, function (_b) {
65
+ switch (_b.label) {
66
+ case 0: return [4 /*yield*/, (_a = this.d1
67
+ .prepare(sql))
68
+ .bind.apply(_a, tslib_1.__spreadArray([], tslib_1.__read(params), false)).run()];
69
+ case 1:
70
+ results = (_b.sent()).results;
71
+ return [2 /*return*/, results];
72
+ }
73
+ });
74
+ });
75
+ };
76
+ return D1BindingClient;
77
+ }());
78
+ exports.D1BindingClient = D1BindingClient;
79
+ var D1Command = /** @class */ (function () {
80
+ function D1Command(d1) {
81
+ this.params = [];
82
+ this.d1 = d1;
83
+ }
84
+ D1Command.prototype.execute = function (sql) {
85
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
86
+ var results;
87
+ return tslib_1.__generator(this, function (_a) {
88
+ switch (_a.label) {
89
+ case 0: return [4 /*yield*/, this.d1.execute(sql, this.params)];
90
+ case 1:
91
+ results = _a.sent();
92
+ return [2 /*return*/, new D1SqlResult(results)];
93
+ }
94
+ });
95
+ });
96
+ };
97
+ /** @deprecated use `param` instead*/
98
+ D1Command.prototype.addParameterAndReturnSqlToken = function (val) {
99
+ return this.param(val);
100
+ };
101
+ D1Command.prototype.param = function (val) {
102
+ var p;
103
+ if (val instanceof Date)
104
+ p = val.valueOf();
105
+ else if (typeof val === 'boolean')
106
+ p = val ? 1 : 0;
107
+ else
108
+ p = val;
109
+ this.params.push(p);
110
+ // According to https://developers.cloudflare.com/d1/worker-api/prepared-statements/
111
+ // only the ordered "?NNN" and anonymous "?" param types are supported (although :AAAA seems to work too)
112
+ var key = "?".concat(this.params.length);
113
+ return key;
114
+ };
115
+ return D1Command;
116
+ }());
117
+ var D1SqlResult = /** @class */ (function () {
118
+ function D1SqlResult(rows) {
119
+ if (rows === void 0) { rows = []; }
120
+ this.rows = rows;
121
+ // NOTE: are we guaranteed that when this is reached, rows is not empty?
122
+ this.columns = rows.length === 0 ? [] : Object.keys(rows[0]);
123
+ }
124
+ D1SqlResult.prototype.getColumnKeyInResultForIndexInSelect = function (index) {
125
+ return this.columns[index];
126
+ };
127
+ return D1SqlResult;
128
+ }());
@@ -12,7 +12,11 @@ function remultAdminHtml(options) {
12
12
  var head = options.head, rootPath = options.rootPath, requireAuthToken = options.requireAuthToken, disableLiveQuery = options.disableLiveQuery;
13
13
  return (0, get_remult_admin_html_js_1.getHtml)()
14
14
  .replace('<!--PLACE_HERE_HEAD-->', head)
15
- .replace('<!--PLACE_HERE_BODY-->', "<script>\n window.optionsFromServer = ".concat(JSON.stringify({ rootPath: rootPath, requireAuthToken: requireAuthToken, disableLiveQuery: disableLiveQuery }), "\n</script>"));
15
+ .replace('<!--PLACE_HERE_BODY-->', "<script>\n window.optionsFromServer = ".concat(JSON.stringify({
16
+ rootPath: rootPath,
17
+ requireAuthToken: requireAuthToken,
18
+ disableLiveQuery: disableLiveQuery,
19
+ }), "\n</script>"));
16
20
  }
17
21
  function buildEntityInfo(options) {
18
22
  var e_1, _a;
@@ -68,7 +72,7 @@ function buildEntityInfo(options) {
68
72
  }
69
73
  else if (info.type === 'toMany') {
70
74
  if (relRepo.metadata.apiReadAllowed) {
71
- relations.push(tslib_1.__assign(tslib_1.__assign({}, relInfo), { where: where, entityKey: relRepo.metadata.key, key: x.key, caption: x.caption }));
75
+ relations.push(tslib_1.__assign(tslib_1.__assign({}, relInfo), { where: where, entityKey: relRepo.metadata.key, key: x.key, caption: x.label }));
72
76
  }
73
77
  return "continue";
74
78
  }
@@ -78,7 +82,7 @@ function buildEntityInfo(options) {
78
82
  readOnly: !x.apiUpdateAllowed(),
79
83
  values: (0, RepositoryImplementation_js_1.getValueList)(x),
80
84
  valFieldKey: valFieldKey,
81
- caption: x.caption,
85
+ caption: x.label,
82
86
  relationToOne: relation,
83
87
  inputType: x.inputType,
84
88
  type: x.inputType === inputTypes_js_1.InputTypes.json
@@ -112,11 +116,11 @@ function buildEntityInfo(options) {
112
116
  }
113
117
  if (metadata.apiReadAllowed) {
114
118
  var superKey = metadata.key;
115
- var caption = metadata.caption;
119
+ var caption = metadata.label;
116
120
  var nbOfEntities = entities.filter(function (e) { return e.key === metadata.key; }).length;
117
121
  if (nbOfEntities > 0) {
118
122
  superKey = metadata.key + '_ext_' + nbOfEntities;
119
- caption = metadata.caption + '*'.repeat(nbOfEntities);
123
+ caption = metadata.label + '*'.repeat(nbOfEntities);
120
124
  }
121
125
  entities.push({
122
126
  superKey: superKey,
@@ -19,6 +19,7 @@ export declare class CompoundIdField implements FieldMetadata<string> {
19
19
  dbReadOnly: boolean;
20
20
  isServerExpression: boolean;
21
21
  key: string;
22
+ label: string;
22
23
  caption: string;
23
24
  inputType: string;
24
25
  dbName: string;
@@ -13,6 +13,7 @@ var CompoundIdField = /** @class */ (function () {
13
13
  this.dbReadOnly = false;
14
14
  this.isServerExpression = false;
15
15
  this.key = '';
16
+ this.label = '';
16
17
  this.caption = '';
17
18
  this.inputType = '';
18
19
  this.dbName = '';
@@ -7,6 +7,11 @@ export interface FieldOptions<entityType = unknown, valueType = unknown> {
7
7
  * <input placeholder={taskRepo.metadata.fields.title.caption}/>
8
8
  */
9
9
  caption?: string;
10
+ /** A human readable name for the field. Can be used to achieve a consistent label for a field throughout the app
11
+ * @example
12
+ * <input placeholder={taskRepo.metadata.fields.title.label}/>
13
+ */
14
+ label?: string;
10
15
  /** If it can store null in the database */
11
16
  allowNull?: boolean;
12
17
  /** If a value is required. Short-cut to say `validate: Validators.required`.
@@ -141,6 +146,12 @@ export interface FieldMetadata<valueType = unknown, entityType = unknown> {
141
146
  * @see {@link FieldOptions#caption} for configuration details
142
147
  */
143
148
  readonly caption: string;
149
+ /** A human readable label for the field. Can be used to achieve a consistent label for a field throughout the app
150
+ * @example
151
+ * <input placeholder={taskRepo.metadata.fields.title.label}/>
152
+ * @see {@link FieldOptions.label} for configuration details
153
+ */
154
+ readonly label: string;
144
155
  /** The name of the column in the database that holds the data for this field. If no name is set, the key will be used instead.
145
156
  * @example
146
157
  *
@@ -336,4 +347,5 @@ export declare function valueOrExpressionToValue<valueType>(f: ValueOrExpression
336
347
  export interface ValueListItem {
337
348
  id?: any;
338
349
  caption?: any;
350
+ label?: any;
339
351
  }
package/src/entity.d.ts CHANGED
@@ -6,6 +6,11 @@ import type { DataProvider } from './data-interfaces.js';
6
6
  export interface EntityOptions<entityType = unknown> {
7
7
  /**A human readable name for the entity */
8
8
  caption?: string;
9
+ /** A human readable label for the entity. Can be used to achieve a consistent label for a field throughout the app
10
+ * @example
11
+ * <h1>Create a new item in {taskRepo.metadata.label}</h1>
12
+ */
13
+ label?: string;
9
14
  /**
10
15
  * Determines if this Entity is available for get requests using Rest Api
11
16
  * @description
@@ -20,7 +20,7 @@ export declare const remultStatic: {
20
20
  };
21
21
  };
22
22
  fieldOptionsEnricher: any;
23
- captionTransformer: any;
23
+ labelTransformer: any;
24
24
  defaultDataProvider: () => Promise<DataProvider | undefined>;
25
25
  };
26
26
  export declare function defaultFactory(): Remult;
@@ -24,7 +24,7 @@ var x = {
24
24
  }); },
25
25
  },
26
26
  fieldOptionsEnricher: undefined,
27
- captionTransformer: undefined,
27
+ labelTransformer: undefined,
28
28
  defaultDataProvider: function () {
29
29
  return undefined;
30
30
  },
@@ -211,39 +211,43 @@ export declare class FieldRefImplementation<entityType, valueType> implements Fi
211
211
  export declare const fieldOptionsEnricher: {
212
212
  enrichFieldOptions: (options: FieldOptions) => void;
213
213
  };
214
- export declare const CaptionTransformer: {
214
+ export declare const LabelTransformer: {
215
215
  /**
216
- * Transforms the caption of a column based on custom rules or criteria.
216
+ * Transforms the label of a column based on custom rules or criteria.
217
217
  *
218
218
  * This method can be assigned an arrow function that dynamically alters the
219
- * caption of a column. It is particularly useful for internationalization,
220
- * applying specific labeling conventions, or any other custom caption transformation
219
+ * label of a column. It is particularly useful for internationalization,
220
+ * applying specific labeling conventions, or any other custom label transformation
221
221
  * logic that your application requires.
222
222
  *
223
223
  * @param {Remult} remult - The Remult context, providing access to various framework features.
224
- * @param {string} key - The key (name) of the field whose caption is being transformed.
225
- * @param {string} caption - The original caption of the field.
224
+ * @param {string} key - The key (name) of the field whose label is being transformed.
225
+ * @param {string} label - The original label of the field.
226
226
  * @param {EntityMetadata<any>} entityMetaData - Metadata of the entity that the field belongs to.
227
- * @returns {string} The transformed caption for the field. If no transformation is applied,
228
- * the original caption is returned.
227
+ * @returns {string} The transformed label for the field. If no transformation is applied,
228
+ * the original label is returned.
229
229
  *
230
230
  * @example
231
- * // Example of translating a field caption to French
232
- * CaptionTransformer.transformCaption = (
233
- * remult, key, caption, entityMetaData
231
+ * // Example of translating a field label to French
232
+ * LabelTransformer.transformLabel = (
233
+ * remult, key, label, entityMetaData
234
234
  * ) => {
235
235
  * if (key === 'firstName') {
236
236
  * return 'Prénom'; // French translation for 'firstName'
237
237
  * }
238
- * return caption;
238
+ * return label;
239
239
  * };
240
240
  *
241
241
  * // Usage
242
- * const firstNameCaption = repo(Person).fields.firstName.caption; // Returns 'Prénom'
242
+ * const firstNameLabel = repo(Person).fields.firstName.label; // Returns 'Prénom'
243
243
  */
244
- transformCaption: (remult: Remult, key: string, caption: string, entityMetaData: EntityMetadata<any>) => string;
244
+ transformLabel: (remult: Remult, key: string, label: string, entityMetaData: EntityMetadata<any>) => string;
245
+ /**
246
+ * @obsolete use LabelTransformer.transformLabel instead
247
+ */
248
+ transformCaption: (remult: Remult, key: string, label: string, entityMetaData: EntityMetadata<any>) => string;
245
249
  };
246
- export declare function buildCaption(caption: string | ((remult: Remult) => string) | undefined, key: string, remult: Remult, metaData: EntityMetadata<any>): string;
250
+ export declare function buildLabel(label: string | ((remult: Remult) => string) | undefined, key: string, remult: Remult, metaData: EntityMetadata<any>): string;
247
251
  export declare class columnDefsImpl implements FieldMetadata {
248
252
  private settings;
249
253
  private entityDefs;
@@ -260,7 +264,8 @@ export declare class columnDefsImpl implements FieldMetadata {
260
264
  readonly: boolean;
261
265
  valueConverter: Required<ValueConverter<any>>;
262
266
  allowNull: boolean;
263
- caption: string;
267
+ label: string;
268
+ get caption(): string;
264
269
  dbName: string;
265
270
  inputType: string;
266
271
  key: string;
@@ -285,7 +290,8 @@ declare class EntityFullInfo<T> implements EntityMetadata<T> {
285
290
  idMetadata: IdMetadata<T>;
286
291
  fields: FieldsMetadata<T>;
287
292
  dbName: string;
288
- caption: string;
293
+ label: string;
294
+ get caption(): string;
289
295
  }
290
296
  export declare function FieldType<valueType = unknown>(...options: (FieldOptions<any, valueType> | ((options: FieldOptions<any, valueType>, remult: Remult) => void))[]): (target: any, context?: any) => any;
291
297
  export declare function isAutoIncrement(f: FieldMetadata): boolean;
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ControllerBase = exports.EntityBase = exports.fieldOptionalValuesFunctionKey = exports.storableMember = exports.ValueListInfo = exports.columnDefsImpl = exports.CaptionTransformer = exports.fieldOptionsEnricher = exports.FieldRefImplementation = exports.controllerRefImpl = exports.rowHelperImplementation = exports.RepositoryImplementation = void 0;
3
+ exports.ControllerBase = exports.EntityBase = exports.fieldOptionalValuesFunctionKey = exports.storableMember = exports.ValueListInfo = exports.columnDefsImpl = exports.LabelTransformer = exports.fieldOptionsEnricher = exports.FieldRefImplementation = exports.controllerRefImpl = exports.rowHelperImplementation = exports.RepositoryImplementation = void 0;
4
4
  exports.createOldEntity = createOldEntity;
5
5
  exports.getFields = getFields;
6
6
  exports.getControllerRef = getControllerRef;
7
- exports.buildCaption = buildCaption;
7
+ exports.buildLabel = buildLabel;
8
8
  exports.FieldType = FieldType;
9
9
  exports.isAutoIncrement = isAutoIncrement;
10
10
  exports.ValueListFieldType = ValueListFieldType;
@@ -1955,7 +1955,7 @@ var rowHelperBase = /** @class */ (function () {
1955
1955
  var col = _d.value;
1956
1956
  if ((_b = this.errors) === null || _b === void 0 ? void 0 : _b[col.key]) {
1957
1957
  error.message =
1958
- this.fields[col.key].metadata.caption +
1958
+ this.fields[col.key].metadata.label +
1959
1959
  ': ' +
1960
1960
  this.errors[col.key];
1961
1961
  this.error = error.message;
@@ -3334,23 +3334,26 @@ var FieldRefImplementation = /** @class */ (function () {
3334
3334
  return FieldRefImplementation;
3335
3335
  }());
3336
3336
  exports.FieldRefImplementation = FieldRefImplementation;
3337
- var tempCaptionTransformer = {
3338
- transformCaption: function (remult, key, caption, entityMetaData) { return caption; },
3337
+ var tempLabelTransformer = {
3338
+ transformLabel: function (remult, key, label, entityMetaData) { return label; },
3339
+ set transformCaption(val) {
3340
+ this.transformLabel = val;
3341
+ },
3339
3342
  };
3340
3343
  exports.fieldOptionsEnricher = remult_static_js_1.remultStatic.fieldOptionsEnricher || {
3341
3344
  enrichFieldOptions: function (options) { return options; },
3342
3345
  };
3343
- exports.CaptionTransformer = remult_static_js_1.remultStatic.captionTransformer ||
3344
- (remult_static_js_1.remultStatic.captionTransformer = tempCaptionTransformer);
3345
- function buildCaption(caption, key, remult, metaData) {
3346
+ exports.LabelTransformer = remult_static_js_1.remultStatic.labelTransformer ||
3347
+ (remult_static_js_1.remultStatic.labelTransformer = tempLabelTransformer);
3348
+ function buildLabel(label, key, remult, metaData) {
3346
3349
  var result = undefined;
3347
- if (typeof caption === 'function') {
3350
+ if (typeof label === 'function') {
3348
3351
  if (remult)
3349
- result = caption(remult);
3352
+ result = label(remult);
3350
3353
  }
3351
- else if (caption)
3352
- result = caption;
3353
- result = exports.CaptionTransformer.transformCaption(remult, key, result !== null && result !== void 0 ? result : '', metaData);
3354
+ else if (label)
3355
+ result = label;
3356
+ result = exports.LabelTransformer.transformLabel(remult, key, result !== null && result !== void 0 ? result : '', metaData);
3354
3357
  if (result)
3355
3358
  return result;
3356
3359
  if (key)
@@ -3360,7 +3363,7 @@ function buildCaption(caption, key, remult, metaData) {
3360
3363
  var columnDefsImpl = /** @class */ (function () {
3361
3364
  function columnDefsImpl(settings, entityDefs, remult) {
3362
3365
  var _this = this;
3363
- var _a;
3366
+ var _a, _b;
3364
3367
  this.settings = settings;
3365
3368
  this.entityDefs = entityDefs;
3366
3369
  this.remult = remult;
@@ -3384,7 +3387,7 @@ var columnDefsImpl = /** @class */ (function () {
3384
3387
  catch (err) {
3385
3388
  var error = "".concat(String(prop), " failed for value ").concat(args === null || args === void 0 ? void 0 : args[0], ". Error: ").concat(typeof err === 'string' ? err : err.message);
3386
3389
  throw new data_interfaces_js_1.EntityError({
3387
- message: _this.caption + ': ' + error,
3390
+ message: _this.label + ': ' + error,
3388
3391
  modelState: (_a = {},
3389
3392
  _a[_this.key] = error,
3390
3393
  _a),
@@ -3408,7 +3411,7 @@ var columnDefsImpl = /** @class */ (function () {
3408
3411
  this.dbName = settings.dbName;
3409
3412
  if (this.dbName == undefined)
3410
3413
  this.dbName = settings.key;
3411
- this.caption = buildCaption(settings.caption, settings.key, remult, entityDefs);
3414
+ this.label = buildLabel((_b = settings.label) !== null && _b !== void 0 ? _b : settings.caption, settings.key, remult, entityDefs);
3412
3415
  }
3413
3416
  columnDefsImpl.prototype.apiUpdateAllowed = function (item) {
3414
3417
  if (this.options.allowApiUpdate === undefined)
@@ -3438,6 +3441,13 @@ var columnDefsImpl = /** @class */ (function () {
3438
3441
  });
3439
3442
  });
3440
3443
  };
3444
+ Object.defineProperty(columnDefsImpl.prototype, "caption", {
3445
+ get: function () {
3446
+ return this.label;
3447
+ },
3448
+ enumerable: false,
3449
+ configurable: true
3450
+ });
3441
3451
  Object.defineProperty(columnDefsImpl.prototype, "dbReadOnly", {
3442
3452
  get: function () {
3443
3453
  return Boolean(this.settings.dbReadOnly);
@@ -3452,6 +3462,7 @@ var EntityFullInfo = /** @class */ (function () {
3452
3462
  function EntityFullInfo(columnsInfo, entityInfo, remult, entityType, key) {
3453
3463
  var _a, e_49, _b;
3454
3464
  var _this = this;
3465
+ var _c;
3455
3466
  this.entityInfo = entityInfo;
3456
3467
  this.remult = remult;
3457
3468
  this.entityType = entityType;
@@ -3562,7 +3573,7 @@ var EntityFullInfo = /** @class */ (function () {
3562
3573
  finally { if (e_49) throw e_49.error; }
3563
3574
  }
3564
3575
  this.fields = r;
3565
- this.caption = buildCaption(entityInfo.caption, this.key, remult, this);
3576
+ this.label = buildLabel((_c = entityInfo.label) !== null && _c !== void 0 ? _c : entityInfo.caption, this.key, remult, this);
3566
3577
  if (entityInfo.id) {
3567
3578
  var r_2 = typeof entityInfo.id === 'string'
3568
3579
  ? this.fields.find(entityInfo.id)
@@ -3627,6 +3638,13 @@ var EntityFullInfo = /** @class */ (function () {
3627
3638
  EntityFullInfo.prototype.getDbName = function () {
3628
3639
  return (0, entityDbName_js_1.entityDbName)(this);
3629
3640
  };
3641
+ Object.defineProperty(EntityFullInfo.prototype, "caption", {
3642
+ get: function () {
3643
+ return this.label;
3644
+ },
3645
+ enumerable: false,
3646
+ configurable: true
3647
+ });
3630
3648
  return EntityFullInfo;
3631
3649
  }());
3632
3650
  function FieldType() {
@@ -3656,7 +3674,7 @@ function ValueListFieldType() {
3656
3674
  FieldType.apply(void 0, tslib_1.__spreadArray([function (o) {
3657
3675
  ;
3658
3676
  (o.valueConverter = ValueListInfo.get(type)),
3659
- (o.displayValue = function (item, val) { return val === null || val === void 0 ? void 0 : val.caption; });
3677
+ (o.displayValue = function (item, val) { var _a; return (_a = val === null || val === void 0 ? void 0 : val.label) !== null && _a !== void 0 ? _a : val === null || val === void 0 ? void 0 : val.caption; });
3660
3678
  o.validate = function (entity, ref) {
3661
3679
  var values = ValueListInfo.get(type).getValues();
3662
3680
  if (ref.value && !values.find(function (v) { return v === ref.value; })) {
@@ -3682,8 +3700,7 @@ var ValueListInfo = /** @class */ (function () {
3682
3700
  s.id = member;
3683
3701
  if (typeof s.id === 'number')
3684
3702
  this.isNumeric = true;
3685
- if (s.caption === undefined)
3686
- s.caption = (0, column_js_1.makeTitle)(s.id !== undefined ? s.id.toString() : member);
3703
+ setLabelAndCaption(s, member);
3687
3704
  this.byIdMap.set(s.id, s);
3688
3705
  this.values.push(s);
3689
3706
  }
@@ -3700,8 +3717,7 @@ var ValueListInfo = /** @class */ (function () {
3700
3717
  (_b = this.values).splice.apply(_b, tslib_1.__spreadArray([0, this.values.length], tslib_1.__read(op.getValues()), false));
3701
3718
  this.byIdMap.clear();
3702
3719
  this.values.forEach(function (s) {
3703
- if (s.caption === undefined && s.id !== undefined)
3704
- s.caption = (0, column_js_1.makeTitle)(s.id);
3720
+ setLabelAndCaption(s, '');
3705
3721
  _this.byIdMap.set(s.id, s);
3706
3722
  });
3707
3723
  }
@@ -3766,6 +3782,16 @@ var ValueListInfo = /** @class */ (function () {
3766
3782
  }());
3767
3783
  exports.ValueListInfo = ValueListInfo;
3768
3784
  var typeCache = new Map();
3785
+ function setLabelAndCaption(s, member) {
3786
+ var _a;
3787
+ var label = (_a = s.label) !== null && _a !== void 0 ? _a : s.caption;
3788
+ if (label === undefined)
3789
+ label = (0, column_js_1.makeTitle)(s.id !== undefined ? s.id.toString() : member);
3790
+ if (s.label === undefined)
3791
+ s.label = label;
3792
+ if (s.caption === undefined)
3793
+ s.caption = label;
3794
+ }
3769
3795
  function getValueList(type) {
3770
3796
  var meta = type === null || type === void 0 ? void 0 : type.metadata;
3771
3797
  if (!meta && (0, isOfType_js_1.isOfType)(type, 'options'))
@@ -198,6 +198,12 @@ export interface EntityMetadata<entityType = unknown> {
198
198
  * @see {@link EntityOptions.caption}
199
199
  */
200
200
  readonly caption: string;
201
+ /** A human readable label for the entity. Can be used to achieve a consistent label for a field throughout the app
202
+ * @example
203
+ * <h1>Create a new item in {taskRepo.metadata.label}</h1>
204
+ * @see {@link EntityOptions.label}
205
+ */
206
+ readonly label: string;
201
207
  /** The name of the table in the database that holds the data for this entity.
202
208
  * If no name is set in the entity options, the `key` will be used instead.
203
209
  * @see {@link EntityOptions.dbName}
@@ -641,7 +647,7 @@ export interface Repository<entityType> {
641
647
  getEntityRef(item: entityType): EntityRef<entityType>;
642
648
  /** Provides information about the fields of the Repository's entity
643
649
  * @example
644
- * console.log(repo.fields.title.caption) // displays the caption of a specific field
650
+ * console.log(repo.fields.title.label) // displays the label of a specific field
645
651
  * console.log(repo.fields.title.options)// writes the options that were defined for this field
646
652
  */
647
653
  fields: FieldsMetadata<entityType>;
@@ -1129,7 +1135,7 @@ export type Paginator<entityType, AggregateResult = EmptyAggregateResult> = {
1129
1135
  * @template matchIdEntity The type used for matching IDs in the relation.
1130
1136
  * @template optionsType The type of find options to apply to the relation (default is FindOptionsBase<toEntity>).
1131
1137
  */
1132
- export interface RelationOptions<fromEntity, toEntity, matchIdEntity, optionsType extends FindOptionsBase<toEntity> = FindOptionsBase<toEntity>> extends Pick<FieldOptions, 'caption'> {
1138
+ export interface RelationOptions<fromEntity, toEntity, matchIdEntity, optionsType extends FindOptionsBase<toEntity> = FindOptionsBase<toEntity>> extends Pick<FieldOptions, 'caption' | 'label'> {
1133
1139
  /**
1134
1140
  * An object specifying custom field names for the relation.
1135
1141
  * Each key represents a field in the related entity, and its value is the corresponding field in the source entity.