@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.mjs
CHANGED
|
@@ -787,6 +787,21 @@ var getBaseResourceProperties = () => {
|
|
|
787
787
|
version: 0
|
|
788
788
|
};
|
|
789
789
|
};
|
|
790
|
+
var nestedLookup = (obj, path) => {
|
|
791
|
+
if (!path || path === "") {
|
|
792
|
+
return obj;
|
|
793
|
+
}
|
|
794
|
+
const parts = path.split(".");
|
|
795
|
+
let val = obj;
|
|
796
|
+
for (let i = 0; i < parts.length; i++) {
|
|
797
|
+
const part = parts[i];
|
|
798
|
+
if (val == void 0) {
|
|
799
|
+
return void 0;
|
|
800
|
+
}
|
|
801
|
+
val = val[part];
|
|
802
|
+
}
|
|
803
|
+
return val;
|
|
804
|
+
};
|
|
790
805
|
var QueryParamsAsArray = (input) => {
|
|
791
806
|
if (input == void 0) {
|
|
792
807
|
return [];
|
|
@@ -2876,38 +2891,71 @@ var parseFilterExpression = (filter, staged) => {
|
|
|
2876
2891
|
var getLexer2 = (value) => {
|
|
2877
2892
|
return new perplex2(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);
|
|
2878
2893
|
};
|
|
2879
|
-
var
|
|
2894
|
+
var parseFilter = (filter) => {
|
|
2880
2895
|
const lexer = getLexer2(filter);
|
|
2881
2896
|
const parser = new Parser2(lexer).builder().nud("IDENTIFIER", 100, (t) => {
|
|
2882
2897
|
return t.token.match;
|
|
2883
2898
|
}).led(":", 100, ({ left, bp }) => {
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2899
|
+
let parsed = parser.parse({ terminals: [bp - 1] });
|
|
2900
|
+
let expressions;
|
|
2901
|
+
expressions = !Array.isArray(parsed) ? [parsed] : parsed;
|
|
2902
|
+
const unique = new Set(expressions.map((expr) => expr.type));
|
|
2903
|
+
if (unique.size > 1) {
|
|
2904
|
+
throw new Error("Invalid expression");
|
|
2889
2905
|
}
|
|
2890
|
-
if (
|
|
2891
|
-
return
|
|
2892
|
-
|
|
2906
|
+
if (expressions.some((expr) => expr.type == "Symbol")) {
|
|
2907
|
+
return {
|
|
2908
|
+
source: left,
|
|
2909
|
+
type: "FilterExpression",
|
|
2910
|
+
children: expressions.map((e) => {
|
|
2911
|
+
if (e.type != "Symbol") {
|
|
2912
|
+
throw new Error("Invalid expression");
|
|
2913
|
+
}
|
|
2914
|
+
return {
|
|
2915
|
+
type: "FilterExpression",
|
|
2916
|
+
match: (obj) => {
|
|
2917
|
+
return obj === e.value;
|
|
2918
|
+
}
|
|
2919
|
+
};
|
|
2920
|
+
})
|
|
2893
2921
|
};
|
|
2894
2922
|
}
|
|
2895
|
-
return
|
|
2896
|
-
|
|
2923
|
+
return {
|
|
2924
|
+
source: left,
|
|
2925
|
+
type: expressions[0].type,
|
|
2926
|
+
children: expressions
|
|
2897
2927
|
};
|
|
2898
2928
|
}).nud("STRING", 20, (t) => {
|
|
2899
|
-
return
|
|
2929
|
+
return {
|
|
2930
|
+
type: "Symbol",
|
|
2931
|
+
kind: "string",
|
|
2932
|
+
value: t.token.groups[1]
|
|
2933
|
+
};
|
|
2900
2934
|
}).nud("INT", 5, (t) => {
|
|
2901
|
-
return
|
|
2935
|
+
return {
|
|
2936
|
+
type: "Symbol",
|
|
2937
|
+
kind: "int",
|
|
2938
|
+
value: parseInt(t.token.match, 10)
|
|
2939
|
+
};
|
|
2902
2940
|
}).nud("STAR", 5, (t) => {
|
|
2903
|
-
return
|
|
2941
|
+
return {
|
|
2942
|
+
type: "Symbol",
|
|
2943
|
+
kind: "any",
|
|
2944
|
+
value: null
|
|
2945
|
+
};
|
|
2904
2946
|
}).nud("EXISTS", 10, ({ bp }) => {
|
|
2905
|
-
return
|
|
2906
|
-
|
|
2947
|
+
return {
|
|
2948
|
+
type: "FilterExpression",
|
|
2949
|
+
match: (obj) => {
|
|
2950
|
+
return obj !== void 0;
|
|
2951
|
+
}
|
|
2907
2952
|
};
|
|
2908
2953
|
}).nud("MISSING", 10, ({ bp }) => {
|
|
2909
|
-
return
|
|
2910
|
-
|
|
2954
|
+
return {
|
|
2955
|
+
type: "FilterExpression",
|
|
2956
|
+
match: (obj) => {
|
|
2957
|
+
return obj === void 0;
|
|
2958
|
+
}
|
|
2911
2959
|
};
|
|
2912
2960
|
}).led("COMMA", 200, ({ left, token, bp }) => {
|
|
2913
2961
|
const expr = parser.parse({ terminals: [bp - 1] });
|
|
@@ -2916,38 +2964,74 @@ var generateMatchFunc2 = (filter) => {
|
|
|
2916
2964
|
} else {
|
|
2917
2965
|
return [left, expr];
|
|
2918
2966
|
}
|
|
2967
|
+
}).nud("(", 100, (t) => {
|
|
2968
|
+
const expr = parser.parse({ terminals: [")"] });
|
|
2969
|
+
lexer.expect(")");
|
|
2970
|
+
return expr;
|
|
2919
2971
|
}).bp(")", 0).led("TO", 20, ({ left, bp }) => {
|
|
2920
2972
|
const expr = parser.parse({ terminals: [bp - 1] });
|
|
2921
|
-
return
|
|
2973
|
+
return {
|
|
2974
|
+
start: left.value,
|
|
2975
|
+
stop: expr.value
|
|
2976
|
+
};
|
|
2922
2977
|
}).nud("RANGE", 20, ({ bp }) => {
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
if (start !== null && stop !== null) {
|
|
2927
|
-
return (obj) => {
|
|
2928
|
-
return obj >= start && obj <= stop;
|
|
2929
|
-
};
|
|
2930
|
-
} else if (start === null && stop !== null) {
|
|
2931
|
-
return (obj) => {
|
|
2932
|
-
return obj <= stop;
|
|
2933
|
-
};
|
|
2934
|
-
} else if (start !== null && stop === null) {
|
|
2935
|
-
return (obj) => {
|
|
2936
|
-
return obj >= start;
|
|
2937
|
-
};
|
|
2938
|
-
} else {
|
|
2939
|
-
return (obj) => {
|
|
2940
|
-
return true;
|
|
2941
|
-
};
|
|
2978
|
+
let ranges = parser.parse();
|
|
2979
|
+
if (!Array.isArray(ranges)) {
|
|
2980
|
+
ranges = [ranges];
|
|
2942
2981
|
}
|
|
2982
|
+
return ranges.map((range) => {
|
|
2983
|
+
let func = void 0;
|
|
2984
|
+
if (range.start !== null && range.stop !== null) {
|
|
2985
|
+
func = (obj) => {
|
|
2986
|
+
return obj >= range.start && obj <= range.stop;
|
|
2987
|
+
};
|
|
2988
|
+
} else if (range.start === null && range.stop !== null) {
|
|
2989
|
+
func = (obj) => {
|
|
2990
|
+
return obj <= range.stop;
|
|
2991
|
+
};
|
|
2992
|
+
} else if (range.start !== null && range.stop === null) {
|
|
2993
|
+
func = (obj) => {
|
|
2994
|
+
return obj >= range.start;
|
|
2995
|
+
};
|
|
2996
|
+
} else {
|
|
2997
|
+
func = (obj) => {
|
|
2998
|
+
return true;
|
|
2999
|
+
};
|
|
3000
|
+
}
|
|
3001
|
+
return {
|
|
3002
|
+
type: "RangeExpression",
|
|
3003
|
+
start: range.start,
|
|
3004
|
+
stop: range.stop,
|
|
3005
|
+
match: func
|
|
3006
|
+
};
|
|
3007
|
+
});
|
|
2943
3008
|
}).build();
|
|
2944
|
-
|
|
2945
|
-
|
|
3009
|
+
return parser.parse();
|
|
3010
|
+
};
|
|
3011
|
+
var generateMatchFunc2 = (filter) => {
|
|
3012
|
+
const result = parseFilter(filter);
|
|
3013
|
+
if (!result) {
|
|
2946
3014
|
const lines = filter.split("\n");
|
|
2947
3015
|
const column = lines[lines.length - 1].length;
|
|
2948
3016
|
throw new Error(`Syntax error while parsing '${filter}'.`);
|
|
2949
3017
|
}
|
|
2950
|
-
|
|
3018
|
+
if (result.type == "TermExpression") {
|
|
3019
|
+
throw new Error(`Syntax error while parsing '${filter}'.`);
|
|
3020
|
+
}
|
|
3021
|
+
return (obj) => {
|
|
3022
|
+
if (!result.children)
|
|
3023
|
+
return false;
|
|
3024
|
+
return result.children.some((c) => c.match(obj));
|
|
3025
|
+
};
|
|
3026
|
+
};
|
|
3027
|
+
var generateFacetFunc = (filter) => {
|
|
3028
|
+
if (!filter.includes(":")) {
|
|
3029
|
+
return {
|
|
3030
|
+
source: filter,
|
|
3031
|
+
type: "TermExpression"
|
|
3032
|
+
};
|
|
3033
|
+
}
|
|
3034
|
+
return parseFilter(filter);
|
|
2951
3035
|
};
|
|
2952
3036
|
var filterProduct = (source, exprFunc) => {
|
|
2953
3037
|
return (p, markMatchingVariants) => {
|
|
@@ -2977,6 +3061,9 @@ var resolveVariantValue = (obj, path) => {
|
|
|
2977
3061
|
if (path === void 0) {
|
|
2978
3062
|
return obj;
|
|
2979
3063
|
}
|
|
3064
|
+
if (path.startsWith("variants.")) {
|
|
3065
|
+
path = path.substring(path.indexOf(".") + 1);
|
|
3066
|
+
}
|
|
2980
3067
|
if (path.startsWith("attributes.")) {
|
|
2981
3068
|
const [, attrName, ...rest] = path.split(".");
|
|
2982
3069
|
if (!obj.attributes) {
|
|
@@ -2993,21 +3080,6 @@ var resolveVariantValue = (obj, path) => {
|
|
|
2993
3080
|
}
|
|
2994
3081
|
return nestedLookup(obj, path);
|
|
2995
3082
|
};
|
|
2996
|
-
var nestedLookup = (obj, path) => {
|
|
2997
|
-
if (!path || path === "") {
|
|
2998
|
-
return obj;
|
|
2999
|
-
}
|
|
3000
|
-
const parts = path.split(".");
|
|
3001
|
-
let val = obj;
|
|
3002
|
-
for (let i = 0; i < parts.length; i++) {
|
|
3003
|
-
const part = parts[i];
|
|
3004
|
-
if (val == void 0) {
|
|
3005
|
-
return void 0;
|
|
3006
|
-
}
|
|
3007
|
-
val = val[part];
|
|
3008
|
-
}
|
|
3009
|
-
return val;
|
|
3010
|
-
};
|
|
3011
3083
|
var getVariants = (p, staged) => {
|
|
3012
3084
|
var _a, _b, _c, _d;
|
|
3013
3085
|
return [
|
|
@@ -3100,6 +3172,7 @@ var ProductProjectionSearch = class {
|
|
|
3100
3172
|
);
|
|
3101
3173
|
}
|
|
3102
3174
|
}
|
|
3175
|
+
const facets = this.getFacets(params, resources);
|
|
3103
3176
|
if (params["filter.query"]) {
|
|
3104
3177
|
try {
|
|
3105
3178
|
const filters = params["filter.query"].map(
|
|
@@ -3133,7 +3206,7 @@ var ProductProjectionSearch = class {
|
|
|
3133
3206
|
offset,
|
|
3134
3207
|
limit,
|
|
3135
3208
|
results: resources.map(this.transform),
|
|
3136
|
-
facets
|
|
3209
|
+
facets
|
|
3137
3210
|
};
|
|
3138
3211
|
}
|
|
3139
3212
|
transform(product) {
|
|
@@ -3151,6 +3224,145 @@ var ProductProjectionSearch = class {
|
|
|
3151
3224
|
productType: product.productType
|
|
3152
3225
|
};
|
|
3153
3226
|
}
|
|
3227
|
+
getFacets(params, products) {
|
|
3228
|
+
if (!params.facet)
|
|
3229
|
+
return {};
|
|
3230
|
+
const staged = false;
|
|
3231
|
+
const result = {};
|
|
3232
|
+
for (const facet of params.facet) {
|
|
3233
|
+
const expression = generateFacetFunc(facet);
|
|
3234
|
+
if (expression.type === "TermExpression") {
|
|
3235
|
+
result[facet] = this.termFacet(expression.source, products, staged);
|
|
3236
|
+
}
|
|
3237
|
+
if (expression.type === "RangeExpression") {
|
|
3238
|
+
result[expression.source] = this.rangeFacet(
|
|
3239
|
+
expression.source,
|
|
3240
|
+
expression.children,
|
|
3241
|
+
products,
|
|
3242
|
+
staged
|
|
3243
|
+
);
|
|
3244
|
+
}
|
|
3245
|
+
if (expression.type === "FilterExpression") {
|
|
3246
|
+
result[expression.source] = this.filterFacet(
|
|
3247
|
+
expression.source,
|
|
3248
|
+
expression.children,
|
|
3249
|
+
products,
|
|
3250
|
+
staged
|
|
3251
|
+
);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
return result;
|
|
3255
|
+
}
|
|
3256
|
+
termFacet(facet, products, staged) {
|
|
3257
|
+
const result = {
|
|
3258
|
+
type: "terms",
|
|
3259
|
+
dataType: "text",
|
|
3260
|
+
missing: 0,
|
|
3261
|
+
total: 0,
|
|
3262
|
+
other: 0,
|
|
3263
|
+
terms: []
|
|
3264
|
+
};
|
|
3265
|
+
const terms = {};
|
|
3266
|
+
if (facet.startsWith("variants.")) {
|
|
3267
|
+
products.forEach((p) => {
|
|
3268
|
+
const variants = getVariants(p, staged);
|
|
3269
|
+
variants.forEach((v) => {
|
|
3270
|
+
result.total++;
|
|
3271
|
+
let value = resolveVariantValue(v, facet);
|
|
3272
|
+
if (value === void 0) {
|
|
3273
|
+
result.missing++;
|
|
3274
|
+
} else {
|
|
3275
|
+
if (typeof value === "number") {
|
|
3276
|
+
value = Number(value).toFixed(1);
|
|
3277
|
+
}
|
|
3278
|
+
terms[value] = value in terms ? terms[value] + 1 : 1;
|
|
3279
|
+
}
|
|
3280
|
+
});
|
|
3281
|
+
});
|
|
3282
|
+
} else {
|
|
3283
|
+
products.forEach((p) => {
|
|
3284
|
+
const value = nestedLookup(p, facet);
|
|
3285
|
+
result.total++;
|
|
3286
|
+
if (value === void 0) {
|
|
3287
|
+
result.missing++;
|
|
3288
|
+
} else {
|
|
3289
|
+
terms[value] = value in terms ? terms[value] + 1 : 1;
|
|
3290
|
+
}
|
|
3291
|
+
});
|
|
3292
|
+
}
|
|
3293
|
+
for (const term in terms) {
|
|
3294
|
+
result.terms.push({
|
|
3295
|
+
term,
|
|
3296
|
+
count: terms[term]
|
|
3297
|
+
});
|
|
3298
|
+
}
|
|
3299
|
+
return result;
|
|
3300
|
+
}
|
|
3301
|
+
filterFacet(source, filters, products, staged) {
|
|
3302
|
+
let count = 0;
|
|
3303
|
+
if (source.startsWith("variants.")) {
|
|
3304
|
+
for (const p of products) {
|
|
3305
|
+
for (const v of getVariants(p, staged)) {
|
|
3306
|
+
const val = resolveVariantValue(v, source);
|
|
3307
|
+
if (filters == null ? void 0 : filters.some((f) => f.match(val))) {
|
|
3308
|
+
count++;
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
} else {
|
|
3313
|
+
throw new Error("not supported");
|
|
3314
|
+
}
|
|
3315
|
+
return {
|
|
3316
|
+
type: "filter",
|
|
3317
|
+
count
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3320
|
+
rangeFacet(source, ranges, products, staged) {
|
|
3321
|
+
const counts = (ranges == null ? void 0 : ranges.map((range) => {
|
|
3322
|
+
if (source.startsWith("variants.")) {
|
|
3323
|
+
const values = [];
|
|
3324
|
+
for (const p of products) {
|
|
3325
|
+
for (const v of getVariants(p, staged)) {
|
|
3326
|
+
const val = resolveVariantValue(v, source);
|
|
3327
|
+
if (val === void 0) {
|
|
3328
|
+
continue;
|
|
3329
|
+
}
|
|
3330
|
+
if (range.match(val)) {
|
|
3331
|
+
values.push(val);
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
const numValues = values.length;
|
|
3336
|
+
return {
|
|
3337
|
+
type: "double",
|
|
3338
|
+
from: range.start || 0,
|
|
3339
|
+
fromStr: range.start !== null ? Number(range.start).toFixed(1) : "",
|
|
3340
|
+
to: range.stop || 0,
|
|
3341
|
+
toStr: range.stop !== null ? Number(range.stop).toFixed(1) : "",
|
|
3342
|
+
count: numValues,
|
|
3343
|
+
total: values.reduce((a, b) => a + b, 0),
|
|
3344
|
+
min: numValues > 0 ? Math.min(...values) : 0,
|
|
3345
|
+
max: numValues > 0 ? Math.max(...values) : 0,
|
|
3346
|
+
mean: numValues > 0 ? mean(values) : 0
|
|
3347
|
+
};
|
|
3348
|
+
} else {
|
|
3349
|
+
throw new Error("not supported");
|
|
3350
|
+
}
|
|
3351
|
+
})) || [];
|
|
3352
|
+
const data = {
|
|
3353
|
+
type: "range",
|
|
3354
|
+
dataType: "number",
|
|
3355
|
+
ranges: counts
|
|
3356
|
+
};
|
|
3357
|
+
return data;
|
|
3358
|
+
}
|
|
3359
|
+
};
|
|
3360
|
+
var mean = (arr) => {
|
|
3361
|
+
let total = 0;
|
|
3362
|
+
for (let i = 0; i < arr.length; i++) {
|
|
3363
|
+
total += arr[i];
|
|
3364
|
+
}
|
|
3365
|
+
return total / arr.length;
|
|
3154
3366
|
};
|
|
3155
3367
|
|
|
3156
3368
|
// src/repositories/product-projection.ts
|
|
@@ -3178,6 +3390,7 @@ var ProductProjectionRepository = class extends AbstractResourceRepository {
|
|
|
3178
3390
|
const results = this._searchService.search(context.projectKey, {
|
|
3179
3391
|
filter: QueryParamsAsArray(query.filter),
|
|
3180
3392
|
"filter.query": QueryParamsAsArray(query["filter.query"]),
|
|
3393
|
+
facet: QueryParamsAsArray(query.facet),
|
|
3181
3394
|
offset: query.offset ? Number(query.offset) : void 0,
|
|
3182
3395
|
limit: query.limit ? Number(query.limit) : void 0,
|
|
3183
3396
|
expand: QueryParamsAsArray(query.expand)
|