@softwear/latestcollectioncore 1.0.160 → 1.0.162

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.
@@ -99,6 +99,28 @@ function buildAggregationEvaluator(aggregationExpression) {
99
99
  function prepareSubTotalAggKey(aggKey) {
100
100
  return aggKey.split('\t').slice(0, -1).join('\t').concat(' Σ');
101
101
  }
102
+ /** Same as filtrex std.coerceBoolean(customProp(...)) for bare join keys on the transaction */
103
+ function coerceJoinKeyValue(v) {
104
+ return typeof v === 'boolean' ? +v : v;
105
+ }
106
+ function getTrieLeaf(root, transaction, keys) {
107
+ const nrKeys = keys.length;
108
+ if (nrKeys === 0)
109
+ return root;
110
+ let node = root;
111
+ for (let i = 0; i < nrKeys; i++) {
112
+ const k = coerceJoinKeyValue(transaction[keys[i]]);
113
+ if (!node.children)
114
+ node.children = new Map();
115
+ let next = node.children.get(k);
116
+ if (!next) {
117
+ next = {};
118
+ node.children.set(k, next);
119
+ }
120
+ node = next;
121
+ }
122
+ return node;
123
+ }
102
124
  /*
103
125
  * A factory function that returns a function that can be used to aggregate transactions
104
126
  * The factory function is called once for each aggregationExpression
@@ -122,47 +144,36 @@ function prepareSubTotalAggKey(aggKey) {
122
144
  * @returns {Function} - The aggregator function
123
145
  */
124
146
  function aggregator({ beginTimestamp, endTimestamp, filterExpression, aggregationExpression, rawAggregations, maxRows, totals, subtotalsForOuterGrouper, parentGroupTotals, }) {
125
- const filterExpressionCache = {};
126
147
  let filter;
127
- let filterDependencyEvaluator;
148
+ let filterGranularity = [];
149
+ const filterTrieRoot = {};
128
150
  if (filterExpression) {
129
151
  filter = (0, filtrex_1.compileExpression)(filterExpression, filtrexOptions);
130
- // Maintain a cache of evaluated filterExpressions
131
- // The granularity of the cache is determined by the joined tables in the filterExpression
132
- const filterGranularity = Object.entries(globalJoinableTables)
152
+ filterGranularity = Object.entries(globalJoinableTables)
133
153
  .filter((join) => filterExpression.includes(join[0] + '.'))
134
154
  .map((join) => join[1]);
135
- filterDependencyEvaluator = (0, filtrex_1.compileExpression)(filterGranularity.join('+'), filtrexOptions);
136
155
  }
137
156
  const aggregationEvaluator = buildAggregationEvaluator(aggregationExpression);
138
- // Maintain a cache of evaluated aggregationExpressions
139
- // The granularity of the cache is determined by the joined tables in the aggregationExpression
140
- const aggregationExpressionCache = {};
141
157
  const aggregationGranularity = Object.entries(globalJoinableTables)
142
158
  .filter((join) => aggregationExpression.includes(join[0] + '.'))
143
159
  .map((join) => join[1]);
144
- let aggregationDependencyExpression = aggregationGranularity.join('+');
145
- if (!aggregationDependencyExpression)
146
- aggregationDependencyExpression = '"N.A."';
147
- const aggregationDependencyEvaluator = (0, filtrex_1.compileExpression)(aggregationDependencyExpression, filtrexOptions);
160
+ const aggregationTrieRoot = {};
148
161
  return function (transaction) {
149
162
  if (filter) {
150
- const filterDependency = filterDependencyEvaluator(transaction);
151
- const filterExpression = filterExpressionCache[filterDependency];
152
- if (filterExpression == -1)
163
+ const filterLeaf = getTrieLeaf(filterTrieRoot, transaction, filterGranularity);
164
+ if (filterLeaf.filterResult === -1)
153
165
  return;
154
- if (!filterExpression) {
155
- filterExpressionCache[filterDependency] = filter(transaction) ? 1 : -1;
156
- if (filterExpressionCache[filterDependency] == -1)
166
+ if (filterLeaf.filterResult === undefined) {
167
+ filterLeaf.filterResult = filter(transaction) ? 1 : -1;
168
+ if (filterLeaf.filterResult === -1)
157
169
  return;
158
170
  }
159
171
  }
160
- const aggregationDependency = aggregationDependencyEvaluator(transaction);
161
- let aggregateKey = aggregationExpressionCache[aggregationDependency];
162
- if (!aggregateKey) {
163
- aggregateKey = aggregationEvaluator(transaction);
164
- aggregationExpressionCache[aggregationDependency] = aggregateKey;
172
+ const aggregateKeyLeaf = getTrieLeaf(aggregationTrieRoot, transaction, aggregationGranularity);
173
+ if (!aggregateKeyLeaf.aggregateKey) {
174
+ aggregateKeyLeaf.aggregateKey = aggregationEvaluator(transaction);
165
175
  }
176
+ const aggregateKey = aggregateKeyLeaf.aggregateKey;
166
177
  // Prepare joined values for derived fields
167
178
  if (transaction.type == types_1.transactionTypeE.SALE) {
168
179
  const sku = globalRelations['sku'][transaction.ean];
@@ -1,3 +1,2 @@
1
- import { SkuI, BrandSettingI } from './index';
2
- import { mappingStrategyE } from './types';
1
+ import { SkuI, BrandSettingI, mappingStrategyE } from './index';
3
2
  export default function (brands: Array<BrandSettingI>, strategy: mappingStrategyE): (sku: SkuI) => SkuI;
package/dist/index.d.ts CHANGED
@@ -15,14 +15,7 @@ export { default as pivotTable } from './pivotTable';
15
15
  export { default as round2 } from './round2';
16
16
  export { default as sizeToMap } from './sizeToMap';
17
17
  export { default as transaction } from './transaction';
18
- export type { AggregateFnI, AggregatorFnI, AttributeI, BrandSettingI, ColorI, dbTransactionI, DocumentItemI, GroupI, HrTimeframeI, ImageI, MarkedSkuI, MatrixI, ProductI, RaGI, RowI, SkuI, StockTransferDataI, StockTransferMatrixI, StockTransferSelectionI, TransactionI, } from './types';
19
- import * as types from './types';
20
- export declare const mappingStrategyE: typeof types.mappingStrategyE;
21
- export declare const subscriptionE: typeof types.subscriptionE;
22
- export declare const tagTypeE: typeof types.tagTypeE;
23
- export declare const TimeGranularityE: typeof types.TimeGranularityE;
24
- export declare const transactionTypeE: typeof types.transactionTypeE;
25
- export declare const vatCategoryE: typeof types.vatCategoryE;
18
+ export * from './types';
26
19
  export * from './consts';
27
20
  export { default as lcAxios, createAxiosInstance, axiosRetry, exponentialDelay, isAxiosError, } from './lcAxios';
28
21
  export type { AxiosRequestConfig, AxiosResponse, AxiosPromise, AxiosError, AxiosTransformer, AxiosRetryOptions, AxiosRequestConfigAny, } from './lcAxios';
package/dist/index.js CHANGED
@@ -10,18 +10,6 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
10
10
  if (k2 === undefined) k2 = k;
11
11
  o[k2] = m[k];
12
12
  }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
15
  };
@@ -29,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
29
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
30
18
  };
31
19
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.isAxiosError = exports.exponentialDelay = exports.axiosRetry = exports.createAxiosInstance = exports.lcAxios = exports.vatCategoryE = exports.transactionTypeE = exports.TimeGranularityE = exports.tagTypeE = exports.subscriptionE = exports.mappingStrategyE = exports.transaction = exports.sizeToMap = exports.round2 = exports.pivotTable = exports.isean13 = exports.imageBinder = exports.hasOnlyDigits = exports.hashBrand = exports.getPreferedPropertyMappings = exports.getBrandName = exports.findSkuByBarcode = exports.ensureArray = exports.edifact = exports.ean13 = exports.deepCopy = exports.buildPropertyMappingFn = exports.articleStatus = void 0;
20
+ exports.isAxiosError = exports.exponentialDelay = exports.axiosRetry = exports.createAxiosInstance = exports.lcAxios = exports.transaction = exports.sizeToMap = exports.round2 = exports.pivotTable = exports.isean13 = exports.imageBinder = exports.hasOnlyDigits = exports.hashBrand = exports.getPreferedPropertyMappings = exports.getBrandName = exports.findSkuByBarcode = exports.ensureArray = exports.edifact = exports.ean13 = exports.deepCopy = exports.buildPropertyMappingFn = exports.articleStatus = void 0;
33
21
  var articleStatus_1 = require("./articleStatus");
34
22
  Object.defineProperty(exports, "articleStatus", { enumerable: true, get: function () { return __importDefault(articleStatus_1).default; } });
35
23
  var buildPropertyMappingFn_1 = require("./buildPropertyMappingFn");
@@ -64,16 +52,7 @@ var sizeToMap_1 = require("./sizeToMap");
64
52
  Object.defineProperty(exports, "sizeToMap", { enumerable: true, get: function () { return __importDefault(sizeToMap_1).default; } });
65
53
  var transaction_1 = require("./transaction");
66
54
  Object.defineProperty(exports, "transaction", { enumerable: true, get: function () { return __importDefault(transaction_1).default; } });
67
- // Runtime enums: use `export const x = types.x`, not `export { x } from './types'`.
68
- // TS emits `Object.defineProperty(exports, "x", { get: ... })` for re-exports; Vite/esbuild
69
- // does not treat those getters as static named exports for ESM interop.
70
- const types = __importStar(require("./types"));
71
- exports.mappingStrategyE = types.mappingStrategyE;
72
- exports.subscriptionE = types.subscriptionE;
73
- exports.tagTypeE = types.tagTypeE;
74
- exports.TimeGranularityE = types.TimeGranularityE;
75
- exports.transactionTypeE = types.transactionTypeE;
76
- exports.vatCategoryE = types.vatCategoryE;
55
+ __exportStar(require("./types"), exports);
77
56
  __exportStar(require("./consts"), exports);
78
57
  var lcAxios_1 = require("./lcAxios");
79
58
  Object.defineProperty(exports, "lcAxios", { enumerable: true, get: function () { return __importDefault(lcAxios_1).default; } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softwear/latestcollectioncore",
3
- "version": "1.0.160",
3
+ "version": "1.0.162",
4
4
  "description": "Core functions for LatestCollections applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,12 +16,9 @@
16
16
  },
17
17
  "scripts": {
18
18
  "build": "tsc -p tsconfig.json",
19
- "verify": "node scripts/verify-exports.mjs",
20
- "postbuild": "npm run verify",
21
19
  "build:watch": "tsc -p tsconfig.json --watch",
22
20
  "test": "vitest run",
23
21
  "test:watch": "vitest",
24
- "prepublishOnly": "npm run build && npm test",
25
22
  "dev": "concurrently \"npm:build:watch\" \"npm:test:watch\""
26
23
  },
27
24
  "repository": {
@@ -40,8 +37,8 @@
40
37
  "typescript": "^4.9.4",
41
38
  "vitest": "^1.0.0"
42
39
  },
43
- "dependencies": {
44
- "date-fns": "^2.29.3",
40
+ "dependencies": {
41
+ "date-fns": "^2.29.3",
45
42
  "filtrex": "^2.2.3"
46
43
  }
47
- }
44
+ }
@@ -167,6 +167,31 @@ function prepareSubTotalAggKey(aggKey) {
167
167
  return aggKey.split('\t').slice(0, -1).join('\t').concat(' Σ')
168
168
  }
169
169
 
170
+ /** Same as filtrex std.coerceBoolean(customProp(...)) for bare join keys on the transaction */
171
+ function coerceJoinKeyValue(v: unknown): unknown {
172
+ return typeof v === 'boolean' ? +v : v
173
+ }
174
+
175
+ type AggregateKeyTrieNode = { aggregateKey?: string; children?: Map<unknown, AggregateKeyTrieNode> }
176
+ type FilterResultTrieNode = { filterResult?: 1 | -1; children?: Map<unknown, FilterResultTrieNode> }
177
+
178
+ function getTrieLeaf<T extends { children?: Map<unknown, T> }>(root: T, transaction: TransactionI, keys: string[]): T {
179
+ const nrKeys = keys.length
180
+ if (nrKeys === 0) return root
181
+ let node = root
182
+ for (let i = 0; i < nrKeys; i++) {
183
+ const k = coerceJoinKeyValue(transaction[keys[i] as keyof TransactionI] as unknown)
184
+ if (!node.children) node.children = new Map()
185
+ let next = node.children.get(k) as T | undefined
186
+ if (!next) {
187
+ next = {} as T
188
+ node.children.set(k, next)
189
+ }
190
+ node = next
191
+ }
192
+ return node
193
+ }
194
+
170
195
  /*
171
196
  * A factory function that returns a function that can be used to aggregate transactions
172
197
  * The factory function is called once for each aggregationExpression
@@ -200,46 +225,35 @@ function aggregator({
200
225
  subtotalsForOuterGrouper,
201
226
  parentGroupTotals,
202
227
  }: AggregatorFnI) {
203
- const filterExpressionCache = {}
204
-
205
- let filter
206
- let filterDependencyEvaluator
228
+ let filter: ((transaction: TransactionI) => unknown) | undefined
229
+ let filterGranularity: string[] = []
230
+ const filterTrieRoot: FilterResultTrieNode = {}
207
231
  if (filterExpression) {
208
232
  filter = compileExpression(filterExpression, filtrexOptions)
209
- // Maintain a cache of evaluated filterExpressions
210
- // The granularity of the cache is determined by the joined tables in the filterExpression
211
- const filterGranularity = Object.entries(globalJoinableTables)
233
+ filterGranularity = Object.entries(globalJoinableTables)
212
234
  .filter((join) => filterExpression.includes(join[0] + '.'))
213
235
  .map((join) => join[1])
214
- filterDependencyEvaluator = compileExpression(filterGranularity.join('+'), filtrexOptions)
215
236
  }
216
237
  const aggregationEvaluator = buildAggregationEvaluator(aggregationExpression)
217
- // Maintain a cache of evaluated aggregationExpressions
218
- // The granularity of the cache is determined by the joined tables in the aggregationExpression
219
- const aggregationExpressionCache = {}
220
238
  const aggregationGranularity = Object.entries(globalJoinableTables)
221
239
  .filter((join) => aggregationExpression.includes(join[0] + '.'))
222
240
  .map((join) => join[1])
241
+ const aggregationTrieRoot: AggregateKeyTrieNode = {}
223
242
 
224
- let aggregationDependencyExpression = aggregationGranularity.join('+')
225
- if (!aggregationDependencyExpression) aggregationDependencyExpression = '"N.A."'
226
- const aggregationDependencyEvaluator = compileExpression(aggregationDependencyExpression, filtrexOptions)
227
243
  return function (transaction: TransactionI): void {
228
244
  if (filter) {
229
- const filterDependency = filterDependencyEvaluator(transaction)
230
- const filterExpression = filterExpressionCache[filterDependency]
231
- if (filterExpression == -1) return
232
- if (!filterExpression) {
233
- filterExpressionCache[filterDependency] = filter(transaction) ? 1 : -1
234
- if (filterExpressionCache[filterDependency] == -1) return
245
+ const filterLeaf = getTrieLeaf<FilterResultTrieNode>(filterTrieRoot, transaction, filterGranularity)
246
+ if (filterLeaf.filterResult === -1) return
247
+ if (filterLeaf.filterResult === undefined) {
248
+ filterLeaf.filterResult = filter(transaction) ? 1 : -1
249
+ if (filterLeaf.filterResult === -1) return
235
250
  }
236
251
  }
237
- const aggregationDependency = aggregationDependencyEvaluator(transaction)
238
- let aggregateKey = aggregationExpressionCache[aggregationDependency]
239
- if (!aggregateKey) {
240
- aggregateKey = aggregationEvaluator(transaction)
241
- aggregationExpressionCache[aggregationDependency] = aggregateKey
252
+ const aggregateKeyLeaf = getTrieLeaf<AggregateKeyTrieNode>(aggregationTrieRoot, transaction, aggregationGranularity)
253
+ if (!aggregateKeyLeaf.aggregateKey) {
254
+ aggregateKeyLeaf.aggregateKey = aggregationEvaluator(transaction) as string
242
255
  }
256
+ const aggregateKey = aggregateKeyLeaf.aggregateKey as string
243
257
  // Prepare joined values for derived fields
244
258
  if (transaction.type == transactionTypeE.SALE) {
245
259
  const sku = globalRelations['sku'][transaction.ean]
@@ -1,5 +1,4 @@
1
- import { hashBrand, SkuI, BrandSettingI } from './index'
2
- import { mappingStrategyE } from './types'
1
+ import { hashBrand, SkuI, BrandSettingI, mappingStrategyE } from './index'
3
2
 
4
3
  // The order of the following mappingPairs is significant.
5
4
  // - If no mapping is available, we prefer colorFamily to be copied from colorSupplier, not colorCodeSupplier.
package/src/index.ts CHANGED
@@ -15,39 +15,7 @@ export { default as pivotTable } from './pivotTable'
15
15
  export { default as round2 } from './round2'
16
16
  export { default as sizeToMap } from './sizeToMap'
17
17
  export { default as transaction } from './transaction'
18
- // Types-only re-exports (no runtime).
19
- export type {
20
- AggregateFnI,
21
- AggregatorFnI,
22
- AttributeI,
23
- BrandSettingI,
24
- ColorI,
25
- dbTransactionI,
26
- DocumentItemI,
27
- GroupI,
28
- HrTimeframeI,
29
- ImageI,
30
- MarkedSkuI,
31
- MatrixI,
32
- ProductI,
33
- RaGI,
34
- RowI,
35
- SkuI,
36
- StockTransferDataI,
37
- StockTransferMatrixI,
38
- StockTransferSelectionI,
39
- TransactionI,
40
- } from './types'
41
- // Runtime enums: use `export const x = types.x`, not `export { x } from './types'`.
42
- // TS emits `Object.defineProperty(exports, "x", { get: ... })` for re-exports; Vite/esbuild
43
- // does not treat those getters as static named exports for ESM interop.
44
- import * as types from './types'
45
- export const mappingStrategyE = types.mappingStrategyE
46
- export const subscriptionE = types.subscriptionE
47
- export const tagTypeE = types.tagTypeE
48
- export const TimeGranularityE = types.TimeGranularityE
49
- export const transactionTypeE = types.transactionTypeE
50
- export const vatCategoryE = types.vatCategoryE
18
+ export * from './types'
51
19
  export * from './consts'
52
20
  export {
53
21
  default as lcAxios,