@rljson/rljson 0.0.32 → 0.0.34

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.
@@ -23,6 +23,10 @@ export interface Buffet extends Json {
23
23
  */
24
24
  ref: Ref;
25
25
  }>;
26
+ /**
27
+ * An optional ID of the buffet.
28
+ */
29
+ id?: BuffetId;
26
30
  }
27
31
  /**
28
32
  * A table containing buffets
@@ -19,11 +19,11 @@ export interface Cake extends Json {
19
19
  * must match these slice ids of the layers.
20
20
  * The slice ids can be found in the idSet table.
21
21
  */
22
- idSet?: SliceIdsRef;
22
+ sliceIds: SliceIdsRef;
23
23
  /**
24
24
  * The table containing the slice ids of the layer
25
25
  */
26
- sliceIdsTable?: TableKey;
26
+ sliceIdsTable: TableKey;
27
27
  /**
28
28
  * The table containing the slice layers defining the layers
29
29
  */
@@ -34,6 +34,10 @@ export interface Cake extends Json {
34
34
  layers: {
35
35
  [layerId: CakeLayerId]: LayerRef;
36
36
  };
37
+ /**
38
+ * An optional ID of the cake.
39
+ */
40
+ id?: string;
37
41
  }
38
42
  /**
39
43
  * A table containing cakes
@@ -1,7 +1,6 @@
1
- import { Json } from '@rljson/json';
2
1
  import { NutritionalValues } from '../example/bakery-example.ts';
3
2
  import { RljsonTable } from '../rljson.ts';
4
- import { Ref } from '../typedefs.ts';
3
+ import { JsonWithId, Ref } from '../typedefs.ts';
5
4
  /**
6
5
  * A reference to a ingredients row in a ingredients table
7
6
  */
@@ -9,7 +8,7 @@ export type IngredientsRef = Ref;
9
8
  /**
10
9
  * A table containing ingredients
11
10
  */
12
- export type IngredientsTable<T extends Json> = RljsonTable<T, 'ingredients'>;
11
+ export type IngredientsTable<T extends JsonWithId> = RljsonTable<T, 'ingredients'>;
13
12
  /**
14
13
  * Provides an example ingredients table for test purposes
15
14
  */
