@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.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 generateMatchFunc2 = (filter) => {
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
- const expr = parser.parse({ terminals: [bp - 1] });
2885
- if (Array.isArray(expr)) {
2886
- return (obj) => {
2887
- return expr.includes(obj);
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 (typeof expr === "function") {
2891
- return (obj) => {
2892
- return expr(obj);
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 (obj) => {
2896
- return obj === expr;
2923
+ return {
2924
+ source: left,
2925
+ type: expressions[0].type,
2926
+ children: expressions
2897
2927
  };
2898
2928
  }).nud("STRING", 20, (t) => {
2899
- return t.token.groups[1];
2929
+ return {
2930
+ type: "Symbol",
2931
+ kind: "string",
2932
+ value: t.token.groups[1]
2933
+ };
2900
2934
  }).nud("INT", 5, (t) => {
2901
- return parseInt(t.token.match, 10);
2935
+ return {
2936
+ type: "Symbol",
2937
+ kind: "int",
2938
+ value: parseInt(t.token.match, 10)
2939
+ };
2902
2940
  }).nud("STAR", 5, (t) => {
2903
- return null;
2941
+ return {
2942
+ type: "Symbol",
2943
+ kind: "any",
2944
+ value: null
2945
+ };
2904
2946
  }).nud("EXISTS", 10, ({ bp }) => {
2905
- return (val) => {
2906
- return val !== void 0;
2947
+ return {
2948
+ type: "FilterExpression",
2949
+ match: (obj) => {
2950
+ return obj !== void 0;
2951
+ }
2907
2952
  };
2908
2953
  }).nud("MISSING", 10, ({ bp }) => {
2909
- return (val) => {
2910
- return val === void 0;
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 [left, expr];
2973
+ return {
2974
+ start: left.value,
2975
+ stop: expr.value
2976
+ };
2922
2977
  }).nud("RANGE", 20, ({ bp }) => {
2923
- lexer.next();
2924
- const [start, stop] = parser.parse();
2925
- console.log(start, stop);
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
- const result = parser.parse();
2945
- if (typeof result !== "function") {
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
- return result;
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)