@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  import express, { Router, Request, Response } from 'express';
2
2
  import * as ctp from '@commercetools/platform-sdk';
3
- import { Project, BaseResource, PagedQueryResponse, ResourceIdentifier, QueryParam, ProductProjectionPagedSearchResponse, Product, ProductProjection, ProductDraft, ReferenceTypeId, ShoppingListDraft, ShoppingList, CartDraft, Cart, CartAddLineItemAction, CartRemoveLineItemAction, CartSetBillingAddressAction, CartSetShippingMethodAction, CartSetCountryAction, CartSetCustomerEmailAction, CartSetCustomFieldAction, CartSetCustomTypeAction, CartSetLocaleAction, CartSetShippingAddressAction, LineItemDraft, LineItem, CustomerDraft, Customer, CustomerChangeEmailAction, CustomObjectDraft, CustomObject, InventoryEntryDraft, InventoryEntry, InventoryEntryChangeQuantityAction, InventoryEntrySetExpectedDeliveryAction, InventoryEntrySetCustomFieldAction, InventoryEntrySetCustomTypeAction, InventoryEntrySetRestockableInDaysAction, OrderFromCartDraft, Order, CartReference, OrderImportDraft, OrderAddPaymentAction, OrderChangeOrderStateAction, OrderChangePaymentStateAction, OrderTransitionStateAction, OrderSetBillingAddressAction, OrderSetCustomerEmailAction, OrderSetCustomFieldAction, OrderSetCustomTypeAction, OrderSetLocaleAction, OrderSetOrderNumberAction, OrderSetShippingAddressAction, OrderSetStoreAction, PaymentDraft, Payment, TransactionDraft, PaymentSetCustomFieldAction, PaymentSetCustomTypeAction, PaymentAddTransactionAction, PaymentChangeTransactionStateAction, PaymentTransitionStateAction, ProductPublishAction, ProductSetAttributeAction, ProductTypeDraft, ProductType, AttributeDefinitionDraft, AttributeDefinition, ProductTypeUpdateAction, ShippingMethodDraft, ShippingMethod, ShippingMethodUpdateAction, StateDraft, State, StateUpdateAction, TaxCategoryDraft, TaxCategory, TaxCategoryUpdateAction, ProductDiscountDraft, ProductDiscount, ProductDiscountUpdateAction, UpdateAction } from '@commercetools/platform-sdk';
3
+ import { Project, BaseResource, PagedQueryResponse, ResourceIdentifier, QueryParam, ProductProjectionPagedSearchResponse, Product, ProductProjection, FacetResults, TermFacetResult, FilteredFacetResult, RangeFacetResult, ProductDraft, ReferenceTypeId, ShoppingListDraft, ShoppingList, CartDraft, Cart, CartAddLineItemAction, CartRemoveLineItemAction, CartSetBillingAddressAction, CartSetShippingMethodAction, CartSetCountryAction, CartSetCustomerEmailAction, CartSetCustomFieldAction, CartSetCustomTypeAction, CartSetLocaleAction, CartSetShippingAddressAction, LineItemDraft, LineItem, CustomerDraft, Customer, CustomerChangeEmailAction, CustomObjectDraft, CustomObject, InventoryEntryDraft, InventoryEntry, InventoryEntryChangeQuantityAction, InventoryEntrySetExpectedDeliveryAction, InventoryEntrySetCustomFieldAction, InventoryEntrySetCustomTypeAction, InventoryEntrySetRestockableInDaysAction, OrderFromCartDraft, Order, CartReference, OrderImportDraft, OrderAddPaymentAction, OrderChangeOrderStateAction, OrderChangePaymentStateAction, OrderTransitionStateAction, OrderSetBillingAddressAction, OrderSetCustomerEmailAction, OrderSetCustomFieldAction, OrderSetCustomTypeAction, OrderSetLocaleAction, OrderSetOrderNumberAction, OrderSetShippingAddressAction, OrderSetStoreAction, PaymentDraft, Payment, TransactionDraft, PaymentSetCustomFieldAction, PaymentSetCustomTypeAction, PaymentAddTransactionAction, PaymentChangeTransactionStateAction, PaymentTransitionStateAction, ProductPublishAction, ProductSetAttributeAction, ProductTypeDraft, ProductType, AttributeDefinitionDraft, AttributeDefinition, ProductTypeUpdateAction, ShippingMethodDraft, ShippingMethod, ShippingMethodUpdateAction, StateDraft, State, StateUpdateAction, TaxCategoryDraft, TaxCategory, TaxCategoryUpdateAction, ProductDiscountDraft, ProductDiscount, ProductDiscountUpdateAction, UpdateAction } from '@commercetools/platform-sdk';
4
4
  import { ParsedQs } from 'qs';
