@cepharum/concrete-db 0.2.1 → 0.3.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.
package/concrete-db.d.ts CHANGED
@@ -1,32 +1,4 @@
1
- /**
2
- * (c) 2022 cepharum GmbH, Berlin, http://cepharum.de
3
- *
4
- * The MIT License (MIT)
5
- *
6
- * Copyright (c) 2021 cepharum GmbH
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
25
- *
26
- * @author: cepharum
27
- */
28
-
29
- declare module "concrete-db" {
1
+ declare namespace ConcreteDB {
30
2
  export interface CuringOptions extends CollectorOptions, ShaperOptions, GeneratorOptions {
31
3
  /**
32
4
  * Selects base folder for writing files of resulting concrete-db.
@@ -260,18 +232,34 @@ declare module "concrete-db" {
260
232
  */
261
233
  export type ShapeCollections = ShapeCollection[];
262
234
 
235
+ /**
236
+ * Defines optional constraints to apply.
237
+ */
238
+ export interface ShapeConstraints {
239
+ /**
240
+ * If set, multiple source records addressing same target record aren't
241
+ * merged, but some exception is thrown.
242
+ *
243
+ * This doesn't affect definition of variants. However, merging single
244
+ * variant from multiple sources is rejected, too.
245
+ */
246
+ singleSource?: boolean;
247
+ }
248
+
263
249
  /**
264
250
  * Describes rules controlling shaping of a model.
265
251
  */
266
252
  export interface ShapeModel {
267
253
  defaults: ShapePropertyDefaults;
268
- properties: ShapeProperties;
269
- collections: ShapeCollections;
270
- contributions: {
254
+ properties?: ShapeProperties;
255
+ collections?: ShapeCollections;
256
+ contributions?: {
271
257
  [contributedModelName: string]: {
272
258
  [targetPropertyName: string]: string;
273
259
  };
274
260
  };
261
+
262
+ constraints?: ShapeConstraints;
275
263
  }
276
264
 
277
265
  export interface Shape {
package/lib/shaper.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  // noinspection ExceptionCaughtLocallyJS
2
+ /* eslint-disable no-await-in-loop */
2
3
 
3
4
  import EventEmitter from "events";
4
5
 
@@ -50,16 +51,17 @@ export class Shaper extends EventEmitter {
50
51
  * @param {Shape[]} localShapes local shapes of folders records have been collected from
51
52
  * @returns {Database} resulting database records
52
53
  */
53
- transform( recordsCollection, localShapes ) {
54
+ async transform( recordsCollection, localShapes ) {
54
55
  if ( recordsCollection.size > 0 && !localShapes?.length ) {
55
56
  throw new Error( "invalid use of Shaper: missing list of local shapes per folder records have been collected from" );
56
57
  }
57
58
 
58
59
  const mergedLocalShapes = merge( {}, DefaultShape, ...localShapes );
59
- const models = this.handleContributions( this.groupByModel( recordsCollection ), mergedLocalShapes );
60
+ const grouped = await this.groupByModel( recordsCollection );
61
+ const models = await this.handleContributions( grouped, mergedLocalShapes );
60
62
  const endpoints = {};
61
63
 
62
- this.populateModels( endpoints, models, mergedLocalShapes );
64
+ await this.populateModels( endpoints, models, mergedLocalShapes );
63
65
 
64
66
  return { prefix: this.prefix, endpoints };
65
67
  }
@@ -70,7 +72,7 @@ export class Shaper extends EventEmitter {
70
72
  * @param {Map<string,CollectedRecord[]>} collectedRecordsByName collection of records to transform
71
73
  * @returns {Object<string,Object<string, ModelItem>>} provided records grouped by model and unique item ID
72
74
  */
73
- groupByModel( collectedRecordsByName ) {
75
+ async groupByModel( collectedRecordsByName ) {
74
76
  const globalItemsPerModel = {};
75
77
  let index = 0;
76
78
 
@@ -83,7 +85,7 @@ export class Shaper extends EventEmitter {
83
85
  process.stderr.write( `\r[${++index}/${collectedRecordsByName.size}]` );
84
86
  }
85
87
 
86
- this.compileRecords( globalItemsPerModel, records );
88
+ await this.compileRecords( globalItemsPerModel, records );
87
89
  }
88
90
 
89
91
  return globalItemsPerModel;
@@ -97,20 +99,20 @@ export class Shaper extends EventEmitter {
97
99
  * @param {Shape} mergedLocalShapes local shapes of source folders merged in order of collecting records
98
100
  * @returns {Object<string,Object<string, CollectedRecord[]>>} collections of items per model as provided
99
101
  */
100
- handleContributions( globalItemsPerModel, mergedLocalShapes ) {
102
+ async handleContributions( globalItemsPerModel, mergedLocalShapes ) {
101
103
  const postProcessingQueue = new Set();
102
104
 
103
105
  if ( this.options.verbose ) {
104
106
  console.error( `\nprocessing contributions ...` );
105
107
  }
106
108
 
107
- this.processContributions( globalItemsPerModel, postProcessingQueue, mergedLocalShapes );
109
+ await this.processContributions( globalItemsPerModel, postProcessingQueue, mergedLocalShapes );
108
110
 
109
111
  if ( this.options.verbose ) {
110
112
  console.error( `post-processing ${postProcessingQueue.size} contributions` );
111
113
  }
112
114
 
113
- this.recompileContributionTargets( globalItemsPerModel, postProcessingQueue );
115
+ await this.recompileContributionTargets( globalItemsPerModel, postProcessingQueue );
114
116
 
115
117
  return globalItemsPerModel;
116
118
  }
@@ -123,11 +125,11 @@ export class Shaper extends EventEmitter {
123
125
  * @param {CollectedRecord[]} records list of records collected from a source
124
126
  * @returns {Object<string,Object<string,ModelItem>>} compiled items grouped by model, addressable by either item's ID
125
127
  */
126
- compileRecords( itemsPerModel, records ) {
128
+ async compileRecords( itemsPerModel, records ) {
127
129
  const shapesPerModelCache = {};
128
130
 
129
131
  for ( let read = 0, numRecords = records.length; read < numRecords; read++ ) {
130
- const item = this.compileModelItemFromRecord( shapesPerModelCache, itemsPerModel, records[read] );
132
+ const item = await this.compileModelItemFromRecord( shapesPerModelCache, itemsPerModel, records[read] );
131
133
  const modelPool = itemsPerModel[item.$model];
132
134
 
133
135
  if ( item.$variantId == null ) {
@@ -154,9 +156,9 @@ export class Shaper extends EventEmitter {
154
156
  * @param {Object<string,ShapeModel>} shapesPerModelCache caches per-model shapes compiled before
155
157
  * @param {Object<string,Object<string,Object>>} itemsPerModel collection of previously compiled items per model
156
158
  * @param {CollectedRecord} record augmented data collected from a source to be compiled
157
- * @returns {object} instance of model with hidden meta information injected
159
+ * @returns {Promise<ModelItem>} instance of model with hidden meta information injected
158
160
  */
159
- compileModelItemFromRecord( shapesPerModelCache, itemsPerModel, record ) {
161
+ async compileModelItemFromRecord( shapesPerModelCache, itemsPerModel, record ) {
160
162
  const { segments, shape, data } = record;
161
163
 
162
164
  const metaProperties = {
@@ -165,9 +167,9 @@ export class Shaper extends EventEmitter {
165
167
 
166
168
  const augmentedData = augmentDataSpace( data, metaProperties );
167
169
 
168
- metaProperties.$model = this.detectModel( augmentedData, shape );
169
- metaProperties.$shape = this.getShapeOfModel( {}, shape, metaProperties.$model );
170
- metaProperties.$id = this.identifyRecord( augmentedData, metaProperties.$shape );
170
+ metaProperties.$model = await this.detectModel( augmentedData, shape );
171
+ metaProperties.$shape = this.getShapeOfModel( shapesPerModelCache, shape, metaProperties.$model );
172
+ metaProperties.$id = await this.identifyRecord( augmentedData, metaProperties.$shape );
171
173
 
172
174
  if ( !itemsPerModel.hasOwnProperty( metaProperties.$model ) ) {
173
175
  // eslint-disable-next-line no-param-reassign
@@ -177,7 +179,7 @@ export class Shaper extends EventEmitter {
177
179
  const model = itemsPerModel[metaProperties.$model];
178
180
 
179
181
  const { properties, defaults } = metaProperties.$shape;
180
- const item = this.compileItem( augmentedData, properties, model[metaProperties.$id] ? {} : defaults );
182
+ const item = await this.compileItem( augmentedData, properties, model[metaProperties.$id] ? {} : defaults );
181
183
 
182
184
  Object.defineProperties( item, {
183
185
  $segments: { value: segments },
@@ -185,7 +187,7 @@ export class Shaper extends EventEmitter {
185
187
  $shape: { value: metaProperties.$shape, configurable: true },
186
188
  $model: { value: metaProperties.$model },
187
189
  $id: { value: metaProperties.$id },
188
- $variantId: { value: this.computeVariantIdOfItem( metaProperties.$shape.properties.$variant, augmentedData ) },
190
+ $variantId: { value: await this.computeVariantIdOfItem( metaProperties.$shape.properties.$variant, augmentedData ) },
189
191
  } );
190
192
 
191
193
  return item;
@@ -200,9 +202,9 @@ export class Shaper extends EventEmitter {
200
202
  * @param {ModelItem} item previously compiled item to re-compile
201
203
  * @returns {ModelItem} re-compiled item
202
204
  */
203
- recompileItem( item ) {
205
+ async recompileItem( item ) {
204
206
  const data = augmentDataSpace( merge( {}, item.$original, item ), { ...item, $post: true } );
205
- const updatedItem = this.compileItem( data, item.$shape.properties, {} );
207
+ const updatedItem = await this.compileItem( data, item.$shape.properties, {} );
206
208
 
207
209
  Object.defineProperties( updatedItem, {
208
210
  $segments: { value: item.$segments },
@@ -221,9 +223,9 @@ export class Shaper extends EventEmitter {
221
223
  *
222
224
  * @param {string?} term term expressing computation of variant ID
223
225
  * @param {ModelItem} item an item to get variant ID for
224
- * @returns {null|any} computed variant ID of provided item, nullish if item is not a variant
226
+ * @returns {Promise<null|any>} computed variant ID of provided item, nullish if item is not a variant
225
227
  */
226
- computeVariantIdOfItem( term, item ) {
228
+ async computeVariantIdOfItem( term, item ) {
227
229
  if ( term == null ) {
228
230
  return null;
229
231
  }
@@ -232,7 +234,7 @@ export class Shaper extends EventEmitter {
232
234
  const data = augmentDataSpace( merge( {}, item.$original, item ), item );
233
235
 
234
236
  try {
235
- const value = Compiler.compile( String( term ), this.termFunctions, this.termsCache )( data );
237
+ const value = await Compiler.compile( String( term ), this.termFunctions, this.termsCache )( data );
236
238
 
237
239
  // support processed term requesting to fail computation of variant ID
238
240
  if ( value instanceof Error ) {
@@ -354,7 +356,7 @@ export class Shaper extends EventEmitter {
354
356
  * @param {Shape} mergedLocalShapes local shapes of source folders merged in order of collecting records
355
357
  * @returns {void}
356
358
  */
357
- processContributions( itemsPerModel, contributedItems, mergedLocalShapes ) {
359
+ async processContributions( itemsPerModel, contributedItems, mergedLocalShapes ) {
358
360
  const contributingModels = this.listContributingModels( itemsPerModel );
359
361
  const shapePerModelCache = {};
360
362
 
@@ -427,7 +429,7 @@ export class Shaper extends EventEmitter {
427
429
  };
428
430
 
429
431
  const augmentedData = augmentDataSpace( item, contributionMeta );
430
- const targetId = this.computeId( contributionTerms.$id, augmentedData );
432
+ const targetId = await this.computeId( contributionTerms.$id, augmentedData );
431
433
 
432
434
  if ( !isOptionalContribution && ( !targetId || ( Array.isArray( targetId ) && !targetId.length ) ) ) {
433
435
  console.warn( `ignoring contribution of record #${item.$id} in model ${item.$model} to model ${targetModelName} due to lack of target ID` ); // eslint-disable-line max-len
@@ -446,7 +448,7 @@ export class Shaper extends EventEmitter {
446
448
 
447
449
 
448
450
  // try computing variant ID based on contributing item
449
- const variantId = this.computeVariantIdOfItem( contributionTerms.$variant, {
451
+ const variantId = await this.computeVariantIdOfItem( contributionTerms.$variant, {
450
452
  ...item,
451
453
  $segments: item.$segments,
452
454
  $original: item.$original,
@@ -499,7 +501,7 @@ export class Shaper extends EventEmitter {
499
501
 
500
502
  // compile actual properties of contribution
501
503
  const contributionDefaults = targetItemExists || variantId != null ? {} : targetModelShape.defaults;
502
- const contribution = this.compileItem( augmentedData, contributionTerms, contributionDefaults );
504
+ const contribution = await this.compileItem( augmentedData, contributionTerms, contributionDefaults );
503
505
 
504
506
 
505
507
  // merge this item's contribution with existing
@@ -551,6 +553,10 @@ export class Shaper extends EventEmitter {
551
553
  * @returns {ModelItem} provided target
552
554
  */
553
555
  mergeModelItem( target, source ) {
556
+ if ( target?.$shape?.constraints?.singleSource ) {
557
+ throw new Error( `merging ${target.$model} with ID ${target.$id} from multiple source records rejected by shape` );
558
+ }
559
+
554
560
  const _to = target || {};
555
561
  const oldNames = target ? Object.keys( _to.$shape.properties ) : [];
556
562
  const newNames = Object.keys( source.$shape.properties );
@@ -558,8 +564,8 @@ export class Shaper extends EventEmitter {
558
564
  // merge properties of items
559
565
  for ( const name of Object.keys( source ) ) {
560
566
  if ( !String( name ).startsWith( "$" ) ) {
561
- const wasCollecting = oldNames.some( n => n.replace( /\s*\[]$/, "" ).trim() === name );
562
- const isCollecting = newNames.some( n => n.replace( /\s*\[]$/, "" ).trim() === name );
567
+ const wasCollecting = oldNames.some( n => n.replace( /\s+/g, "" ) === name + "[]" );
568
+ const isCollecting = newNames.some( n => n.replace( /\s+/g, "" ) === name + "[]" );
563
569
 
564
570
  if ( _to.hasOwnProperty( name ) ) {
565
571
  if ( isCollecting ) {
@@ -610,7 +616,7 @@ export class Shaper extends EventEmitter {
610
616
  * @param {Set<string>} contributions lists IDs of items or their variants that have been contributed to
611
617
  * @returns {Object<string,Object<string,ModelItem>>} pool of items per model as provided
612
618
  */
613
- recompileContributionTargets( itemsPerModel, contributions ) {
619
+ async recompileContributionTargets( itemsPerModel, contributions ) {
614
620
  for ( const track of contributions.values() ) {
615
621
  const [ model, id, variantId ] = JSON.parse( track );
616
622
 
@@ -629,7 +635,7 @@ export class Shaper extends EventEmitter {
629
635
  const item = modelPool[id];
630
636
 
631
637
  if ( variantId == null ) {
632
- modelPool[id] = this.recompileItem( item );
638
+ modelPool[id] = await this.recompileItem( item );
633
639
  } else {
634
640
  if ( !item.$variants ) {
635
641
  console.warn( `inconsistency: missing variants of item ${id} of model ${model} though contributions have been tracked` );
@@ -643,7 +649,7 @@ export class Shaper extends EventEmitter {
643
649
  continue;
644
650
  }
645
651
 
646
- variants[variantId] = this.recompileItem( variants[variantId] );
652
+ variants[variantId] = await this.recompileItem( variants[variantId] );
647
653
  }
648
654
  }
649
655
 
@@ -655,16 +661,16 @@ export class Shaper extends EventEmitter {
655
661
  *
656
662
  * @param {object} data source of record
657
663
  * @param {Shape} shape shape of database affecting record
658
- * @returns {string} name of model to use
664
+ * @returns {Promise<string>} name of model to use
659
665
  */
660
- detectModel( data, shape ) {
666
+ async detectModel( data, shape ) {
661
667
  const selector = shape?.common?.properties?.$model;
662
668
 
663
669
  if ( !selector || typeof selector !== "string" ) {
664
670
  throw new Error( "missing or invalid definition of common property $model in shape" );
665
671
  }
666
672
 
667
- const name = Compiler.compile( selector, this.termFunctions, this.termsCache )( data );
673
+ const name = await Compiler.compile( selector, this.termFunctions, this.termsCache )( data );
668
674
 
669
675
  // support processed term requesting to fail model detection
670
676
  if ( name instanceof Error ) {
@@ -683,10 +689,10 @@ export class Shaper extends EventEmitter {
683
689
  *
684
690
  * @param {object} data source of record
685
691
  * @param {ShapeModel} modelShape shape of particular model
686
- * @returns {string} ID of record
692
+ * @returns {Promise<string>} ID of record
687
693
  */
688
- identifyRecord( data, modelShape ) {
689
- const id = this.computeId( modelShape?.properties?.$id, data );
694
+ async identifyRecord( data, modelShape ) {
695
+ const id = await this.computeId( modelShape?.properties?.$id, data );
690
696
 
691
697
  if ( !id ) {
692
698
  throw new Error( `detecting ID of item related to record ${data.$segments.join( "/" )} failed` );
@@ -702,14 +708,14 @@ export class Shaper extends EventEmitter {
702
708
  * @param {ShapeProperties} properties definition of resulting item's properties
703
709
  * @param {ShapePropertyDefaults} defaults definition of default values for resulting item's properties
704
710
  * @param {string[]} accept list names of properties to accept even when starting with a dollar sign
705
- * @returns {object} compiled item
711
+ * @returns {Promise<Partial<ModelItem>>} compiled item
706
712
  */
707
- compileItem( data, properties = {}, defaults = {}, accept = [] ) {
713
+ async compileItem( data, properties = {}, defaults = {}, accept = [] ) {
708
714
  const item = {};
709
715
 
710
716
  for ( const property of Object.keys( properties ) ) {
711
717
  if ( accept.indexOf( property ) > -1 || !String( property ).startsWith( "$" ) ) {
712
- const propertyName = property.replace( /\s*\[]$/, "" );
718
+ const propertyName = property.replace( /\s*\[]\s*$/, "" );
713
719
  const isCollecting = property !== propertyName;
714
720
 
715
721
  const term = properties[property];
@@ -724,7 +730,7 @@ export class Shaper extends EventEmitter {
724
730
  let value;
725
731
 
726
732
  try {
727
- value = Compiler.compile( term, this.termFunctions, this.termsCache )( data );
733
+ value = await Compiler.compile( term, this.termFunctions, this.termsCache )( data );
728
734
 
729
735
  // support processed term requesting to fail computation of property's value
730
736
  if ( value instanceof Error ) {
@@ -741,7 +747,7 @@ export class Shaper extends EventEmitter {
741
747
 
742
748
  try {
743
749
  const code = trimmed.startsWith( "=" ) ? trimmed.slice( 1 ) : undefined;
744
- value = code ? Compiler.compile( code, this.termFunctions, this.termsCache )( data ) : defaultValue;
750
+ value = code ? await Compiler.compile( code, this.termFunctions, this.termsCache )( data ) : defaultValue;
745
751
 
746
752
  // support processed term requesting to fail computation of default value
747
753
  if ( value instanceof Error ) {
@@ -779,15 +785,15 @@ export class Shaper extends EventEmitter {
779
785
  *
780
786
  * @param {string} term term to process
781
787
  * @param {object} data data space available to term processing
782
- * @returns {any} processed term's result
788
+ * @returns {Promise<any>} processed term's result
783
789
  */
784
- computeId( term, data ) {
790
+ async computeId( term, data ) {
785
791
  if ( !term || typeof term !== "string" ) {
786
792
  throw new Error( `missing or invalid term for computing ID of ${data.$segments.join( "/" )}` );
787
793
  }
788
794
 
789
795
  try {
790
- const value = Compiler.compile( term, this.termFunctions, this.termsCache )( data );
796
+ const value = await Compiler.compile( term, this.termFunctions, this.termsCache )( data );
791
797
 
792
798
  // support processed term requesting to fail computation of ID
793
799
  if ( value instanceof Error ) {
@@ -808,7 +814,7 @@ export class Shaper extends EventEmitter {
808
814
  * @param {Shape} mergedLocalShapes local shapes of source folders merged in order of collecting records
809
815
  * @returns {DatabaseEndpoints} map of routes into data sets to expose eventually
810
816
  */
811
- populateModels( endpoints, models, mergedLocalShapes ) {
817
+ async populateModels( endpoints, models, mergedLocalShapes ) {
812
818
  const modelNames = Object.keys( models );
813
819
  let index = 0;
814
820
 
@@ -833,7 +839,7 @@ export class Shaper extends EventEmitter {
833
839
  endpoints[normalized] = model[itemId]; // eslint-disable-line no-param-reassign
834
840
  }
835
841
 
836
- this.populateModelCollections( endpoints, models, modelName, mergedLocalShapes );
842
+ await this.populateModelCollections( endpoints, models, modelName, mergedLocalShapes );
837
843
  }
838
844
 
839
845
  return endpoints;
@@ -849,7 +855,7 @@ export class Shaper extends EventEmitter {
849
855
  * @param {Shape} mergedLocalShapes local shapes of source folders merged in order of collecting records
850
856
  * @returns {DatabaseEndpoints} map of routes into data sets to expose eventually
851
857
  */
852
- populateModelCollections( endpoints, models, modelName, mergedLocalShapes ) {
858
+ async populateModelCollections( endpoints, models, modelName, mergedLocalShapes ) {
853
859
  const finalModelShape = merge( {}, mergedLocalShapes.common, mergedLocalShapes.models[modelName] );
854
860
  const collections = finalModelShape.collections || {};
855
861
  const cache = {};
@@ -893,7 +899,7 @@ export class Shaper extends EventEmitter {
893
899
  collection = cache[definition.reference];
894
900
  isKeyed = collection.$isKeyed;
895
901
  } else {
896
- collection = this.compileCollection( models, modelName, definition, normalized );
902
+ collection = await this.compileCollection( models, modelName, definition, normalized );
897
903
  isKeyed = definition.key && typeof definition.key === "string";
898
904
 
899
905
  Object.defineProperties( collection, {
@@ -964,7 +970,7 @@ export class Shaper extends EventEmitter {
964
970
  const items = collection.items;
965
971
 
966
972
  for ( let offset = 0; offset < items.length; offset += limit ) {
967
- const normalized = normalizePathname( prefix + route.replace( ptnOffset, offset ) );
973
+ const normalized = normalizePathname( prefix + route.replace( ptnOffset, String( offset ) ) );
968
974
  endpoints[normalized] = { count: items.length, items: items.slice( offset, offset + limit ) }; // eslint-disable-line no-param-reassign
969
975
  }
970
976
  } else if ( isKeyed ) {
@@ -1032,7 +1038,7 @@ export class Shaper extends EventEmitter {
1032
1038
  * @param {string} route route for resulting collection
1033
1039
  * @returns {DatabaseCollection} compiled collection
1034
1040
  */
1035
- compileCollection( models, modelName, definition, route ) {
1041
+ async compileCollection( models, modelName, definition, route ) {
1036
1042
  const model = models[modelName];
1037
1043
  const { key: $key, filter: $filter, properties: $properties } = definition;
1038
1044
  const isKeyed = $key && typeof $key === "string";
@@ -1103,9 +1109,9 @@ export class Shaper extends EventEmitter {
1103
1109
  context.$id = id;
1104
1110
 
1105
1111
  // ignore this item or prepare its spot in resulting collection?
1106
- if ( !filterFn || filterFn( data ) ) {
1112
+ if ( !filterFn || await filterFn( data ) ) {
1107
1113
  if ( isKeyed ) {
1108
- const key = keyFn( data );
1114
+ const key = await keyFn( data );
1109
1115
  if ( key != null ) {
1110
1116
  const _key = String( key );
1111
1117
 
@@ -1131,7 +1137,7 @@ export class Shaper extends EventEmitter {
1131
1137
  if ( propertiesFn ) {
1132
1138
  // compile custom representation of item in collection
1133
1139
  for ( const fn of propertiesFn ) {
1134
- extracted[fn.target] = fn( data );
1140
+ extracted[fn.target] = await fn( data );
1135
1141
  }
1136
1142
  } else {
1137
1143
  // expose all properties of item in collection, too
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cepharum/concrete-db",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "a read-only web database generator",
5
5
  "main": "lib/collector.mjs",
6
6
  "types": "concrete-db.d.ts",
@@ -20,22 +20,22 @@
20
20
  "author": "cepharum GmbH",
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "ajv": "^8.11.0",
23
+ "ajv": "^8.12.0",
24
24
  "file-essentials": "^0.1.2",
25
25
  "lodash.merge": "^4.6.2",
26
- "minimist": "^1.2.6",
26
+ "minimist": "^1.2.8",
27
27
  "promise-essentials": "^0.2.0",
28
- "simple-terms": "^0.4.0",
29
- "yaml": "^2.1.0"
28
+ "simple-terms": "^0.4.1",
29
+ "yaml": "^2.2.2"
30
30
  },
31
31
  "devDependencies": {
32
- "c8": "^7.11.3",
33
- "eslint": "^8.16.0",
34
- "eslint-config-cepharum": "^1.0.12",
35
- "eslint-plugin-promise": "^6.0.0",
36
- "mocha": "^10.0.0",
32
+ "c8": "^7.13.0",
33
+ "eslint": "^8.40.0",
34
+ "eslint-config-cepharum": "^1.0.13",
35
+ "eslint-plugin-promise": "^6.1.1",
36
+ "mocha": "^10.2.0",
37
37
  "should": "^13.2.3",
38
- "vuepress": "^1.9.7",
38
+ "vuepress": "^1.9.9",
39
39
  "vuepress-plugin-mermaidjs": "^1.9.1"
40
40
  },
41
41
  "engines": {