@cepharum/concrete-db 0.2.0 → 0.2.2
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 +20 -32
- package/lib/shaper.mjs +8 -4
- package/lib/term-functions.mjs +8 -6
- package/package.json +1 -1
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
|
|
269
|
-
collections
|
|
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
|
@@ -166,7 +166,7 @@ export class Shaper extends EventEmitter {
|
|
|
166
166
|
const augmentedData = augmentDataSpace( data, metaProperties );
|
|
167
167
|
|
|
168
168
|
metaProperties.$model = this.detectModel( augmentedData, shape );
|
|
169
|
-
metaProperties.$shape = this.getShapeOfModel(
|
|
169
|
+
metaProperties.$shape = this.getShapeOfModel( shapesPerModelCache, shape, metaProperties.$model );
|
|
170
170
|
metaProperties.$id = this.identifyRecord( augmentedData, metaProperties.$shape );
|
|
171
171
|
|
|
172
172
|
if ( !itemsPerModel.hasOwnProperty( metaProperties.$model ) ) {
|
|
@@ -551,6 +551,10 @@ export class Shaper extends EventEmitter {
|
|
|
551
551
|
* @returns {ModelItem} provided target
|
|
552
552
|
*/
|
|
553
553
|
mergeModelItem( target, source ) {
|
|
554
|
+
if ( target?.$shape?.constraints?.singleSource ) {
|
|
555
|
+
throw new Error( `merging ${target.$model} with ID ${target.$id} from multiple source records rejected by shape` );
|
|
556
|
+
}
|
|
557
|
+
|
|
554
558
|
const _to = target || {};
|
|
555
559
|
const oldNames = target ? Object.keys( _to.$shape.properties ) : [];
|
|
556
560
|
const newNames = Object.keys( source.$shape.properties );
|
|
@@ -558,8 +562,8 @@ export class Shaper extends EventEmitter {
|
|
|
558
562
|
// merge properties of items
|
|
559
563
|
for ( const name of Object.keys( source ) ) {
|
|
560
564
|
if ( !String( name ).startsWith( "$" ) ) {
|
|
561
|
-
const wasCollecting = oldNames.some( n => n.replace( /\s
|
|
562
|
-
const isCollecting = newNames.some( n => n.replace( /\s
|
|
565
|
+
const wasCollecting = oldNames.some( n => n.replace( /\s+/g, "" ) === name + "[]" );
|
|
566
|
+
const isCollecting = newNames.some( n => n.replace( /\s+/g, "" ) === name + "[]" );
|
|
563
567
|
|
|
564
568
|
if ( _to.hasOwnProperty( name ) ) {
|
|
565
569
|
if ( isCollecting ) {
|
|
@@ -709,7 +713,7 @@ export class Shaper extends EventEmitter {
|
|
|
709
713
|
|
|
710
714
|
for ( const property of Object.keys( properties ) ) {
|
|
711
715
|
if ( accept.indexOf( property ) > -1 || !String( property ).startsWith( "$" ) ) {
|
|
712
|
-
const propertyName = property.replace( /\s*\[]
|
|
716
|
+
const propertyName = property.replace( /\s*\[]\s*$/, "" );
|
|
713
717
|
const isCollecting = property !== propertyName;
|
|
714
718
|
|
|
715
719
|
const term = properties[property];
|
package/lib/term-functions.mjs
CHANGED
|
@@ -69,12 +69,13 @@ export function compare( left, right ) {
|
|
|
69
69
|
* @param {number} maxWordSize maximum number of characters in extracted words
|
|
70
70
|
* @param {boolean} ignoreCase set true to drop case of extracted words
|
|
71
71
|
* @param {boolean} strict set false to have any non-string value converted to string instead of being ignored
|
|
72
|
+
* @param {string} wordPattern provides source of global unicode regexp matching a word to generate
|
|
72
73
|
* @returns {Object<string,number>} map of extracted words into either words's number of occurrences
|
|
73
74
|
*/
|
|
74
|
-
export function spread( value, minSize = 10, minWordSize = 3, maxWordSize = Infinity, ignoreCase = true, strict = true ) {
|
|
75
|
+
export function spread( value, minSize = 10, minWordSize = 3, maxWordSize = Infinity, ignoreCase = true, strict = true, wordPattern = undefined ) {
|
|
75
76
|
const result = {};
|
|
76
77
|
|
|
77
|
-
for ( const word of generateWords( value, minSize, ignoreCase, strict ) ) {
|
|
78
|
+
for ( const word of generateWords( value, minSize, ignoreCase, strict, wordPattern ) ) {
|
|
78
79
|
if ( word.length >= minWordSize && word.length <= maxWordSize ) {
|
|
79
80
|
result[word] = ( result[word] || 0 ) + 1;
|
|
80
81
|
}
|
|
@@ -102,9 +103,10 @@ export function fail( message ) {
|
|
|
102
103
|
* @param {number} minSize minimum number of characters in a string to be considered for extracting terms
|
|
103
104
|
* @param {boolean} ignoreCase set true to drop case of extracted terms
|
|
104
105
|
* @param {boolean} strict set false to have any non-string value converted to string instead of being ignored
|
|
106
|
+
* @param {string} wordPattern provides source of global unicode regexp matching a word to generate
|
|
105
107
|
* @returns {Generator<string|*, void, *>} iterator over flat sequence of terms
|
|
106
108
|
*/
|
|
107
|
-
function *generateWords( source, minSize, ignoreCase, strict ) {
|
|
109
|
+
function *generateWords( source, minSize, ignoreCase, strict, wordPattern = undefined ) {
|
|
108
110
|
let stream;
|
|
109
111
|
|
|
110
112
|
if ( Array.isArray( source ) ) {
|
|
@@ -124,17 +126,17 @@ function *generateWords( source, minSize, ignoreCase, strict ) {
|
|
|
124
126
|
return;
|
|
125
127
|
}
|
|
126
128
|
|
|
127
|
-
const ptn = /
|
|
129
|
+
const ptn = wordPattern ? new RegExp( wordPattern, "gu" ) : /[\p{L}\p{N}_][\p{L}\p{N}_-]*/gu;
|
|
128
130
|
let match;
|
|
129
131
|
|
|
130
132
|
while ( ( match = ptn.exec( string ) ) ) {
|
|
131
|
-
yield ignoreCase ? match[1].toLocaleLowerCase() : match[1];
|
|
133
|
+
yield ignoreCase ? ( match[1] ?? match[0] ).toLocaleLowerCase() : match[1] ?? match[0];
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
return;
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
for ( const sub of stream ) {
|
|
138
|
-
yield* generateWords( sub, minSize, ignoreCase, strict );
|
|
140
|
+
yield* generateWords( sub, minSize, ignoreCase, strict, wordPattern );
|
|
139
141
|
}
|
|
140
142
|
}
|