5
5
 
6
6
  declare type GetParams$1 = {
@@ -31,6 +31,21 @@ declare abstract class AbstractStorage {
31
31
  abstract expand<T>(projectKey: string, obj: T, clause: undefined | string | string[]): T;
32
32
  }
33
33
 
34
+ /**
35
+ * This module implements the commercetools product projection filter expression.
36
+ */
37
+
38
+ declare type RangeExpression = {
39
+ type: 'RangeExpression';
40
+ start?: number;
41
+ stop?: number;
42
+ match: (obj: any) => boolean;
43
+ };
44
+ declare type FilterExpression = {
45
+ type: 'FilterExpression';
46
+ match: (obj: any) => boolean;
47
+ };
48
+
34
49
  declare type ProductProjectionSearchParams = {
35
50
  fuzzy?: boolean;
36
51
  fuzzyLevel?: number;
@@ -58,6 +73,15 @@ declare class ProductProjectionSearch {
58
73
  constructor(storage: AbstractStorage);
59
74
  search(projectKey: string, params: ProductProjectionSearchParams): ProductProjectionPagedSearchResponse;
60
75
  transform(product: Product): ProductProjection;
76
+ getFacets(params: ProductProjectionSearchParams, products: Product[]): FacetResults;
77
+ /**
78
+ * TODO: This implemention needs the following additional features:
79
+ * - counting products
80
+ * - correct dataType
81
+ */
82
+ termFacet(facet: string, products: Product[], staged: boolean): TermFacetResult;
83
+ filterFacet(source: string, filters: FilterExpression[] | undefined, products: Product[], staged: boolean): FilteredFacetResult;
84
+ rangeFacet(source: string, ranges: RangeExpression[] | undefined, products: Product[], staged: boolean): RangeFacetResult;
61
85
  }
62
86
 
63
87
  declare class ProductProjectionRepository extends AbstractResourceRepository {
@@ -44420,7 +44420,7 @@ ${this.pendingMocks().join("\n")}`
44420
44420
  function maxBy(array, iteratee2) {
44421
44421
  return array && array.length ? baseExtremum(array, getIteratee(iteratee2, 2), baseGt) : undefined2;
44422
44422
  }
44423
- function mean(array) {
44423
+ function mean2(array) {
44424
44424
  return baseMean(array, identity);
44425
44425
  }
44426
44426
  function meanBy(array, iteratee2) {
@@ -44689,7 +44689,7 @@ ${this.pendingMocks().join("\n")}`
44689
44689
  lodash.lte = lte;
44690
44690
  lodash.max = max;
44691
44691
  lodash.maxBy = maxBy;
44692
- lodash.mean = mean;
44692
+ lodash.mean = mean2;
44693
44693
  lodash.meanBy = meanBy;
44694
44694
  lodash.min = min;
44695
44695
  lodash.minBy = minBy;
@@ -45736,6 +45736,21 @@ ${this.pendingMocks().join("\n")}`
45736
45736
  version: 0
45737
45737
  };
45738
45738
  };
45739
+ var nestedLookup = (obj, path) => {
45740
+ if (!path || path === "") {
45741
+ return obj;
45742
+ }
45743
+ const parts = path.split(".");
45744
+ let val = obj;
45745
+ for (let i = 0; i < parts.length; i++) {
45746
+ const part = parts[i];
45747
+ if (val == void 0) {
45748
+ return void 0;
45749
+ }
45750
+ val = val[part];
45751
+ }
45752
+ return val;
45753
+ };
45739
45754
  var QueryParamsAsArray = (input) => {
45740
45755
  if (input == void 0) {
45741
45756
  return [];
@@ -47820,38 +47835,71 @@ ${this.pendingMocks().join("\n")}`
47820
47835
  var getLexer2 = (value) => {
47821
47836
  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);
47822
47837
  };
47823
- var generateMatchFunc2 = (filter) => {
47838
+ var parseFilter = (filter) => {
47824
47839
  const lexer = getLexer2(filter);
47825
47840
  const parser = new import_pratt2.default(lexer).builder().nud("IDENTIFIER", 100, (t) => {
47826
47841
  return t.token.match;
47827
47842
  }).led(":", 100, ({ left, bp }) => {
47828
- const expr = parser.parse({ terminals: [bp - 1] });
47829
- if (Array.isArray(expr)) {
47830
- return (obj) => {
47831
- return expr.includes(obj);
47832
- };
47833
- }
47834
- if (typeof expr === "function") {
47835
- return (obj) => {
47836
- return expr(obj);
47843
+ let parsed = parser.parse({ terminals: [bp - 1] });
47844
+ let expressions;
47845
+ expressions = !Array.isArray(parsed) ? [parsed] : parsed;
47846
+ const unique = new Set(expressions.map((expr) => expr.type));
47847
+ if (unique.size > 1) {
47848
+ throw new Error("Invalid expression");
47849
+ }
47850
+ if (expressions.some((expr) => expr.type == "Symbol")) {
47851
+ return {
47852
+ source: left,
47853
+ type: "FilterExpression",
47854
+ children: expressions.map((e) => {
47855
+ if (e.type != "Symbol") {
47856
+ throw new Error("Invalid expression");
47857
+ }
47858
+ return {
47859
+ type: "FilterExpression",
47860
+ match: (obj) => {
47861
+ return obj === e.value;
47862
+ }
47863
+ };
47864
+ })
47837
47865
  };
47838
47866
  }
47839
- return (obj) => {
47840
- return obj === expr;
47867
+ return {
47868
+ source: left,
47869
+ type: expressions[0].type,
47870
+ children: expressions
47841
47871
  };
47842
47872
  }).nud("STRING", 20, (t) => {
47843
- return t.token.groups[1];
47873
+ return {
47874
+ type: "Symbol",
47875
+ kind: "string",
47876
+ value: t.token.groups[1]
47877
+ };
47844
47878
  }).nud("INT", 5, (t) => {
47845
- return parseInt(t.token.match, 10);
47879
+ return {
47880
+ type: "Symbol",
47881
+ kind: "int",
47882
+ value: parseInt(t.token.match, 10)
47883
+ };
47846
47884
  }).nud("STAR", 5, (t) => {
47847
- return null;
47885
+ return {
47886
+ type: "Symbol",
47887
+ kind: "any",
47888
+ value: null
47889
+ };
47848
47890
  }).nud("EXISTS", 10, ({ bp }) => {
47849
- return (val) => {
47850
- return val !== void 0;
47891
+ return {
47892
+ type: "FilterExpression",
47893
+ match: (obj) => {
47894
+ return obj !== void 0;
47895
+ }
47851
47896
  };
47852
47897
  }).nud("MISSING", 10, ({ bp }) => {
47853
- return (val) => {
47854
- return val === void 0;
47898
+ return {
47899
+ type: "FilterExpression",
47900
+ match: (obj) => {
47901
+ return obj === void 0;
47902
+ }
47855
47903
  };
47856
47904
  }).led("COMMA", 200, ({ left, token, bp }) => {
47857
47905
  const expr = parser.parse({ terminals: [bp - 1] });
@@ -47860,38 +47908,74 @@ ${this.pendingMocks().join("\n")}`
47860
47908
  } else {
47861
47909
  return [left, expr];
47862
47910
  }
47911
+ }).nud("(", 100, (t) => {
47912
+ const expr = parser.parse({ terminals: [")"] });
47913
+ lexer.expect(")");
47914
+ return expr;
47863
47915
  }).bp(")", 0).led("TO", 20, ({ left, bp }) => {
47864
47916
  const expr = parser.parse({ terminals: [bp - 1] });
47865
- return [left, expr];
47917
+ return {
47918
+ start: left.value,
47919
+ stop: expr.value
47920
+ };
47866
47921
  }).nud("RANGE", 20, ({ bp }) => {
47867
- lexer.next();
47868
- const [start, stop] = parser.parse();
47869
- console.log(start, stop);
47870
- if (start !== null && stop !== null) {
47871
- return (obj) => {
47872
- return obj >= start && obj <= stop;
47873
- };
47874
- } else if (start === null && stop !== null) {
47875
- return (obj) => {
47876
- return obj <= stop;
47877
- };
47878
- } else if (start !== null && stop === null) {
47879
- return (obj) => {
47880
- return obj >= start;
47881
- };
47882
- } else {
47883
- return (obj) => {
47884
- return true;
47922
+ let ranges = parser.parse();
47923
+ if (!Array.isArray(ranges)) {
47924
+ ranges = [ranges];
47925
+ }
47926
+ return ranges.map((range) => {
47927
+ let func = void 0;
47928
+ if (range.start !== null && range.stop !== null) {
47929
+ func = (obj) => {
47930
+ return obj >= range.start && obj <= range.stop;
47931
+ };
47932
+ } else if (range.start === null && range.stop !== null) {
47933
+ func = (obj) => {
47934
+ return obj <= range.stop;
47935
+ };
47936
+ } else if (range.start !== null && range.stop === null) {
47937
+ func = (obj) => {
47938
+ return obj >= range.start;
47939
+ };
47940
+ } else {
47941
+ func = (obj) => {
47942
+ return true;
47943
+ };
47944
+ }
47945
+ return {
47946
+ type: "RangeExpression",
47947
+ start: range.start,
47948
+ stop: range.stop,
47949
+ match: func
47885
47950
  };
47886
- }
47951
+ });
47887
47952
  }).build();
47888
- const result = parser.parse();
47889
- if (typeof result !== "function") {
47953
+ return parser.parse();
47954
+ };
47955
+ var generateMatchFunc2 = (filter) => {
47956
+ const result = parseFilter(filter);
47957
+ if (!result) {
47890
47958
  const lines = filter.split("\n");
47891
47959
  const column = lines[lines.length - 1].length;
47892
47960
  throw new Error(`Syntax error while parsing '${filter}'.`);
47893
47961
  }
47894
- return result;
47962
+ if (result.type == "TermExpression") {
47963
+ throw new Error(`Syntax error while parsing '${filter}'.`);
47964
+ }
47965
+ return (obj) => {
47966
+ if (!result.children)
47967
+ return false;
47968
+ return result.children.some((c) => c.match(obj));
47969
+ };
47970
+ };
47971
+ var generateFacetFunc = (filter) => {
47972
+ if (!filter.includes(":")) {
47973
+ return {
47974
+ source: filter,
47975
+ type: "TermExpression"
47976
+ };
47977
+ }
47978
+ return parseFilter(filter);
47895
47979
  };
47896
47980
  var filterProduct = (source, exprFunc) => {
47897
47981
  return (p, markMatchingVariants) => {
@@ -47921,6 +48005,9 @@ ${this.pendingMocks().join("\n")}`
47921
48005
  if (path === void 0) {
47922
48006
  return obj;
47923
48007
  }
48008
+ if (path.startsWith("variants.")) {
48009
+ path = path.substring(path.indexOf(".") + 1);
48010
+ }
47924
48011
  if (path.startsWith("attributes.")) {
47925
48012
  const [, attrName, ...rest] = path.split(".");
47926
48013
  if (!obj.attributes) {
@@ -47937,21 +48024,6 @@ ${this.pendingMocks().join("\n")}`
47937
48024
  }
47938
48025
  return nestedLookup(obj, path);
47939
48026
  };
47940
- var nestedLookup = (obj, path) => {
47941
- if (!path || path === "") {
47942
- return obj;
47943
- }
47944
- const parts = path.split(".");
47945
- let val = obj;
47946
- for (let i = 0; i < parts.length; i++) {
47947
- const part = parts[i];
47948
- if (val == void 0) {
47949
- return void 0;
47950
- }
47951
- val = val[part];
47952
- }
47953
- return val;
47954
- };
47955
48027
  var getVariants = (p, staged) => {
47956
48028
  var _a, _b, _c, _d;
47957
48029
  return [
@@ -48044,6 +48116,7 @@ ${this.pendingMocks().join("\n")}`
48044
48116
  );
48045
48117
  }
48046
48118
  }
48119
+ const facets = this.getFacets(params, resources);
48047
48120
  if (params["filter.query"]) {
48048
48121
  try {
48049
48122
  const filters = params["filter.query"].map(
@@ -48077,7 +48150,7 @@ ${this.pendingMocks().join("\n")}`
48077
48150
  offset,
48078
48151
  limit,
48079
48152
  results: resources.map(this.transform),
48080
- facets: {}
48153
+ facets
48081
48154
  };
48082
48155
  }
48083
48156
  transform(product) {
@@ -48095,6 +48168,145 @@ ${this.pendingMocks().join("\n")}`
48095
48168
  productType: product.productType
48096
48169
  };
48097
48170
  }
48171
+ getFacets(params, products) {
48172
+ if (!params.facet)
48173
+ return {};
48174
+ const staged = false;
48175
+ const result = {};
48176
+ for (const facet of params.facet) {
48177
+ const expression = generateFacetFunc(facet);
48178
+ if (expression.type === "TermExpression") {
48179
+ result[facet] = this.termFacet(expression.source, products, staged);
48180
+ }
48181
+ if (expression.type === "RangeExpression") {
48182
+ result[expression.source] = this.rangeFacet(
48183
+ expression.source,
48184
+ expression.children,
48185
+ products,
48186
+ staged
48187
+ );
48188
+ }
48189
+ if (expression.type === "FilterExpression") {
48190
+ result[expression.source] = this.filterFacet(
48191
+ expression.source,
48192
+ expression.children,
48193
+ products,
48194
+ staged
48195
+ );
48196
+ }
48197
+ }
48198
+ return result;
48199
+ }
48200
+ termFacet(facet, products, staged) {
48201
+ const result = {
48202
+ type: "terms",
48203
+ dataType: "text",
48204
+ missing: 0,
48205
+ total: 0,
48206
+ other: 0,
48207
+ terms: []
48208
+ };
48209
+ const terms = {};
48210
+ if (facet.startsWith("variants.")) {
48211
+ products.forEach((p) => {
48212
+ const variants = getVariants(p, staged);
48213
+ variants.forEach((v) => {
48214
+ result.total++;
48215
+ let value = resolveVariantValue(v, facet);
48216
+ if (value === void 0) {
48217
+ result.missing++;
48218
+ } else {
48219
+ if (typeof value === "number") {
48220
+ value = Number(value).toFixed(1);
48221
+ }
48222
+ terms[value] = value in terms ? terms[value] + 1 : 1;
48223
+ }
48224
+ });
48225
+ });
48226
+ } else {
48227
+ products.forEach((p) => {
48228
+ const value = nestedLookup(p, facet);
48229
+ result.total++;
48230
+ if (value === void 0) {
48231
+ result.missing++;
48232
+ } else {
48233
+ terms[value] = value in terms ? terms[value] + 1 : 1;
48234
+ }
48235
+ });
48236
+ }
48237
+ for (const term in terms) {
48238
+ result.terms.push({
48239
+ term,
48240
+ count: terms[term]
48241
+ });
48242
+ }
48243
+ return result;
48244
+ }
48245
+ filterFacet(source, filters, products, staged) {
48246
+ let count = 0;
48247
+ if (source.startsWith("variants.")) {
48248
+ for (const p of products) {
48249
+ for (const v of getVariants(p, staged)) {
48250
+ const val = resolveVariantValue(v, source);
48251
+ if (filters == null ? void 0 : filters.some((f) => f.match(val))) {
48252
+ count++;
48253
+ }
48254
+ }
48255
+ }
48256
+ } else {
48257
+ throw new Error("not supported");
48258
+ }
48259
+ return {
48260
+ type: "filter",
48261
+ count
48262
+ };
48263
+ }
48264
+ rangeFacet(source, ranges, products, staged) {
48265
+ const counts = (ranges == null ? void 0 : ranges.map((range) => {
48266
+ if (source.startsWith("variants.")) {
48267
+ const values = [];
48268
+ for (const p of products) {
48269
+ for (const v of getVariants(p, staged)) {
48270
+ const val = resolveVariantValue(v, source);
48271
+ if (val === void 0) {
48272
+ continue;
48273
+ }
48274
+ if (range.match(val)) {
48275
+ values.push(val);
48276
+ }
48277
+ }
48278
+ }
48279
+ const numValues = values.length;
48280
+ return {
48281
+ type: "double",
48282
+ from: range.start || 0,
48283
+ fromStr: range.start !== null ? Number(range.start).toFixed(1) : "",
48284
+ to: range.stop || 0,
48285
+ toStr: range.stop !== null ? Number(range.stop).toFixed(1) : "",
48286
+ count: numValues,
48287
+ total: values.reduce((a, b) => a + b, 0),
48288
+ min: numValues > 0 ? Math.min(...values) : 0,
48289
+ max: numValues > 0 ? Math.max(...values) : 0,
48290
+ mean: numValues > 0 ? mean(values) : 0
48291
+ };
48292
+ } else {
48293
+ throw new Error("not supported");
48294
+ }
48295
+ })) || [];
48296
+ const data = {
48297
+ type: "range",
48298
+ dataType: "number",
48299
+ ranges: counts
48300
+ };
48301
+ return data;
48302
+ }
48303
+ };
48304
+ var mean = (arr) => {
48305
+ let total = 0;
48306
+ for (let i = 0; i < arr.length; i++) {
48307
+ total += arr[i];
48308
+ }
48309
+ return total / arr.length;
48098
48310
  };
48099
48311
 
48100
48312
  // src/repositories/product-projection.ts
@@ -48122,6 +48334,7 @@ ${this.pendingMocks().join("\n")}`
48122
48334
  const results = this._searchService.search(context.projectKey, {
48123
48335
  filter: QueryParamsAsArray(query.filter),
48124
48336
  "filter.query": QueryParamsAsArray(query["filter.query"]),
48337
+ facet: QueryParamsAsArray(query.facet),
48125
48338
  offset: query.offset ? Number(query.offset) : void 0,
48126
48339
  limit: query.limit ? Number(query.limit) : void 0,
48127
48340
  expand: QueryParamsAsArray(query.expand)