@@ -19,7 +19,7 @@ export interface Layer extends Json {
19
19
  * The item ids of the layer. If present, the item ids in `assign`
20
20
  * must match these ids. The item id sets can be found in the sliceIds table.
21
21
  */
22
- idSet?: SliceIdsRef;
22
+ sliceIds?: SliceIdsRef;
23
23
  /**
24
24
  * The table containing the item ids of the layer
25
25
  */
@@ -0,0 +1,37 @@
1
+ import { Json } from '@rljson/json';
2
+ import { RljsonTable } from '../rljson.ts';
3
+ import { Ref, TableKey } from '../typedefs.ts';
4
+ /**
5
+ * Describes a revision of a row in a table
6
+ */
7
+ export interface Revision extends Json {
8
+ /**
9
+ * The name of the table the revisione row belongs to
10
+ */
11
+ table: TableKey;
12
+ /**
13
+ * The predecessor of the revision
14
+ */
15
+ predecessor: Ref;
16
+ /**
17
+ * The successor of the revision
18
+ */
19
+ successor: Ref;
20
+ /**
21
+ * The UTC timestamp of the revision
22
+ */
23
+ timestamp: number;
24
+ /**
25
+ * The optional ID of the revisioned element.
26
+ * Can be used get all revisions of a specific ingredient.
27
+ */
28
+ id?: string;
29
+ }
30
+ /**
31
+ * A table containing revisions
32
+ */
33
+ export type RevisionsTable = RljsonTable<Revision, 'ingredients'>;
34
+ /**
35
+ * Example revision object for test purposes
36
+ */
37
+ export declare const exampleRevision: () => Revision;
@@ -9,10 +9,6 @@ export type TableCfgRef = Ref;
9
9
  * A column configuration
10
10
  */
11
11
  export interface ColumnCfg extends Json {
12
- /**
13
- * The key of the column used in data
14
- */
15
- key: ColumnKey;
16
12
  /**
17
13
  * The type of the column
18
14
  */
@@ -43,6 +39,30 @@ export interface TableCfg extends Json {
43
39
  * Needs to be increased when new columns are added.
44
40
  */
45
41
  version: number;
42
+ /**
43
+ * Head tables serve as versioning entry points.
44
+ *
45
+ * - Head tables must contain an id column
46
+ * - Rows in an head table must contain a non-null id
47
+ * - Same row ids must refer to the same physical object
48
+ * - Head tables have no or only one parent table
49
+ */
50
+ isHead: boolean;
51
+ /**
52
+ * Root tables are tables that have no parent table.
53
+ *
54
+ * - Root tables are also head tables
55
+ */
56
+ isRoot: boolean;
57
+ /**
58
+ * Shared tables are tables that are used by multiple parents.
59
+ *
60
+ * - The don't need an id column
61
+ * - Same id can refer to different physical objects
62
+ * - Shared tables can have multiple parents
63
+ * - Shared tables can not be head or root tables
64
+ */
65
+ isShared: boolean;
46
66
  }
47
67
  /**
48
68
  * A table containing columns
package/dist/example.d.ts CHANGED
@@ -23,7 +23,7 @@ export declare class Example {
23
23
  missingReferencedTable: () => Rljson;
24
24
  };
25
25
  tableCfg: {
26
- wrongType: () => import('@rljson/hash').Hashed<Rljson>;
26
+ wrongType: () => Rljson;
27
27
  };
28
28
  layers: {
29
29
  missingBase: () => Rljson;
package/dist/rljson.d.ts CHANGED
@@ -3,6 +3,7 @@ import { BuffetsTable } from './content/buffet.ts';
3
3
  import { CakesTable } from './content/cake.ts';
4
4
  import { IngredientsTable } from './content/ingredients.ts';
5
5
  import { LayersTable } from './content/layer.ts';
6
+ import { RevisionsTable } from './content/revision.ts';
6
7
  import { SliceIdsTable } from './content/slice-ids.ts';
7
8
  import { TableCfgRef, TablesCfgTable } from './content/table-cfg.ts';
8
9
  import { ContentType, Ref, TableKey } from './typedefs.ts';
@@ -11,7 +12,7 @@ export declare const reservedTableKeys: string[];
11
12
  /**
12
13
  * One of the supported Rljson table types
13
14
  */
14
- export type TableType = BuffetsTable | IngredientsTable<any> | LayersTable | SliceIdsTable | CakesTable;
15
+ export type TableType = BuffetsTable | IngredientsTable<any> | LayersTable | SliceIdsTable | CakesTable | RevisionsTable;
15
16
  /** The rljson data format */
16
17
  export interface Rljson extends Json {
17
18
  [tableId: TableKey]: TableType;
package/dist/rljson.js CHANGED
@@ -9,11 +9,20 @@ const bakeryExample = () => {
9
9
  _type: "ingredients",
10
10
  _data: [
11
11
  {
12
+ id: "flour",
12
13
  energy: 364,
13
14
  fat: 0.98,
14
15
  protein: 10.33,
15
16
  carbohydrates: 76.31,
16
17
  _hash: ""
18
+ },
19
+ {
20
+ id: "flour",
21
+ energy: 364.1,
22
+ fat: 0.981,
23
+ protein: 10.331,
24
+ carbohydrates: 76.311,
25
+ _hash: ""
17
26
  }
18
27
  ],
19
28
  _hash: ""
@@ -22,7 +31,7 @@ const bakeryExample = () => {
22
31
  _type: "ingredients",
23
32
  _data: [
24
33
  {
25
- name: "flour",
34
+ id: "flour",
26
35
  amountUnit: "g",
27
36
  nutritionalValuesRef: nutritionalValues._data[0]._hash,
28
37
  _hash: ""
@@ -34,6 +43,7 @@ const bakeryExample = () => {
34
43
  _type: "ingredients",
35
44
  _data: [
36
45
  {
46
+ id: "flour",
37
47
  ingredientsRef: ingredients._data[0]._hash,
38
48
  quantity: 500,
39
49
  _hash: ""
@@ -45,6 +55,7 @@ const bakeryExample = () => {
45
55
  _type: "layers",
46
56
  _data: [
47
57
  {
58
+ id: "tastyCake",
48
59
  ingredientsTable: "recipeIngredients",
49
60
  assign: {
50
61
  flour: recipeIngredients._data[0]._hash
@@ -70,23 +81,21 @@ const bakeryExample = () => {
70
81
  _data: [
71
82
  {
72
83
  add: ["slice0", "slice1"],
73
- remove: [],
74
- _hash: ""
84
+ remove: []
75
85
  }
76
- ],
77
- _hash: ""
86
+ ]
78
87
  });
79
88
  const cakes = hip({
80
89
  _type: "cakes",
81
90
  _data: [
82
91
  {
92
+ id: "cake1",
83
93
  sliceIdsTable: "slices",
84
- idSet: slices._data[0]._hash,
94
+ sliceIds: slices._data[0]._hash,
85
95
  layersTable: "layers",
86
96
  layers: {
87
97
  flour: layers._data[0]._hash
88
- },
89
- _hash: ""
98
+ }
90
99
  }
91
100
  ]
92
101
  });
@@ -94,6 +103,7 @@ const bakeryExample = () => {
94
103
  _type: "buffets",
95
104
  _data: [
96
105
  {
106
+ id: "salesCounter",
97
107
  items: [
98
108
  {
99
109
  table: "cakes",
@@ -156,37 +166,32 @@ __publicField(_Example, "ok", {
156
166
  _hash: "",
157
167
  key: "table",
158
168
  type: "ingredients",
169
+ isHead: false,
170
+ isRoot: false,
171
+ isShared: true,
159
172
  columns: {
160
173
  int: {
161
- key: "int",
162
174
  type: "number"
163
175
  },
164
176
  double: {
165
- key: "double",
166
177
  type: "number"
167
178
  },
168
179
  string: {
169
- key: "string",
170
180
  type: "string"
171
181
  },
172
182
  boolean: {
173
- key: "boolean",
174
183
  type: "boolean"
175
184
  },
176
185
  null: {
177
- key: "null",
178
186
  type: "null"
179
187
  },
180
188
  jsonArray: {
181
- key: "jsonArray",
182
189
  type: "jsonArray"
183
190
  },
184
191
  json: {
185
- key: "json",
186
192
  type: "json"
187
193
  },
188
194
  jsonValue: {
189
- key: "jsonValue",
190
195
  type: "jsonValue"
191
196
  }
192
197
  }
@@ -274,14 +279,14 @@ __publicField(_Example, "ok", {
274
279
  const ingredient1 = ingredients._data[1];
275
280
  const layer0 = hip({
276
281
  sliceIdsTable: "sliceIds",
277
- idSet: "MgHRBYSrhpyl4rvsOmAWcQ",
282
+ sliceIds: "MgHRBYSrhpyl4rvsOmAWcQ",
278
283
  ingredientsTable: "ingredients",
279
284
  assign: {}
280
285
  });
281
286
  const layer1 = hip({
282
287
  base: layer0._hash,
283
288
  sliceIdsTable: "sliceIds",
284
- idSet: "MgHRBYSrhpyl4rvsOmAWcQ",
289
+ sliceIds: "MgHRBYSrhpyl4rvsOmAWcQ",
285
290
  ingredientsTable: "ingredients",
286
291
  assign: {
287
292
  id0: ingredient0._hash,
@@ -294,7 +299,7 @@ __publicField(_Example, "ok", {
294
299
  });
295
300
  const cake = hip({
296
301
  sliceIdsTable: "sliceIds",
297
- idSet: sliceIds._data[0]._hash,
302
+ sliceIds: sliceIds._data[0]._hash,
298
303
  layersTable: "layers",
299
304
  layers: {
300
305
  layer0: layer0._hash,
@@ -399,7 +404,10 @@ __publicField(_Example, "broken", {
399
404
  const result = _Example.ok.singleRow();
400
405
  const tableCfg = result.tableCfgs._data[0];
401
406
  tableCfg.columns["int"].type = "numberBroken";
402
- return hip(result, true, false);
407
+ return hip(result, {
408
+ updateExistingHashes: true,
409
+ throwOnWrongHashes: false
410
+ });
403
411
  }
404
412
  },
405
413
  layers: {
@@ -407,13 +415,19 @@ __publicField(_Example, "broken", {
407
415
  const result = _Example.ok.complete();
408
416
  const layer1 = result.layers._data[1];
409
417
  layer1.base = "MISSING";
410
- return hip(result, true, false);
418
+ return hip(result, {
419
+ updateExistingHashes: true,
420
+ throwOnWrongHashes: false
421
+ });
411
422
  },
412
423
  missingSliceIdSet: () => {
413
424
  const result = _Example.ok.complete();
414
425
  const layer1 = result.layers._data[1];
415
- layer1.idSet = "MISSING1";
416
- return hip(result, true, false);
426
+ layer1.sliceIds = "MISSING1";
427
+ return hip(result, {
428
+ updateExistingHashes: true,
429
+ throwOnWrongHashes: false
430
+ });
417
431
  },
418
432
  missingAssignedIngredientTable: () => {
419
433
  const result = _Example.ok.complete();
@@ -423,27 +437,39 @@ __publicField(_Example, "broken", {
423
437
  missingAssignedIngredient: () => {
424
438
  const result = _Example.ok.complete();
425
439
  result.ingredients._data.splice(1, 2);
426
- return hip(result, true, false);
440
+ return hip(result, {
441
+ updateExistingHashes: true,
442
+ throwOnWrongHashes: false
443
+ });
427
444
  }
428
445
  },
429
446
  cakes: {
430
447
  missingSliceIdSet: () => {
431
448
  const result = _Example.ok.complete();
432
- result.cakes._data[0].idSet = "MISSING";
433
- hip(result.cakes, true, false);
449
+ result.cakes._data[0].sliceIds = "MISSING";
450
+ hip(result.cakes, {
451
+ updateExistingHashes: true,
452
+ throwOnWrongHashes: false
453
+ });
434
454
  return result;
435
455
  },
436
456
  missingLayersTable: () => {
437
457
  const result = _Example.ok.complete();
438
458
  result.cakes._data[0].layersTable = "MISSING";
439
- hip(result.cakes, true, false);
459
+ hip(result.cakes, {
460
+ updateExistingHashes: true,
461
+ throwOnWrongHashes: false
462
+ });
440
463
  return result;
441
464
  },
442
465
  missingCakeLayer: () => {
443
466
  const result = _Example.ok.complete();
444
467
  result.cakes._data[0].layers["layer0"] = "MISSING0";
445
468
  result.cakes._data[0].layers["layer1"] = "MISSING1";
446
- hip(result.cakes, true, false);
469
+ hip(result.cakes, {
470
+ updateExistingHashes: true,
471
+ throwOnWrongHashes: false
472
+ });
447
473
  return result;
448
474
  }
449
475
  },
@@ -453,7 +479,7 @@ __publicField(_Example, "broken", {
453
479
  const buffet = result.buffets._data[0];
454
480
  buffet.items[0].table = "MISSING0";
455
481
  buffet.items[1].table = "MISSING1";
456
- hip(result, true, false);
482
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
457
483
  return result;
458
484
  },
459
485
  missingItems: () => {
@@ -461,7 +487,7 @@ __publicField(_Example, "broken", {
461
487
  const buffet = result.buffets._data[0];
462
488
  buffet.items[0].ref = "MISSING0";
463
489
  buffet.items[1].ref = "MISSING1";
464
- hip(result, true, false);
490
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
465
491
  return result;
466
492
  }
467
493
  }
@@ -475,15 +501,16 @@ const exampleTableCfg = (tableCfg = void 0) => {
475
501
  version: 1,
476
502
  columns: (tableCfg == null ? void 0 : tableCfg.columns) ?? {
477
503
  a: {
478
- key: "a",
479
504
  type: "string"
480
505
  },
481
506
  b: {
482
- key: "b",
483
507
  type: "number"
484
508
  }
485
509
  },
486
- type: (tableCfg == null ? void 0 : tableCfg.type) ?? "ingredients"
510
+ type: (tableCfg == null ? void 0 : tableCfg.type) ?? "ingredients",
511
+ isHead: true,
512
+ isRoot: true,
513
+ isShared: false
487
514
  };
488
515
  };
489
516
  // @license
@@ -511,7 +538,13 @@ const rljsonIndexed = (rljson) => {
511
538
  };
512
539
  // @license
513
540
  const reservedFieldNames = ["_type", "_data"];
514
- const reservedTableKeys = ["_hash", "sliceIds", "tableCfgs"];
541
+ const reservedTableKeys = [
542
+ "_hash",
543
+ "sliceIds",
544
+ "tableCfgs",
545
+ "reverseRefs",
546
+ "revisions"
547
+ ];
515
548
  const exampleRljson = () => Example.ok.singleRow();
516
549
  const iterateTables = (rljson, callback) => {
517
550
  for (const tableKey in rljson) {
@@ -587,6 +620,8 @@ class _BaseValidator {
587
620
  () => this._missingColumnConfigs(),
588
621
  () => this._dataDoesNotMatchColumnConfig(),
589
622
  () => this._tableTypesDoNotMatch(),
623
+ () => this._tableCfgHasRootHeadSharedError(),
624
+ () => this._rootOrHeadTableHasNoIdColumn(),
590
625
  // Check references
591
626
  () => this._refsNotFound(),
592
627
  // Check layers
@@ -893,6 +928,76 @@ class _BaseValidator {
893
928
  }
894
929
  }
895
930
  // ...........................................................................
931
+ _tableCfgHasRootHeadSharedError() {
932
+ const rljson = this.rljson;
933
+ const inconsistentTableCfgs = [];
934
+ for (const tableKey of this.tableKeys) {
935
+ const table = rljson[tableKey];
936
+ const cfgRef = table._tableCfg;
937
+ if (!cfgRef) {
938
+ continue;
939
+ }
940
+ const cfg = this.rljsonIndexed.tableCfgs._data[cfgRef];
941
+ const { isRoot, isHead, isShared } = cfg;
942
+ if (isShared && (isRoot || isHead)) {
943
+ inconsistentTableCfgs.push({
944
+ error: "Tables with isShared = true must have isRoot = false and isHead = false",
945
+ table: tableKey,
946
+ tableCfg: cfgRef
947
+ });
948
+ } else if (isRoot && !isHead) {
949
+ inconsistentTableCfgs.push({
950
+ error: "Tables with isRoot = true must also have isHead = true",
951
+ table: tableKey,
952
+ tableCfg: cfgRef
953
+ });
954
+ } else if (!isRoot && !isHead && !isShared) {
955
+ inconsistentTableCfgs.push({
956
+ error: "Tables must be either root, root+head or shared",
957
+ table: tableKey,
958
+ tableCfg: cfgRef
959
+ });
960
+ }
961
+ }
962
+ if (inconsistentTableCfgs.length > 0) {
963
+ this.errors.tableCfgHasRootHeadSharedError = {
964
+ error: "Table configs have inconsistent root/head/shared settings",
965
+ tables: inconsistentTableCfgs
966
+ };
967
+ }
968
+ }
969
+ // ...........................................................................
970
+ _rootOrHeadTableHasNoIdColumn() {
971
+ const rljson = this.rljson;
972
+ const rootOrHeadTablesWithoutIdColumns = [];
973
+ for (const tableKey of this.tableKeys) {
974
+ const table = rljson[tableKey];
975
+ const cfgRef = table._tableCfg;
976
+ if (!cfgRef) {
977
+ continue;
978
+ }
979
+ const cfg = this.rljsonIndexed.tableCfgs._data[cfgRef];
980
+ const isRootOrHeadTable = cfg.isRoot || cfg.isHead;
981
+ if (!isRootOrHeadTable) {
982
+ continue;
983
+ }
984
+ const columns = cfg.columns;
985
+ const idField = columns["id"];
986
+ if (!idField) {
987
+ rootOrHeadTablesWithoutIdColumns.push({
988
+ table: tableKey,
989
+ tableCfg: cfgRef
990
+ });
991
+ }
992
+ }
993
+ if (rootOrHeadTablesWithoutIdColumns.length > 0) {
994
+ this.errors.rootOrHeadTableHasNoIdColumn = {
995
+ error: "Root or head tables must have an id column",
996
+ tables: rootOrHeadTablesWithoutIdColumns
997
+ };
998
+ }
999
+ }
1000
+ // ...........................................................................
896
1001
  _dataHasWrongType() {
897
1002
  const rljson = this.rljson;
898
1003
  const tablesWithWrongType = [];
@@ -1043,7 +1148,7 @@ class _BaseValidator {
1043
1148
  }
1044
1149
  const layersTable = table;
1045
1150
  for (const layer of layersTable._data) {
1046
- const idSetRef = layer.idSet;
1151
+ const idSetRef = layer.sliceIds;
1047
1152
  if (!idSetRef) {
1048
1153
  continue;
1049
1154
  }
@@ -1124,16 +1229,16 @@ class _BaseValidator {
1124
1229
  }
1125
1230
  const cakesTable = table;
1126
1231
  for (const cake of cakesTable._data) {
1127
- const sliceIdsRef = cake.sliceIdsTable;
1128
- if (!sliceIdsRef) {
1232
+ const sliceIdsTableName = cake.sliceIdsTable;
1233
+ if (!sliceIdsTableName) {
1129
1234
  continue;
1130
1235
  }
1131
- const sliceIds = this.rljsonIndexed[sliceIdsRef];
1132
- if (!sliceIds) {
1236
+ const sliceIdsTable = this.rljsonIndexed[sliceIdsTableName];
1237
+ if (!sliceIdsTable) {
1133
1238
  brokenCakes.push({
1134
1239
  cakeTable: tableKey,
1135
1240
  brokenCake: cake._hash,
1136
- missingSliceIds: sliceIdsRef
1241
+ missingSliceIdsTable: sliceIdsTableName
1137
1242
  });
1138
1243
  }
1139
1244
  }
@@ -1153,18 +1258,18 @@ class _BaseValidator {
1153
1258
  }
1154
1259
  const cakesTable = table;
1155
1260
  for (const cake of cakesTable._data) {
1156
- const idSetRef = cake.idSet;
1157
- if (!idSetRef) {
1261
+ const sliceIdsRef = cake.sliceIds;
1262
+ if (!sliceIdsRef) {
1158
1263
  continue;
1159
1264
  }
1160
- const sliceIdsRef = cake.sliceIdsTable;
1161
- const sliceIds = this.rljsonIndexed[sliceIdsRef];
1162
- const idSet = sliceIds._data[idSetRef];
1163
- if (!idSet) {
1265
+ const sliceIdsTableName = cake.sliceIdsTable;
1266
+ const sliceIdsTable = this.rljsonIndexed[sliceIdsTableName];
1267
+ const sliceIds = sliceIdsTable._data[sliceIdsRef];
1268
+ if (!sliceIds) {
1164
1269
  brokenCakes.push({
1165
1270
  cakeTable: tableKey,
1166
1271
  brokenCake: cake._hash,
1167
- missingSliceIds: idSetRef
1272
+ missingSliceIds: sliceIdsRef
1168
1273
  });
1169
1274
  }
1170
1275
  }
@@ -49,37 +49,32 @@ export class Example {
49
49
  _hash: '',
50
50
  key: 'table',
51
51
  type: 'ingredients',
52
+ isHead: false,
53
+ isRoot: false,
54
+ isShared: true,
52
55
  columns: {
53
56
  int: {
54
- key: 'int',
55
57
  type: 'number',
56
58
  },
57
59
  double: {
58
- key: 'double',
59
60
  type: 'number',
60
61
  },
61
62
  string: {
62
- key: 'string',
63
63
  type: 'string',
64
64
  },
65
65
  boolean: {
66
- key: 'boolean',
67
66
  type: 'boolean',
68
67
  },
69
68
  null: {
70
- key: 'null',
71
69
  type: 'null',
72
70
  },
73
71
  jsonArray: {
74
- key: 'jsonArray',
75
72
  type: 'jsonArray',
76
73
  },
77
74
  json: {
78
- key: 'json',
79
75
  type: 'json',
80
76
  },
81
77
  jsonValue: {
82
- key: 'jsonValue',
83
78
  type: 'jsonValue',
84
79
  },
85
80
  },
@@ -174,7 +169,7 @@ export class Example {
174
169
 
175
170
  const layer0: Layer = hip({
176
171
  sliceIdsTable: 'sliceIds',
177
- idSet: 'MgHRBYSrhpyl4rvsOmAWcQ',
172
+ sliceIds: 'MgHRBYSrhpyl4rvsOmAWcQ',
178
173
  ingredientsTable: 'ingredients',
179
174
  assign: {},
180
175
  });
@@ -182,7 +177,7 @@ export class Example {
182
177
  const layer1: Layer = hip({
183
178
  base: layer0._hash as string,
184
179
  sliceIdsTable: 'sliceIds',
185
- idSet: 'MgHRBYSrhpyl4rvsOmAWcQ',
180
+ sliceIds: 'MgHRBYSrhpyl4rvsOmAWcQ',
186
181
  ingredientsTable: 'ingredients',
187
182
  assign: {
188
183
  id0: ingredient0._hash,
@@ -197,7 +192,7 @@ export class Example {
197
192
 
198
193
  const cake: Cake = hip({
199
194
  sliceIdsTable: 'sliceIds',
200
- idSet: sliceIds._data[0]._hash as string,
195
+ sliceIds: sliceIds._data[0]._hash as string,
201
196
  layersTable: 'layers',
202
197
  layers: {
203
198
  layer0: layer0._hash as string,
@@ -309,7 +304,10 @@ export class Example {
309
304
  const result = Example.ok.singleRow();
310
305
  const tableCfg = result.tableCfgs._data[0];
311
306
  tableCfg.columns['int'].type = 'numberBroken'; // Break one of the types
312
- return hip(result, true, false);
307
+ return hip(result, {
308
+ updateExistingHashes: true,
309
+ throwOnWrongHashes: false,
310
+ });
313
311
  },
314
312
  },
315
313
 
@@ -320,17 +318,23 @@ export class Example {
320
318
  layer1.base = 'MISSING'; // Missing base
321
319
 
322
320
  // Recalculate hashes
323
- return hip(result, true, false);
321
+ return hip(result, {
322
+ updateExistingHashes: true,
323
+ throwOnWrongHashes: false,
324
+ });
324
325
  },
325
326
 
326
327
  missingSliceIdSet: (): Rljson => {
327
328
  const result = Example.ok.complete();
328
329
  const layer1 = result.layers._data[1];
329
330
 
330
- layer1.idSet = 'MISSING1';
331
+ layer1.sliceIds = 'MISSING1';
331
332
 
332
333
  // Recalculate hashes
333
- return hip(result, true, false);
334
+ return hip(result, {
335
+ updateExistingHashes: true,
336
+ throwOnWrongHashes: false,
337
+ });
334
338
  },
335
339
 
336
340
  missingAssignedIngredientTable: (): Rljson => {
@@ -342,22 +346,31 @@ export class Example {
342
346
  missingAssignedIngredient: (): Rljson => {
343
347
  const result = Example.ok.complete();
344
348
  result.ingredients._data.splice(1, 2); // Remove an ingredient that is assigned
345
- return hip(result, true, false);
349
+ return hip(result, {
350
+ updateExistingHashes: true,
351
+ throwOnWrongHashes: false,
352
+ });
346
353
  },
347
354
  },
348
355
 
349
356
  cakes: {
350
357
  missingSliceIdSet: (): Rljson => {
351
358
  const result = Example.ok.complete();
352
- result.cakes._data[0].idSet = 'MISSING'; // Missing ID set
353
- hip(result.cakes, true, false);
359
+ result.cakes._data[0].sliceIds = 'MISSING'; // Missing ID set
360
+ hip(result.cakes, {
361
+ updateExistingHashes: true,
362
+ throwOnWrongHashes: false,
363
+ });
354
364
  return result;
355
365
  },
356
366
 
357
367
  missingLayersTable: (): Rljson => {
358
368
  const result = Example.ok.complete();
359
369
  result.cakes._data[0].layersTable = 'MISSING'; // Missing layers table
360
- hip(result.cakes, true, false);
370
+ hip(result.cakes, {
371
+ updateExistingHashes: true,
372
+ throwOnWrongHashes: false,
373
+ });
361
374
  return result;
362
375
  },
363
376
 
@@ -365,7 +378,10 @@ export class Example {
365
378
  const result = Example.ok.complete();
366
379
  result.cakes._data[0].layers['layer0'] = 'MISSING0';
367
380
  result.cakes._data[0].layers['layer1'] = 'MISSING1';
368
- hip(result.cakes, true, false);
381
+ hip(result.cakes, {
382
+ updateExistingHashes: true,
383
+ throwOnWrongHashes: false,
384
+ });
369
385
  return result;
370
386
  },
371
387
  },
@@ -376,7 +392,7 @@ export class Example {
376
392
  const buffet = result.buffets._data[0];
377
393
  buffet.items[0].table = 'MISSING0';
378
394
  buffet.items[1].table = 'MISSING1';
379
- hip(result, true, false);
395
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
380
396
  return result;
381
397
  },
382
398
 
@@ -385,7 +401,7 @@ export class Example {
385
401
  const buffet = result.buffets._data[0];
386
402
  buffet.items[0].ref = 'MISSING0';
387
403
  buffet.items[1].ref = 'MISSING1';
388
- hip(result, true, false);
404
+ hip(result, { updateExistingHashes: true, throwOnWrongHashes: false });
389
405
  return result;
390
406
  },
391
407
  },
@@ -1,4 +1,4 @@
1
- import { JsonKey } from '@rljson/json';
1
+ import { Json, JsonKey } from '@rljson/json';
2
2
  /**
3
3
  * A ref is a hash that references to another element
4
4
  */
@@ -37,3 +37,9 @@ export declare const exampleTypedefs: () => {
37
37
  tableKey: TableKey;
38
38
  contentType: ContentType;
39
39
  };
40
+ /**
41
+ * A json object with an optional id
42
+ */
43
+ export type JsonWithId = Json & {
44
+ id?: string;
45
+ };
@@ -16,6 +16,8 @@ export interface BaseErrors extends Errors {
16
16
  columnConfigNotFound?: Json;
17
17
  dataDoesNotMatchColumnConfig?: Json;
18
18
  tableTypesDoNotMatch?: Json;
19
+ rootOrHeadTableHasNoIdColumn?: Json;
20
+ tableCfgHasRootHeadSharedError?: Json;
19
21
  refsNotFound?: Json;
20
22
  layerBasesNotFound?: Json;
21
23
  layerSliceIdsTableNotFound?: Json;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/rljson",
3
- "version": "0.0.32",
3
+ "version": "0.0.34",
4
4
  "packageManager": "pnpm@10.6.3",
5
5
  "description": "The RLJSON data format specification",
6
6
  "homepage": "https://github.com/rljson/rljson",
@@ -29,10 +29,10 @@
29
29
  "updateGoldens": "cross-env UPDATE_GOLDENS=true npm test"
30
30
  },
31
31
  "devDependencies": {
32
- "@types/node": "^22.13.13",
33
- "@typescript-eslint/eslint-plugin": "^8.28.0",
34
- "@typescript-eslint/parser": "^8.28.0",
35
- "@vitest/coverage-v8": "^3.0.9",
32
+ "@types/node": "^22.13.17",
33
+ "@typescript-eslint/eslint-plugin": "^8.29.0",
34
+ "@typescript-eslint/parser": "^8.29.0",
35
+ "@vitest/coverage-v8": "^3.1.1",
36
36
  "cross-env": "^7.0.3",
37
37
  "eslint": "^9.23.0",
38
38
  "eslint-plugin-jsdoc": "^50.6.9",
@@ -41,16 +41,16 @@
41
41
  "jsdoc": "^4.0.4",
42
42
  "read-pkg": "^9.0.1",
43
43
  "typescript": "~5.8.2",
44
- "typescript-eslint": "^8.28.0",
45
- "vite": "^6.2.3",
46
- "vite-node": "^3.0.9",
44
+ "typescript-eslint": "^8.29.0",
45
+ "vite": "^6.2.4",
46
+ "vite-node": "^3.1.1",
47
47
  "vite-plugin-dts": "^4.5.3",
48
48
  "vite-tsconfig-paths": "^5.1.4",
49
- "vitest": "^3.0.9",
49
+ "vitest": "^3.1.1",
50
50
  "vitest-dom": "^0.1.1"
51
51
  },
52
52
  "dependencies": {
53
- "@rljson/hash": "^0.0.12",
53
+ "@rljson/hash": "^0.0.13",
54
54
  "@rljson/json": "^0.0.18"
55
55
  },
56
56
  "pnpm": {