@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.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 generateMatchFunc2 = (filter) => {
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
- const expr = parser.parse({ terminals: [bp - 1] });
2918
- if (Array.isArray(expr)) {
2919
- return (obj) => {
2920
- return expr.includes(obj);
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 (typeof expr === "function") {
2924
- return (obj) => {
2925
- return expr(obj);
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 (obj) => {
2929
- return obj === expr;
2956
+ return {
2957
+ source: left,
2958
+ type: expressions[0].type,
2959
+ children: expressions
2930
2960
  };
2931
2961
  }).nud("STRING", 20, (t) => {
2932
- return t.token.groups[1];
2962
+ return {
2963
+ type: "Symbol",
2964
+ kind: "string",
2965
+ value: t.token.groups[1]
2966
+ };
2933
2967
  }).nud("INT", 5, (t) => {
2934
- return parseInt(t.token.match, 10);
2968
+ return {
2969
+ type: "Symbol",
2970
+ kind: "int",
2971
+ value: parseInt(t.token.match, 10)
2972
+ };
2935
2973
  }).nud("STAR", 5, (t) => {
2936
- return null;
2974
+ return {
2975
+ type: "Symbol",
2976
+ kind: "any",
2977
+ value: null
2978
+ };
2937
2979
  }).nud("EXISTS", 10, ({ bp }) => {
2938
- return (val) => {
2939
- return val !== void 0;
2980
+ return {
2981
+ type: "FilterExpression",
2982
+ match: (obj) => {
2983
+ return obj !== void 0;
2984
+ }
2940
2985
  };
2941
2986
  }).nud("MISSING", 10, ({ bp }) => {
2942
- return (val) => {
2943
- return val === void 0;
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 [left, expr];
3006
+ return {
3007
+ start: left.value,
3008
+ stop: expr.value
3009
+ };
2955
3010
  }).nud("RANGE", 20, ({ bp }) => {
2956
- lexer.next();
2957
- const [start, stop] = parser.parse();
2958
- console.log(start, stop);
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
- const result = parser.parse();
2978
- if (typeof result !== "function") {
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
- return result;
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)