@labdigital/commercetools-mock 0.7.1 → 0.8.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/dist/index.d.ts +25 -1
- package/dist/index.global.js +273 -60
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +270 -57
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +270 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -1
- package/src/helpers.ts +24 -0
- package/src/lib/projectionSearchFilter.test.ts +6 -0
- package/src/lib/projectionSearchFilter.ts +173 -74
- package/src/product-projection-search.ts +206 -10
- package/src/repositories/product-projection.ts +1 -0
- package/src/services/product-projection.test.ts +170 -3
package/dist/index.js
CHANGED
|
@@ -820,6 +820,21 @@ var getBaseResourceProperties = () => {
|
|
|
820
820
|
version: 0
|
|
821
821
|
};
|
|
822
822
|
};
|
|
823
|
+
var nestedLookup = (obj, path) => {
|
|
824
|
+
if (!path || path === "") {
|
|
825
|
+
return obj;
|
|
826
|
+
}
|
|
827
|
+
const parts = path.split(".");
|
|
828
|
+
let val = obj;
|
|
829
|
+
for (let i = 0; i < parts.length; i++) {
|
|
830
|
+
const part = parts[i];
|
|
831
|
+
if (val == void 0) {
|
|
832
|
+
return void 0;
|
|
833
|
+
}
|
|
834
|
+
val = val[part];
|
|
835
|
+
}
|
|
836
|
+
return val;
|
|
837
|
+
};
|
|
823
838
|
var QueryParamsAsArray = (input) => {
|
|
824
839
|
if (input == void 0) {
|
|
825
840
|
return [];
|
|
@@ -2909,38 +2924,71 @@ var parseFilterExpression = (filter, staged) => {
|
|
|
2909
2924
|
var getLexer2 = (value) => {
|
|
2910
2925
|
return new import_perplex2.default(value).token("MISSING", /missing(?![-_a-z0-9]+)/i).token("EXISTS", /exists(?![-_a-z0-9]+)/i).token("RANGE", /range(?![-_a-z0-9]+)/i).token("TO", /to(?![-_a-z0-9]+)/i).token("IDENTIFIER", /[-_\.a-z]+/i).token("FLOAT", /\d+\.\d+/).token("INT", /\d+/).token("STRING", /"((?:\\.|[^"\\])*)"/).token("STRING", /'((?:\\.|[^'\\])*)'/).token("COMMA", ",").token("STAR", "*").token("(", "(").token(":", ":").token(")", ")").token('"', '"').token("WS", /\s+/, true);
|
|
2911
2926
|
};
|
|
2912
|
-
var
|
|
2927
|
+
var parseFilter = (filter) => {
|
|
2913
2928
|
const lexer = getLexer2(filter);
|
|
2914
2929
|
const parser = new import_pratt2.default(lexer).builder().nud("IDENTIFIER", 100, (t) => {
|
|
2915
2930
|
return t.token.match;
|
|
2916
2931
|
}).led(":", 100, ({ left, bp }) => {
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2932
|
+
let parsed = parser.parse({ terminals: [bp - 1] });
|
|
2933
|
+
let expressions;
|
|
2934
|
+
expressions = !Array.isArray(parsed) ? [parsed] : parsed;
|
|
2935
|
+
const unique = new Set(expressions.map((expr) => expr.type));
|
|
2936
|
+
if (unique.size > 1) {
|
|
2937
|
+
throw new Error("Invalid expression");
|
|
2922
2938
|
}
|
|
2923
|
-
if (
|
|
2924
|
-
return
|
|
2925
|
-
|
|
2939
|
+
if (expressions.some((expr) => expr.type == "Symbol")) {
|
|
2940
|
+
return {
|
|
2941
|
+
source: left,
|
|
2942
|
+
type: "FilterExpression",
|
|
2943
|
+
children: expressions.map((e) => {
|
|
2944
|
+
if (e.type != "Symbol") {
|
|
2945
|
+
throw new Error("Invalid expression");
|
|
2946
|
+
}
|
|
2947
|
+
return {
|
|
2948
|
+
type: "FilterExpression",
|
|
2949
|
+
match: (obj) => {
|
|
2950
|
+
return obj === e.value;
|
|
2951
|
+
}
|
|
2952
|
+
};
|
|
2953
|
+
})
|
|
2926
2954
|
};
|
|
2927
2955
|
}
|
|
2928
|
-
return
|
|
2929
|
-
|
|
2956
|
+
return {
|
|
2957
|
+
source: left,
|
|
2958
|
+
type: expressions[0].type,
|
|
2959
|
+
children: expressions
|
|
2930
2960
|
};
|
|
2931
2961
|
}).nud("STRING", 20, (t) => {
|
|
2932
|
-
return
|
|
2962
|
+
return {
|
|
2963
|
+
type: "Symbol",
|
|
2964
|
+
kind: "string",
|
|
2965
|
+
value: t.token.groups[1]
|
|
2966
|
+
};
|
|
2933
2967
|
}).nud("INT", 5, (t) => {
|
|
2934
|
-
return
|
|
2968
|
+
return {
|
|
2969
|
+
type: "Symbol",
|
|
2970
|
+
kind: "int",
|
|
2971
|
+
value: parseInt(t.token.match, 10)
|
|
2972
|
+
};
|
|
2935
2973
|
}).nud("STAR", 5, (t) => {
|
|
2936
|
-
return
|
|
2974
|
+
return {
|
|
2975
|
+
type: "Symbol",
|
|
2976
|
+
kind: "any",
|
|
2977
|
+
value: null
|
|
2978
|
+
};
|
|
2937
2979
|
}).nud("EXISTS", 10, ({ bp }) => {
|
|
2938
|
-
return
|
|
2939
|
-
|
|
2980
|
+
return {
|
|
2981
|
+
type: "FilterExpression",
|
|
2982
|
+
match: (obj) => {
|
|
2983
|
+
return obj !== void 0;
|
|
2984
|
+
}
|
|
2940
2985
|
};
|
|
2941
2986
|
}).nud("MISSING", 10, ({ bp }) => {
|
|
2942
|
-
return
|
|
2943
|
-
|
|
2987
|
+
return {
|
|
2988
|
+
type: "FilterExpression",
|
|
2989
|
+
match: (obj) => {
|
|
2990
|
+
return obj === void 0;
|
|
2991
|
+
}
|
|
2944
2992
|
};
|
|
2945
2993
|
}).led("COMMA", 200, ({ left, token, bp }) => {
|
|
2946
2994
|
const expr = parser.parse({ terminals: [bp - 1] });
|
|
@@ -2949,38 +2997,74 @@ var generateMatchFunc2 = (filter) => {
|
|
|
2949
2997
|
} else {
|
|
2950
2998
|
return [left, expr];
|
|
2951
2999
|
}
|
|
3000
|
+
}).nud("(", 100, (t) => {
|
|
3001
|
+
const expr = parser.parse({ terminals: [")"] });
|
|
3002
|
+
lexer.expect(")");
|
|
3003
|
+
return expr;
|
|
2952
3004
|
}).bp(")", 0).led("TO", 20, ({ left, bp }) => {
|
|
2953
3005
|
const expr = parser.parse({ terminals: [bp - 1] });
|
|
2954
|
-
return
|
|
3006
|
+
return {
|
|
3007
|
+
start: left.value,
|
|
3008
|
+
stop: expr.value
|
|
3009
|
+
};
|
|
2955
3010
|
}).nud("RANGE", 20, ({ bp }) => {
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
if (start !== null && stop !== null) {
|
|
2960
|
-
return (obj) => {
|
|
2961
|
-
return obj >= start && obj <= stop;
|
|
2962
|
-
};
|
|
2963
|
-
} else if (start === null && stop !== null) {
|
|
2964
|
-
return (obj) => {
|
|
2965
|
-
return obj <= stop;
|
|
2966
|
-
};
|
|
2967
|
-
} else if (start !== null && stop === null) {
|
|
2968
|
-
return (obj) => {
|
|
2969
|
-
return obj >= start;
|
|
2970
|
-
};
|
|
2971
|
-
} else {
|
|
2972
|
-
return (obj) => {
|
|
2973
|
-
return true;
|
|
2974
|
-
};
|
|
3011
|
+
let ranges = parser.parse();
|
|
3012
|
+
if (!Array.isArray(ranges)) {
|
|
3013
|
+
ranges = [ranges];
|
|
2975
3014
|
}
|
|
3015
|
+
return ranges.map((range) => {
|
|
3016
|
+
let func = void 0;
|
|
3017
|
+
if (range.start !== null && range.stop !== null) {
|
|
3018
|
+
func = (obj) => {
|
|
3019
|
+
return obj >= range.start && obj <= range.stop;
|
|
3020
|
+
};
|
|
3021
|
+
} else if (range.start === null && range.stop !== null) {
|
|
3022
|
+
func = (obj) => {
|
|
3023
|
+
return obj <= range.stop;
|
|
3024
|
+
};
|
|
3025
|
+
} else if (range.start !== null && range.stop === null) {
|
|
3026
|
+
func = (obj) => {
|
|
3027
|
+
return obj >= range.start;
|
|
3028
|
+
};
|
|
3029
|
+
} else {
|
|
3030
|
+
func = (obj) => {
|
|
3031
|
+
return true;
|
|
3032
|
+
};
|
|
3033
|
+
}
|
|
3034
|
+
return {
|
|
3035
|
+
type: "RangeExpression",
|
|
3036
|
+
start: range.start,
|
|
3037
|
+
stop: range.stop,
|
|
3038
|
+
match: func
|
|
3039
|
+
};
|
|
3040
|
+
});
|
|
2976
3041
|
}).build();
|
|
2977
|
-
|
|
2978
|
-
|
|
3042
|
+
return parser.parse();
|
|
3043
|
+
};
|
|
3044
|
+
var generateMatchFunc2 = (filter) => {
|
|
3045
|
+
const result = parseFilter(filter);
|
|
3046
|
+
if (!result) {
|
|
2979
3047
|
const lines = filter.split("\n");
|
|
2980
3048
|
const column = lines[lines.length - 1].length;
|
|
2981
3049
|
throw new Error(`Syntax error while parsing '${filter}'.`);
|
|
2982
3050
|
}
|
|
2983
|
-
|
|
3051
|
+
if (result.type == "TermExpression") {
|
|
3052
|
+
throw new Error(`Syntax error while parsing '${filter}'.`);
|
|
3053
|
+
}
|
|
3054
|
+
return (obj) => {
|
|
3055
|
+
if (!result.children)
|
|
3056
|
+
return false;
|
|
3057
|
+
return result.children.some((c) => c.match(obj));
|
|
3058
|
+
};
|
|
3059
|
+
};
|
|
3060
|
+
var generateFacetFunc = (filter) => {
|
|
3061
|
+
if (!filter.includes(":")) {
|
|
3062
|
+
return {
|
|
3063
|
+
source: filter,
|
|
3064
|
+
type: "TermExpression"
|
|
3065
|
+
};
|
|
3066
|
+
}
|
|
3067
|
+
return parseFilter(filter);
|
|
2984
3068
|
};
|
|
2985
3069
|
var filterProduct = (source, exprFunc) => {
|
|
2986
3070
|
return (p, markMatchingVariants) => {
|
|
@@ -3010,6 +3094,9 @@ var resolveVariantValue = (obj, path) => {
|
|
|
3010
3094
|
if (path === void 0) {
|
|
3011
3095
|
return obj;
|
|
3012
3096
|
}
|
|
3097
|
+
if (path.startsWith("variants.")) {
|
|
3098
|
+
path = path.substring(path.indexOf(".") + 1);
|
|
3099
|
+
}
|
|
3013
3100
|
if (path.startsWith("attributes.")) {
|
|
3014
3101
|
const [, attrName, ...rest] = path.split(".");
|
|
3015
3102
|
if (!obj.attributes) {
|
|
@@ -3026,21 +3113,6 @@ var resolveVariantValue = (obj, path) => {
|
|
|
3026
3113
|
}
|
|
3027
3114
|
return nestedLookup(obj, path);
|
|
3028
3115
|
};
|
|
3029
|
-
var nestedLookup = (obj, path) => {
|
|
3030
|
-
if (!path || path === "") {
|
|
3031
|
-
return obj;
|
|
3032
|
-
}
|
|
3033
|
-
const parts = path.split(".");
|
|
3034
|
-
let val = obj;
|
|
3035
|
-
for (let i = 0; i < parts.length; i++) {
|
|
3036
|
-
const part = parts[i];
|
|
3037
|
-
if (val == void 0) {
|
|
3038
|
-
return void 0;
|
|
3039
|
-
}
|
|
3040
|
-
val = val[part];
|
|
3041
|
-
}
|
|
3042
|
-
return val;
|
|
3043
|
-
};
|
|
3044
3116
|
var getVariants = (p, staged) => {
|
|
3045
3117
|
var _a, _b, _c, _d;
|
|
3046
3118
|
return [
|
|
@@ -3133,6 +3205,7 @@ var ProductProjectionSearch = class {
|
|
|
3133
3205
|
);
|
|
3134
3206
|
}
|
|
3135
3207
|
}
|
|
3208
|
+
const facets = this.getFacets(params, resources);
|
|
3136
3209
|
if (params["filter.query"]) {
|
|
3137
3210
|
try {
|
|
3138
3211
|
const filters = params["filter.query"].map(
|
|
@@ -3166,7 +3239,7 @@ var ProductProjectionSearch = class {
|
|
|
3166
3239
|
offset,
|
|
3167
3240
|
limit,
|
|
3168
3241
|
results: resources.map(this.transform),
|
|
3169
|
-
facets
|
|
3242
|
+
facets
|
|
3170
3243
|
};
|
|
3171
3244
|
}
|
|
3172
3245
|
transform(product) {
|
|
@@ -3184,6 +3257,145 @@ var ProductProjectionSearch = class {
|
|
|
3184
3257
|
productType: product.productType
|
|
3185
3258
|
};
|
|
3186
3259
|
}
|
|
3260
|
+
getFacets(params, products) {
|
|
3261
|
+
if (!params.facet)
|
|
3262
|
+
return {};
|
|
3263
|
+
const staged = false;
|
|
3264
|
+
const result = {};
|
|
3265
|
+
for (const facet of params.facet) {
|
|
3266
|
+
const expression = generateFacetFunc(facet);
|
|
3267
|
+
if (expression.type === "TermExpression") {
|
|
3268
|
+
result[facet] = this.termFacet(expression.source, products, staged);
|
|
3269
|
+
}
|
|
3270
|
+
if (expression.type === "RangeExpression") {
|
|
3271
|
+
result[expression.source] = this.rangeFacet(
|
|
3272
|
+
expression.source,
|
|
3273
|
+
expression.children,
|
|
3274
|
+
products,
|
|
3275
|
+
staged
|
|
3276
|
+
);
|
|
3277
|
+
}
|
|
3278
|
+
if (expression.type === "FilterExpression") {
|
|
3279
|
+
result[expression.source] = this.filterFacet(
|
|
3280
|
+
expression.source,
|
|
3281
|
+
expression.children,
|
|
3282
|
+
products,
|
|
3283
|
+
staged
|
|
3284
|
+
);
|
|
3285
|
+
}
|
|
3286
|
+
}
|
|
3287
|
+
return result;
|
|
3288
|
+
}
|
|
3289
|
+
termFacet(facet, products, staged) {
|
|
3290
|
+
const result = {
|
|
3291
|
+
type: "terms",
|
|
3292
|
+
dataType: "text",
|
|
3293
|
+
missing: 0,
|
|
3294
|
+
total: 0,
|
|
3295
|
+
other: 0,
|
|
3296
|
+
terms: []
|
|
3297
|
+
};
|
|
3298
|
+
const terms = {};
|
|
3299
|
+
if (facet.startsWith("variants.")) {
|
|
3300
|
+
products.forEach((p) => {
|
|
3301
|
+
const variants = getVariants(p, staged);
|
|
3302
|
+
variants.forEach((v) => {
|
|
3303
|
+
result.total++;
|
|
3304
|
+
let value = resolveVariantValue(v, facet);
|
|
3305
|
+
if (value === void 0) {
|
|
3306
|
+
result.missing++;
|
|
3307
|
+
} else {
|
|
3308
|
+
if (typeof value === "number") {
|
|
3309
|
+
value = Number(value).toFixed(1);
|
|
3310
|
+
}
|
|
3311
|
+
terms[value] = value in terms ? terms[value] + 1 : 1;
|
|
3312
|
+
}
|
|
3313
|
+
});
|
|
3314
|
+
});
|
|
3315
|
+
} else {
|
|
3316
|
+
products.forEach((p) => {
|
|
3317
|
+
const value = nestedLookup(p, facet);
|
|
3318
|
+
result.total++;
|
|
3319
|
+
if (value === void 0) {
|
|
3320
|
+
result.missing++;
|
|
3321
|
+
} else {
|
|
3322
|
+
terms[value] = value in terms ? terms[value] + 1 : 1;
|
|
3323
|
+
}
|
|
3324
|
+
});
|
|
3325
|
+
}
|
|
3326
|
+
for (const term in terms) {
|
|
3327
|
+
result.terms.push({
|
|
3328
|
+
term,
|
|
3329
|
+
count: terms[term]
|
|
3330
|
+
});
|
|
3331
|
+
}
|
|
3332
|
+
return result;
|
|
3333
|
+
}
|
|
3334
|
+
filterFacet(source, filters, products, staged) {
|
|
3335
|
+
let count = 0;
|
|
3336
|
+
if (source.startsWith("variants.")) {
|
|
3337
|
+
for (const p of products) {
|
|
3338
|
+
for (const v of getVariants(p, staged)) {
|
|
3339
|
+
const val = resolveVariantValue(v, source);
|
|
3340
|
+
if (filters == null ? void 0 : filters.some((f) => f.match(val))) {
|
|
3341
|
+
count++;
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
} else {
|
|
3346
|
+
throw new Error("not supported");
|
|
3347
|
+
}
|
|
3348
|
+
return {
|
|
3349
|
+
type: "filter",
|
|
3350
|
+
count
|
|
3351
|
+
};
|
|
3352
|
+
}
|
|
3353
|
+
rangeFacet(source, ranges, products, staged) {
|
|
3354
|
+
const counts = (ranges == null ? void 0 : ranges.map((range) => {
|
|
3355
|
+
if (source.startsWith("variants.")) {
|
|
3356
|
+
const values = [];
|
|
3357
|
+
for (const p of products) {
|
|
3358
|
+
for (const v of getVariants(p, staged)) {
|
|
3359
|
+
const val = resolveVariantValue(v, source);
|
|
3360
|
+
if (val === void 0) {
|
|
3361
|
+
continue;
|
|
3362
|
+
}
|
|
3363
|
+
if (range.match(val)) {
|
|
3364
|
+
values.push(val);
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
const numValues = values.length;
|
|
3369
|
+
return {
|
|
3370
|
+
type: "double",
|
|
3371
|
+
from: range.start || 0,
|
|
3372
|
+
fromStr: range.start !== null ? Number(range.start).toFixed(1) : "",
|
|
3373
|
+
to: range.stop || 0,
|
|
3374
|
+
toStr: range.stop !== null ? Number(range.stop).toFixed(1) : "",
|
|
3375
|
+
count: numValues,
|
|
3376
|
+
total: values.reduce((a, b) => a + b, 0),
|
|
3377
|
+
min: numValues > 0 ? Math.min(...values) : 0,
|
|
3378
|
+
max: numValues > 0 ? Math.max(...values) : 0,
|
|
3379
|
+
mean: numValues > 0 ? mean(values) : 0
|
|
3380
|
+
};
|
|
3381
|
+
} else {
|
|
3382
|
+
throw new Error("not supported");
|
|
3383
|
+
}
|
|
3384
|
+
})) || [];
|
|
3385
|
+
const data = {
|
|
3386
|
+
type: "range",
|
|
3387
|
+
dataType: "number",
|
|
3388
|
+
ranges: counts
|
|
3389
|
+
};
|
|
3390
|
+
return data;
|
|
3391
|
+
}
|
|
3392
|
+
};
|
|
3393
|
+
var mean = (arr) => {
|
|
3394
|
+
let total = 0;
|
|
3395
|
+
for (let i = 0; i < arr.length; i++) {
|
|
3396
|
+
total += arr[i];
|
|
3397
|
+
}
|
|
3398
|
+
return total / arr.length;
|
|
3187
3399
|
};
|
|
3188
3400
|
|
|
3189
3401
|
// src/repositories/product-projection.ts
|
|
@@ -3211,6 +3423,7 @@ var ProductProjectionRepository = class extends AbstractResourceRepository {
|
|
|
3211
3423
|
const results = this._searchService.search(context.projectKey, {
|
|
3212
3424
|
filter: QueryParamsAsArray(query.filter),
|
|
3213
3425
|
"filter.query": QueryParamsAsArray(query["filter.query"]),
|
|
3426
|
+
facet: QueryParamsAsArray(query.facet),
|
|
3214
3427
|
offset: query.offset ? Number(query.offset) : void 0,
|
|
3215
3428
|
limit: query.limit ? Number(query.limit) : void 0,
|
|
3216
3429
|
expand: QueryParamsAsArray(query.expand)
|