@questwork/q-utilities 0.1.34 → 0.1.36

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.
@@ -1956,10 +1956,280 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
1956
1956
  function escapeRegex(string) {
1957
1957
  return String(string).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
1958
1958
  }
1959
+ function init(_class, options) {
1960
+ if (options instanceof _class) {
1961
+ return options;
1962
+ }
1963
+ try {
1964
+ const instance2 = new _class(options);
1965
+ return instance2.isValid !== false ? instance2 : null;
1966
+ } catch (e) {
1967
+ console.log(`init failed for class: ${_class._classname || "no _classname"}`, e);
1968
+ return null;
1969
+ }
1970
+ }
1971
+ function initFromArray(_class, arr) {
1972
+ if (Array.isArray(arr)) {
1973
+ return arr.map((a) => init(_class, a));
1974
+ }
1975
+ return [];
1976
+ }
1977
+ function initOnlyValidFromArray(_class, arr) {
1978
+ return initFromArray(_class, arr).filter((i) => i);
1979
+ }
1980
+ const DATAWRAPPER_STATUS = {
1981
+ ORPHAN_DELETED: "orphanDeleted",
1982
+ EXISTED: "existed",
1983
+ FAILED: "failed",
1984
+ INSERTED: "inserted",
1985
+ SKIPPED: "skipped",
1986
+ UPDATED: "updated"
1987
+ };
1988
+ const LOG_TYPE = {
1989
+ IGNORE: "IGNORE",
1990
+ DUPLICATED: "DUPLICATED",
1991
+ REQUIRED_ERROR: "REQUIRED_ERROR",
1992
+ TRANSFORM_ERROR: "TRANSFORM_ERROR",
1993
+ CONVERT_ERROR: "CONVERT_ERROR",
1994
+ ORPHAN_DELETE_ERROR: "ORPHAN_DELETE_ERROR",
1995
+ INSERT_ERROR: "INSERT_ERROR",
1996
+ UPDATE_ERROR: "UPDATE_ERROR",
1997
+ SKIPPED: "SKIPPED",
1998
+ INSERTED: "INSERTED",
1999
+ UPDATED: "UPDATED",
2000
+ ORPHAN_DELETED: "ORPHAN_DELETED"
2001
+ };
2002
+ class DataWrapper {
2003
+ constructor(opts) {
2004
+ this.data = opts.data || {};
2005
+ this.logs = opts.logs || [];
2006
+ this.rawData = opts.rawData || {};
2007
+ this.rowIndex = opts.rowIndex || 0;
2008
+ this.status = opts.status || {
2009
+ orphanDeleted: null,
2010
+ existed: null,
2011
+ failed: null,
2012
+ inserted: null,
2013
+ updated: null
2014
+ };
2015
+ this.transformedData = opts.transformedData || {};
2016
+ }
2017
+ static init(opts) {
2018
+ return init(this, opts);
2019
+ }
2020
+ static initFromArray(arr = []) {
2021
+ return initFromArray(this, arr);
2022
+ }
2023
+ static initOnlyValidFromArray(arr = []) {
2024
+ return initOnlyValidFromArray(this, arr);
2025
+ }
2026
+ get errorLogs() {
2027
+ const excludedTypes = [LOG_TYPE.IGNORE, LOG_TYPE.SKIPPED, LOG_TYPE.DUPLICATED];
2028
+ return this.logs.filter((l) => !excludedTypes.includes(l.type));
2029
+ }
2030
+ get ignoreLog() {
2031
+ return this.logs.find((l) => l.type === LOG_TYPE.IGNORE);
2032
+ }
2033
+ addLog(detail) {
2034
+ this.logs.push({
2035
+ ...detail,
2036
+ rowIndex: this.rowIndex
2037
+ });
2038
+ return this;
2039
+ }
2040
+ addError(detail) {
2041
+ return this.addLog(detail).setFailed();
2042
+ }
2043
+ addOrphanDeleteError(msg) {
2044
+ this.addError({
2045
+ column: "",
2046
+ message: msg || "Delete failed.",
2047
+ type: LOG_TYPE.ORPHAN_DELETE_ERROR
2048
+ });
2049
+ return this;
2050
+ }
2051
+ addInsertError(msg) {
2052
+ this.addError({
2053
+ column: "",
2054
+ message: msg || "Insert failed.",
2055
+ type: LOG_TYPE.INSERT_ERROR
2056
+ });
2057
+ return this;
2058
+ }
2059
+ addUpdateError(msg) {
2060
+ this.addError({
2061
+ column: "",
2062
+ message: msg || "Update failed.",
2063
+ type: LOG_TYPE.UPDATE_ERROR
2064
+ });
2065
+ return this;
2066
+ }
2067
+ addDuplicatedLog(msg) {
2068
+ return this.addLog({
2069
+ column: "",
2070
+ message: msg || "Duplicated.",
2071
+ type: LOG_TYPE.DUPLICATED
2072
+ });
2073
+ }
2074
+ addSkippedLog(msg) {
2075
+ return this.addLog({
2076
+ column: "",
2077
+ message: msg || "Skipped.",
2078
+ type: LOG_TYPE.SKIPPED
2079
+ }).setSkipped();
2080
+ }
2081
+ addIgnoreLog(msg) {
2082
+ this.logs = this.logs.filter((l) => l.type !== LOG_TYPE.IGNORE);
2083
+ return this.addLog({
2084
+ column: "",
2085
+ message: msg || "Ignored.",
2086
+ type: LOG_TYPE.IGNORE
2087
+ });
2088
+ }
2089
+ addInsertedLog(msg) {
2090
+ return this.addLog({
2091
+ column: "",
2092
+ message: msg || "Inserted.",
2093
+ type: LOG_TYPE.INSERTED
2094
+ }).setInserted();
2095
+ }
2096
+ addUpdatedLog(msg) {
2097
+ return this.addLog({
2098
+ column: "",
2099
+ message: msg || "Updated.",
2100
+ type: LOG_TYPE.UPDATED
2101
+ }).setUpdated();
2102
+ }
2103
+ addOrphanDeletedLog(msg) {
2104
+ return this.addLog({
2105
+ column: "",
2106
+ message: msg || "Orphan deleted.",
2107
+ type: LOG_TYPE.ORPHAN_DELETED
2108
+ }).setOrphanDeleted();
2109
+ }
2110
+ isCheckValid() {
2111
+ return this.errorLogs.length === 0 && !this.ignoreLog && !this.logs.some((l) => l.type === LOG_TYPE.DUPLICATED);
2112
+ }
2113
+ isIgnored() {
2114
+ return !!this.ignoreLog;
2115
+ }
2116
+ isDuplicated() {
2117
+ return this.logs.some((log) => log.type === LOG_TYPE.DUPLICATED);
2118
+ }
2119
+ hasErrors() {
2120
+ return this.errorLogs.length > 0;
2121
+ }
2122
+ setStatus(status) {
2123
+ this.status[DATAWRAPPER_STATUS[status]] = Date.now();
2124
+ return this;
2125
+ }
2126
+ setExisted() {
2127
+ this.setStatus("EXISTED");
2128
+ return this;
2129
+ }
2130
+ setFailed() {
2131
+ this.setStatus("FAILED");
2132
+ return this;
2133
+ }
2134
+ setInserted() {
2135
+ this.setStatus("INSERTED");
2136
+ return this;
2137
+ }
2138
+ setSkipped() {
2139
+ this.setStatus("SKIPPED");
2140
+ return this;
2141
+ }
2142
+ setUpdated() {
2143
+ this.setStatus("UPDATED");
2144
+ return this;
2145
+ }
2146
+ setOrphanDeleted() {
2147
+ this.setStatus("ORPHAN_DELETED");
2148
+ return this;
2149
+ }
2150
+ setData(data) {
2151
+ this.data = data;
2152
+ return this;
2153
+ }
2154
+ setRawData(rawData) {
2155
+ this.rawData = rawData;
2156
+ return this;
2157
+ }
2158
+ setTransformedData(transformedData) {
2159
+ this.transformedData = transformedData;
2160
+ return this;
2161
+ }
2162
+ }
2163
+ class DataSet {
2164
+ constructor(opts) {
2165
+ opts = opts || {};
2166
+ this.name = opts.name || "";
2167
+ this.data = DataWrapper.initOnlyValidFromArray(opts.data || []);
2168
+ this.orphanData = DataWrapper.initOnlyValidFromArray(opts.orphanData || []);
2169
+ this.checkResultConfig = opts.checkResultConfig ? { ...opts.checkResultConfig } : {};
2170
+ this.checkResultConfig.hidden = this.checkResultConfig.hidden ?? false;
2171
+ this.saveResultConfig = opts.saveResultConfig ? { ...opts.saveResultConfig } : {};
2172
+ this.saveResultConfig.hidden = this.saveResultConfig.hidden ?? false;
2173
+ this.orphanBehavior = opts.orphanBehavior ?? null;
2174
+ this.notExistBehavior = opts.notExistBehavior;
2175
+ this.existBehavior = opts.existBehavior;
2176
+ }
2177
+ static init(opts) {
2178
+ return init(this, opts);
2179
+ }
2180
+ static initFromArray(arr = []) {
2181
+ return initFromArray(this, arr);
2182
+ }
2183
+ static initOnlyValidFromArray(arr = []) {
2184
+ return initOnlyValidFromArray(this, arr);
2185
+ }
2186
+ add(data) {
2187
+ this.data.push(data);
2188
+ return this;
2189
+ }
2190
+ getExistedData() {
2191
+ return this.data.filter((item) => {
2192
+ var _a;
2193
+ return item.isCheckValid() && ((_a = item.status) == null ? void 0 : _a.existed);
2194
+ });
2195
+ }
2196
+ getInvalidData() {
2197
+ return this.data.filter((item) => !item.isCheckValid());
2198
+ }
2199
+ getNotExistedData() {
2200
+ return this.data.filter((item) => {
2201
+ var _a;
2202
+ return item.isCheckValid() && !((_a = item.status) == null ? void 0 : _a.existed);
2203
+ });
2204
+ }
2205
+ getSkipData() {
2206
+ return this.data.filter((item) => item.isIgnored() || item.isDuplicated());
2207
+ }
2208
+ addOrphan(data) {
2209
+ const dataWrapper = new DataWrapper({
2210
+ data,
2211
+ rowIndex: -1
2212
+ });
2213
+ this.orphanData.push(dataWrapper);
2214
+ return this;
2215
+ }
2216
+ getOrphanData() {
2217
+ return this.orphanData;
2218
+ }
2219
+ }
1959
2220
  class CheckResult {
1960
2221
  constructor(opts) {
1961
2222
  this.dataSets = [];
1962
- this.dataSets = (opts == null ? void 0 : opts.dataSets) || [];
2223
+ this.dataSets = DataSet.initOnlyValidFromArray((opts == null ? void 0 : opts.dataSets) || []);
2224
+ }
2225
+ static init(opts) {
2226
+ return init(this, opts);
2227
+ }
2228
+ static initFromArray(arr = []) {
2229
+ return initFromArray(this, arr);
2230
+ }
2231
+ static initOnlyValidFromArray(arr = []) {
2232
+ return initOnlyValidFromArray(this, arr);
1963
2233
  }
1964
2234
  addDataSet(dataSet) {
1965
2235
  this.dataSets.push(dataSet);
@@ -1967,16 +2237,21 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
1967
2237
  getDataSetByName(name) {
1968
2238
  return this.dataSets.find((dataSet) => dataSet.name === name);
1969
2239
  }
2240
+ getAllSummary() {
2241
+ return {
2242
+ summary: this.getSummary()
2243
+ };
2244
+ }
1970
2245
  getSummary() {
1971
2246
  return this.dataSets.map((dataSet) => ({
1972
2247
  name: dataSet.name,
1973
2248
  hidden: dataSet.checkResultConfig.hidden,
1974
2249
  summary: {
1975
2250
  total: dataSet.data.length,
1976
- valid: dataSet.data.filter((row) => row.errorLogs.length === 0 && !row.ignoreLog).length,
1977
- ignored: dataSet.data.filter((row) => row.ignoreLog).length,
1978
- invalid: dataSet.data.filter((row) => row.errorLogs.length > 0 && !row.errorLogs.some((detail) => detail.type === "DUPLICATED")).length,
1979
- duplicated: dataSet.data.filter((row) => row.errorLogs.some((detail) => detail.type === "DUPLICATED")).length
2251
+ ignored: dataSet.data.filter((row) => row.isIgnored()).length,
2252
+ duplicated: dataSet.data.filter((row) => !row.isIgnored() && row.isDuplicated()).length,
2253
+ invalid: dataSet.data.filter((row) => !row.isIgnored() && !row.isDuplicated() && row.hasErrors()).length,
2254
+ valid: dataSet.data.filter((row) => row.isCheckValid()).length
1980
2255
  }
1981
2256
  }));
1982
2257
  }
@@ -1984,8 +2259,8 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
1984
2259
  return this.dataSets.map((dataSet) => ({
1985
2260
  name: dataSet.name,
1986
2261
  hidden: dataSet.checkResultConfig.hidden,
1987
- logs: dataSet.data.filter((row) => row.errorLogs.some((detail) => detail.type === "DUPLICATED")).reduce((acc, row) => {
1988
- return [...acc, ...row.errorLogs];
2262
+ logs: dataSet.data.filter((row) => row.logs.some((detail) => detail.type === LOG_TYPE.DUPLICATED)).reduce((acc, row) => {
2263
+ return [...acc, ...row.logs.filter((detail) => detail.type === LOG_TYPE.DUPLICATED)];
1989
2264
  }, [])
1990
2265
  }));
1991
2266
  }
@@ -2002,21 +2277,33 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2002
2277
  return this.dataSets.map((dataSet) => ({
2003
2278
  name: dataSet.name,
2004
2279
  hidden: dataSet.checkResultConfig.hidden,
2005
- logs: dataSet.data.filter((row) => row.errorLogs.length > 0 && !row.errorLogs.some((detail) => detail.type === "DUPLICATED")).reduce((acc, row) => {
2280
+ logs: dataSet.data.filter((row) => row.errorLogs.length > 0).reduce((acc, row) => {
2006
2281
  return [...acc, ...row.errorLogs];
2007
2282
  }, [])
2008
2283
  }));
2009
2284
  }
2010
2285
  getValidDetails() {
2011
2286
  return this.dataSets.reduce((acc, dataSet) => {
2012
- acc[dataSet.name] = dataSet.data.filter((row) => row.errorLogs.length === 0).reduce((acc2, row) => {
2287
+ acc[dataSet.name] = dataSet.data.filter((row) => row.isCheckValid()).reduce((acc2, row) => {
2013
2288
  return [...acc2, row];
2014
2289
  }, []);
2015
2290
  return acc;
2016
2291
  }, {});
2017
2292
  }
2293
+ getAllDetails() {
2294
+ return {
2295
+ details: this.getDetails()
2296
+ };
2297
+ }
2298
+ getDetails() {
2299
+ return {
2300
+ ignoredDetails: this.getIgnoredDetails(),
2301
+ invalidDetails: this.getInvalidDetails(),
2302
+ duplicatedDetails: this.getDuplicatedDetails()
2303
+ };
2304
+ }
2018
2305
  hasInvalidData() {
2019
- return this.dataSets.some((dataSet) => dataSet.data.some((row) => row.errorLogs.length > 0 && !row.errorLogs.some((detail) => detail.type === "DUPLICATED")));
2306
+ return this.dataSets.some((dataSet) => dataSet.data.some((row) => row.errorLogs.length > 0));
2020
2307
  }
2021
2308
  }
2022
2309
  class SaveResult {
@@ -2029,11 +2316,112 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2029
2316
  this.dataSets.push(dataSet);
2030
2317
  return this;
2031
2318
  }
2319
+ getAllDetails() {
2320
+ return {
2321
+ details: this.getDetails(),
2322
+ orphanDetails: this.getOrphanDetails()
2323
+ };
2324
+ }
2325
+ getDetails() {
2326
+ return {
2327
+ failed: this.getFailedDetails(),
2328
+ skipped: this.getSkippedDetails(),
2329
+ inserted: this.getInsertedDetails(),
2330
+ updated: this.getUpdatedDetails()
2331
+ };
2332
+ }
2333
+ getFailedDetails() {
2334
+ const types = [LOG_TYPE.INSERT_ERROR, LOG_TYPE.UPDATE_ERROR];
2335
+ return this.dataSets.map((dataSet) => {
2336
+ return {
2337
+ name: dataSet.name,
2338
+ hidden: dataSet.saveResultConfig.hidden,
2339
+ logs: dataSet.data.filter((row) => row.logs.some((detail) => types.includes(detail.type))).reduce((acc, row) => {
2340
+ return acc.concat(row.logs.filter((detail) => types.includes(detail.type)));
2341
+ }, [])
2342
+ };
2343
+ });
2344
+ }
2345
+ getSkippedDetails() {
2346
+ const types = [LOG_TYPE.SKIPPED, LOG_TYPE.IGNORE, LOG_TYPE.DUPLICATED];
2347
+ return this.dataSets.map((dataSet) => {
2348
+ return {
2349
+ name: dataSet.name,
2350
+ hidden: dataSet.saveResultConfig.hidden,
2351
+ logs: dataSet.data.reduce((acc, row) => {
2352
+ const filtered = row.logs.filter((detail) => types.includes(detail.type));
2353
+ return acc.concat(filtered);
2354
+ }, [])
2355
+ };
2356
+ });
2357
+ }
2358
+ getInsertedDetails() {
2359
+ return this.dataSets.map((dataSet) => {
2360
+ return {
2361
+ name: dataSet.name,
2362
+ hidden: dataSet.saveResultConfig.hidden,
2363
+ logs: dataSet.data.reduce((acc, row) => {
2364
+ const filtered = row.logs.filter((detail) => detail.type === LOG_TYPE.INSERTED);
2365
+ return acc.concat(filtered);
2366
+ }, [])
2367
+ };
2368
+ });
2369
+ }
2370
+ getUpdatedDetails() {
2371
+ return this.dataSets.map((dataSet) => {
2372
+ return {
2373
+ name: dataSet.name,
2374
+ hidden: dataSet.saveResultConfig.hidden,
2375
+ logs: dataSet.data.reduce((acc, row) => {
2376
+ const filtered = row.logs.filter((detail) => detail.type === LOG_TYPE.UPDATED);
2377
+ return acc.concat(filtered);
2378
+ }, [])
2379
+ };
2380
+ });
2381
+ }
2382
+ getOrphanDetails() {
2383
+ return {
2384
+ deleted: this.getOrphanDeletedDetails(),
2385
+ failed: this.getOrphanFailedDetails()
2386
+ };
2387
+ }
2388
+ getOrphanFailedDetails() {
2389
+ return this.dataSets.reduce((acc, dataSet) => {
2390
+ if (dataSet.orphanBehavior) {
2391
+ acc.push({
2392
+ name: dataSet.name,
2393
+ hidden: dataSet.saveResultConfig.hidden,
2394
+ logs: dataSet.orphanData.filter((row) => {
2395
+ var _a;
2396
+ return (_a = row.errorLogs) == null ? void 0 : _a.some((log) => log.type === LOG_TYPE.ORPHAN_DELETE_ERROR);
2397
+ }).reduce((acc2, row) => {
2398
+ return acc2.concat(row.errorLogs);
2399
+ }, [])
2400
+ });
2401
+ }
2402
+ return acc;
2403
+ }, []);
2404
+ }
2405
+ getOrphanDeletedDetails() {
2406
+ return this.dataSets.reduce((acc, dataSet) => {
2407
+ if (dataSet.orphanBehavior) {
2408
+ acc.push({
2409
+ name: dataSet.name,
2410
+ hidden: dataSet.saveResultConfig.hidden,
2411
+ logs: dataSet.orphanData.filter((row) => row.status.orphanDeleted).reduce((acc2, row) => {
2412
+ return acc2.concat(row.errorLogs);
2413
+ }, [])
2414
+ });
2415
+ }
2416
+ return acc;
2417
+ }, []);
2418
+ }
2419
+ // Deprecated, will use getAllDetails instead
2032
2420
  getSaveDetails() {
2033
2421
  return this.dataSets.map((dataSet) => {
2034
2422
  var _a;
2035
2423
  const returnDetail = (_a = dataSet.saveResultConfig) == null ? void 0 : _a.returnDetail;
2036
- return {
2424
+ const result = {
2037
2425
  name: dataSet.name,
2038
2426
  hidden: dataSet.saveResultConfig.hidden,
2039
2427
  details: {
@@ -2041,140 +2429,89 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2041
2429
  inserted: (returnDetail == null ? void 0 : returnDetail.inserted) ? dataSet.data.filter((row) => row.status.inserted) : null,
2042
2430
  skipped: (returnDetail == null ? void 0 : returnDetail.skipped) ? dataSet.data.filter((row) => row.status.skipped) : null,
2043
2431
  updated: (returnDetail == null ? void 0 : returnDetail.updated) ? dataSet.data.filter((row) => row.status.updated) : null
2044
- }
2432
+ },
2433
+ orphanDetails: null
2045
2434
  };
2435
+ if (dataSet.orphanBehavior) {
2436
+ result.orphanDetails = {
2437
+ deleted: (returnDetail == null ? void 0 : returnDetail.orphanDeleted) ? dataSet.orphanData.filter((row) => row.status.orphanDeleted) : [],
2438
+ failed: dataSet.orphanData.filter((row) => {
2439
+ var _a2;
2440
+ return (_a2 = row.errorLogs) == null ? void 0 : _a2.some((log) => log.type === LOG_TYPE.ORPHAN_DELETE_ERROR);
2441
+ })
2442
+ };
2443
+ }
2444
+ return result;
2046
2445
  });
2047
2446
  }
2447
+ // Deprecated, will use getAllSummary instead
2048
2448
  getSaveSummary() {
2049
- return this.dataSets.map((dataSet) => ({
2050
- name: dataSet.name,
2051
- hidden: dataSet.saveResultConfig.hidden,
2052
- summary: {
2053
- total: dataSet.data.length,
2054
- failed: dataSet.data.filter((row) => row.status.failed).length,
2055
- inserted: dataSet.data.filter((row) => row.status.inserted).length,
2056
- skipped: dataSet.data.filter((row) => row.status.skipped).length,
2057
- updated: dataSet.data.filter((row) => row.status.updated).length
2449
+ return this.dataSets.map((dataSet) => {
2450
+ const result = {
2451
+ name: dataSet.name,
2452
+ hidden: dataSet.saveResultConfig.hidden,
2453
+ summary: {
2454
+ total: dataSet.data.length,
2455
+ failed: dataSet.data.filter((row) => row.status.failed).length,
2456
+ inserted: dataSet.data.filter((row) => row.status.inserted).length,
2457
+ skipped: dataSet.data.filter((row) => row.status.skipped).length,
2458
+ updated: dataSet.data.filter((row) => row.status.updated).length
2459
+ },
2460
+ orphanSummary: null
2461
+ };
2462
+ if (dataSet.orphanBehavior) {
2463
+ result.orphanSummary = {
2464
+ total: dataSet.orphanData.length,
2465
+ deleted: dataSet.orphanData.filter((row) => row.status.orphanDeleted).length,
2466
+ failed: dataSet.orphanData.filter((row) => {
2467
+ var _a;
2468
+ return (_a = row.errorLogs) == null ? void 0 : _a.some((log) => log.type === LOG_TYPE.ORPHAN_DELETE_ERROR);
2469
+ }).length
2470
+ };
2058
2471
  }
2059
- }));
2060
- }
2061
- }
2062
- class DataSet {
2063
- constructor(opts) {
2064
- opts = opts || {};
2065
- this.name = opts.name || "";
2066
- this.data = opts.data || [];
2067
- this.checkResultConfig = opts.checkResultConfig ? { ...opts.checkResultConfig } : {};
2068
- this.checkResultConfig.hidden = this.checkResultConfig.hidden ?? false;
2069
- this.saveResultConfig = opts.saveResultConfig ? { ...opts.saveResultConfig } : {};
2070
- this.saveResultConfig.hidden = this.saveResultConfig.hidden ?? false;
2071
- }
2072
- add(data) {
2073
- this.data.push(data);
2074
- return this;
2075
- }
2076
- getExistedData() {
2077
- return this.data.filter((item) => {
2078
- var _a;
2079
- return item.isValid() && ((_a = item.status) == null ? void 0 : _a.existed);
2080
- });
2081
- }
2082
- getInvalidData() {
2083
- return this.data.filter((item) => !item.isValid());
2084
- }
2085
- getNotExistedData() {
2086
- return this.data.filter((item) => {
2087
- var _a;
2088
- return item.isValid() && !((_a = item.status) == null ? void 0 : _a.existed);
2472
+ return result;
2089
2473
  });
2090
2474
  }
2091
- }
2092
- const DATAWRAPPER_STATUS = {
2093
- EXISTED: "existed",
2094
- FAILED: "failed",
2095
- INSERTED: "inserted",
2096
- SKIPPED: "skipped",
2097
- UPDATED: "updated"
2098
- };
2099
- class DataWrapper {
2100
- constructor(opts) {
2101
- this.data = opts.data || {};
2102
- this.errorLogs = opts.errorLogs || [];
2103
- this.ignoreLog = opts.ignoreLog;
2104
- this.rawData = opts.rawData || {};
2105
- this.rowIndex = opts.rowIndex || 0;
2106
- this.status = opts.status || {
2107
- existed: null,
2108
- failed: null,
2109
- inserted: null,
2110
- updated: null
2475
+ getAllSummary() {
2476
+ return {
2477
+ summary: this.getSummary(),
2478
+ orphanSummary: this.getOrphanSummary()
2111
2479
  };
2112
- this.transformedData = opts.transformedData || {};
2113
2480
  }
2114
- addError(detail) {
2115
- this.errorLogs.push(detail);
2116
- return this;
2117
- }
2118
- addInsertError(msg) {
2119
- this.addError({
2120
- rowIndex: this.rowIndex,
2121
- column: "",
2122
- message: msg,
2123
- type: "INSERT_ERROR"
2124
- });
2125
- return this;
2126
- }
2127
- addUpdateError(msg) {
2128
- this.addError({
2129
- rowIndex: this.rowIndex,
2130
- column: "",
2131
- message: msg,
2132
- type: "UPDATE_ERROR"
2481
+ getSummary() {
2482
+ return this.dataSets.map((dataSet) => {
2483
+ const result = {
2484
+ name: dataSet.name,
2485
+ hidden: dataSet.saveResultConfig.hidden,
2486
+ summary: {
2487
+ total: dataSet.data.length,
2488
+ failed: dataSet.data.filter((row) => row.status.failed).length,
2489
+ inserted: dataSet.data.filter((row) => row.status.inserted).length,
2490
+ skipped: dataSet.data.filter((row) => row.status.skipped).length,
2491
+ updated: dataSet.data.filter((row) => row.status.updated).length
2492
+ }
2493
+ };
2494
+ return result;
2133
2495
  });
2134
- return this;
2135
- }
2136
- isValid() {
2137
- return this.errorLogs.length === 0 && !this.ignoreLog;
2138
- }
2139
- setIgnoreLog(detail) {
2140
- this.ignoreLog = detail;
2141
- return this;
2142
- }
2143
- setData(data) {
2144
- this.data = data;
2145
- return this;
2146
- }
2147
- setExisted() {
2148
- this.setStatus("EXISTED");
2149
- return this;
2150
- }
2151
- setFailed() {
2152
- this.setStatus("FAILED");
2153
- return this;
2154
- }
2155
- setInserted() {
2156
- this.setStatus("INSERTED");
2157
- return this;
2158
- }
2159
- setRawData(rawData) {
2160
- this.rawData = rawData;
2161
- return this;
2162
- }
2163
- setSkipped() {
2164
- this.setStatus("SKIPPED");
2165
- return this;
2166
- }
2167
- setStatus(status) {
2168
- this.status[DATAWRAPPER_STATUS[status]] = Date.now();
2169
- return this;
2170
2496
  }
2171
- setTransformedData(transformedData) {
2172
- this.transformedData = transformedData;
2173
- return this;
2174
- }
2175
- setUpdated() {
2176
- this.setStatus("UPDATED");
2177
- return this;
2497
+ getOrphanSummary() {
2498
+ return this.dataSets.reduce((acc, dataSet) => {
2499
+ if (dataSet.orphanBehavior) {
2500
+ acc.push({
2501
+ name: dataSet.name,
2502
+ hidden: dataSet.saveResultConfig.hidden,
2503
+ summary: {
2504
+ total: dataSet.orphanData.length,
2505
+ deleted: dataSet.orphanData.filter((row) => row.status.orphanDeleted).length,
2506
+ failed: dataSet.orphanData.filter((row) => {
2507
+ var _a;
2508
+ return (_a = row.errorLogs) == null ? void 0 : _a.some((log) => log.type === LOG_TYPE.ORPHAN_DELETE_ERROR);
2509
+ }).length
2510
+ }
2511
+ });
2512
+ }
2513
+ return acc;
2514
+ }, []);
2178
2515
  }
2179
2516
  }
2180
2517
  class ExcelImportHelper {
@@ -2190,7 +2527,7 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2190
2527
  if (!worksheetData) continue;
2191
2528
  const worksheet = config.worksheets.find((item) => item.name === worksheetName);
2192
2529
  const dataSources = (worksheet == null ? void 0 : worksheet.dataSources) || [];
2193
- const { headerRow = 1, dataStartRow = 2 } = worksheet || {};
2530
+ const { headerRow = 1, dataStartRow = 2, rowIndexKey } = worksheet || {};
2194
2531
  for (const dataSource of dataSources) {
2195
2532
  if (!dataSource.headerConfigs || !dataSource.name) continue;
2196
2533
  const seenPrimaryKeys = /* @__PURE__ */ new Map();
@@ -2198,14 +2535,18 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2198
2535
  name: dataSource.name,
2199
2536
  data: [],
2200
2537
  checkResultConfig: dataSource.checkResultConfig,
2201
- saveResultConfig: dataSource.saveResultConfig
2538
+ saveResultConfig: dataSource.saveResultConfig,
2539
+ orphanBehavior: dataSource.orphanBehavior,
2540
+ notExistBehavior: dataSource.notExistBehavior,
2541
+ existBehavior: dataSource.existBehavior
2202
2542
  });
2203
2543
  for (let rowIndex = 0; rowIndex < worksheetData.length; rowIndex++) {
2204
2544
  const row = worksheetData[rowIndex];
2205
2545
  const rawData = this.getRawDataFromHeaders(row, dataSource.headerConfigs);
2206
- let excelRow = this.createExcelRow(rawData, rowIndex + dataStartRow);
2546
+ let excelRow = this.createExcelRow(rawData, getRowIndex(row, rowIndexKey));
2207
2547
  const ctx = Object.assign({ dataSets: result.dataSets }, context);
2208
2548
  const handlers = [
2549
+ (row2) => this.checkRequired(row2, dataSource.headerConfigs, headers),
2209
2550
  (row2) => this.checkDuplicated(row2, dataSource, seenPrimaryKeys),
2210
2551
  (row2) => this.isIgnore(row2, ctx, dataSource.isIgnore),
2211
2552
  (row2) => this.transform(row2, dataSource.headerConfigs, headers),
@@ -2213,7 +2554,7 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2213
2554
  ];
2214
2555
  for (const handler of handlers) {
2215
2556
  excelRow = handler(excelRow);
2216
- if (excelRow.errorLogs.length > 0 || excelRow.ignoreLog) {
2557
+ if (excelRow.errorLogs.length > 0 || excelRow.ignoreLog || excelRow.isDuplicated()) {
2217
2558
  break;
2218
2559
  }
2219
2560
  }
@@ -2227,10 +2568,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2227
2568
  }
2228
2569
  static createExcelRow(row, rowIndex) {
2229
2570
  return new DataWrapper({
2230
- // data: { ...row },
2231
2571
  rawData: row,
2232
2572
  rowIndex,
2233
- errorLogs: []
2573
+ logs: []
2234
2574
  });
2235
2575
  }
2236
2576
  static getRawDataFromHeaders(excelRow, headerConfigs = []) {
@@ -2246,25 +2586,28 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2246
2586
  }
2247
2587
  const { ignore, reason } = isIgnore({ rawData: row.rawData, rowIndex: row.rowIndex, ctx });
2248
2588
  if (ignore) {
2249
- row.setIgnoreLog({
2250
- rowIndex: row.rowIndex,
2251
- column: "",
2252
- message: reason || "",
2253
- type: "IGNORE"
2254
- });
2589
+ row.addIgnoreLog(reason || "");
2590
+ }
2591
+ return row;
2592
+ }
2593
+ static checkRequired(row, headerConfigs = [], headers = []) {
2594
+ const rawData = { ...row.rawData };
2595
+ for (const config of headerConfigs) {
2596
+ const value = rawData[config.name];
2597
+ if (config.required && (value === null || value === void 0 || value === "")) {
2598
+ row.addError({
2599
+ column: getExcelColumnName(headers.indexOf(config.name)),
2600
+ message: `${config.name} is required.`,
2601
+ type: LOG_TYPE.REQUIRED_ERROR
2602
+ });
2603
+ }
2255
2604
  }
2256
2605
  return row;
2257
2606
  }
2258
2607
  static checkDuplicated(row, dataSource, seenPrimaryKeys) {
2259
2608
  const primaryKey = dataSource.primaryKeys.map((key) => row.rawData[key]).join("-");
2260
2609
  if (seenPrimaryKeys.has(primaryKey)) {
2261
- row.addError({
2262
- rowIndex: row.rowIndex,
2263
- // column: getPrimaryKeyColumn(dataSource.primaryKeys, headers),
2264
- column: "",
2265
- message: `Duplicated with row ${seenPrimaryKeys.get(primaryKey) || 0}`,
2266
- type: "DUPLICATED"
2267
- });
2610
+ row.addDuplicatedLog(`Duplicated with row ${seenPrimaryKeys.get(primaryKey) || 0}.`);
2268
2611
  } else {
2269
2612
  seenPrimaryKeys.set(primaryKey, row.rowIndex);
2270
2613
  }
@@ -2274,26 +2617,13 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2274
2617
  const rawData = { ...row.rawData };
2275
2618
  const transformedData = {};
2276
2619
  for (const config of headerConfigs) {
2277
- const value = rawData[config.name];
2278
- let hasRequiredError = false;
2279
- if (config.required && (value === null || value === void 0 || value === "")) {
2280
- row.addError({
2281
- rowIndex: row.rowIndex,
2282
- column: getExcelColumnName(headers.indexOf(config.name)),
2283
- message: `${config.name} is required`,
2284
- type: "REQUIRED"
2285
- });
2286
- hasRequiredError = true;
2287
- }
2288
- if (hasRequiredError) continue;
2289
2620
  try {
2290
2621
  transformedData[config.name] = typeof config.transform === "function" ? config.transform(rawData[config.name]) : rawData[config.name];
2291
2622
  } catch (error) {
2292
2623
  row.addError({
2293
- rowIndex: row.rowIndex,
2294
2624
  column: getExcelColumnName(headers.indexOf(config.name)),
2295
- message: `transform ${config.name} failed`,
2296
- type: "TRANSFORM"
2625
+ message: `Transform ${config.name} failed: ${error.message}`,
2626
+ type: LOG_TYPE.TRANSFORM_ERROR
2297
2627
  });
2298
2628
  }
2299
2629
  }
@@ -2311,10 +2641,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2311
2641
  return row.setData(result);
2312
2642
  } catch (error) {
2313
2643
  row.addError({
2314
- rowIndex: row.rowIndex,
2315
2644
  column: "",
2316
- message: `convert failed`,
2317
- type: "CONVERT"
2645
+ message: `Convert failed: ${error.message}`,
2646
+ type: LOG_TYPE.CONVERT_ERROR
2318
2647
  });
2319
2648
  }
2320
2649
  return row;
@@ -2340,6 +2669,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2340
2669
  if (checkExisted && typeof checkExisted === "function") {
2341
2670
  updatedDataSet = await checkExisted({ dataSet: updatedDataSet, ctx });
2342
2671
  }
2672
+ if (dataSource.orphanBehavior === "DELETE" && dataSource.checkOrphans && typeof dataSource.checkOrphans === "function") {
2673
+ await dataSource.checkOrphans({ dataSet: updatedDataSet, ctx });
2674
+ }
2343
2675
  if (handleData && typeof handleData === "function") {
2344
2676
  updatedDataSet = await handleData({ dataSet: updatedDataSet, dataSource, ctx });
2345
2677
  } else {
@@ -2362,6 +2694,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2362
2694
  }
2363
2695
  return result;
2364
2696
  }
2697
+ function getRowIndex(row, rowIndexKey) {
2698
+ return row[rowIndexKey || "__rowNum"] || 0;
2699
+ }
2365
2700
  function customHandler({ responseHelper, handler, ignoreError = false }) {
2366
2701
  return async (reqOrCtx, resOrNext, nextInExpress) => {
2367
2702
  const isKoa = typeof resOrNext === "function" && !nextInExpress;
@@ -2624,6 +2959,26 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2624
2959
  }
2625
2960
  return options;
2626
2961
  }
2962
+ async bulkWriteDocs({ operations, config, systemLog }) {
2963
+ const log = _makeLog({
2964
+ systemLog,
2965
+ label: "REPO_BULK_WRITE",
2966
+ message: `fn ${this._classname}.prototype.bulkWriteDocs`,
2967
+ input: [{ operations: { ...operations }, config: { ...config }, systemLog: { ...systemLog } }]
2968
+ });
2969
+ const sharedOptions = {
2970
+ ...this._sharedOptions,
2971
+ ...config
2972
+ };
2973
+ try {
2974
+ const result = await this.model.bulkWriteDocs(operations, sharedOptions);
2975
+ log({ level: "info", output: { ...result } });
2976
+ return result;
2977
+ } catch (err) {
2978
+ log({ level: "warn", output: err.toString() });
2979
+ throw err;
2980
+ }
2981
+ }
2627
2982
  async deleteOne({ id }) {
2628
2983
  try {
2629
2984
  const result = await this.model.deleteOne({ _id: id });
@@ -2907,6 +3262,27 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2907
3262
  }
2908
3263
  return new Service({ repo });
2909
3264
  }
3265
+ class ServiceBulkWrite extends Service {
3266
+ constructor({ repo }) {
3267
+ super({ repo });
3268
+ }
3269
+ static get _classname() {
3270
+ return "ServiceBulkWrite";
3271
+ }
3272
+ async bulkWriteDocs({ operations, config }) {
3273
+ const result = await this.repo.bulkWriteDocs({ operations, config });
3274
+ return result;
3275
+ }
3276
+ }
3277
+ function makeServiceBulkWrite({ repo }) {
3278
+ if (repo === void 0) {
3279
+ throw new Error("repo is required.");
3280
+ }
3281
+ if (repo._superclass !== Repo._superclass) {
3282
+ throw new Error("repo is not an instance of Repo.");
3283
+ }
3284
+ return new ServiceBulkWrite({ repo });
3285
+ }
2910
3286
  async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator: UniqueKeyGenerator2, resourceInfo }) {
2911
3287
  const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body;
2912
3288
  const _resourceInfo = resourceInfo || body.resourceInfo;
@@ -3027,27 +3403,6 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
3027
3403
  return acc;
3028
3404
  }, {});
3029
3405
  }
3030
- function init(_class, options) {
3031
- if (options instanceof _class) {
3032
- return options;
3033
- }
3034
- try {
3035
- const instance2 = new _class(options);
3036
- return instance2.isValid !== false ? instance2 : null;
3037
- } catch (e) {
3038
- console.log(`init failed for class: ${_class._classname || "no _classname"}`, e);
3039
- return null;
3040
- }
3041
- }
3042
- function initFromArray(_class, arr) {
3043
- if (Array.isArray(arr)) {
3044
- return arr.map((a) => init(_class, a));
3045
- }
3046
- return [];
3047
- }
3048
- function initOnlyValidFromArray(_class, arr) {
3049
- return initFromArray(_class, arr).filter((i) => i);
3050
- }
3051
3406
  function mergeArraysByKey(arr1, arr2) {
3052
3407
  const safeArr1 = Array.isArray(arr1) ? arr1 : [];
3053
3408
  const safeArr2 = Array.isArray(arr2) ? arr2 : [];
@@ -3638,6 +3993,7 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
3638
3993
  __proto__: null,
3639
3994
  CheckResult,
3640
3995
  ExcelImportHelper,
3996
+ LOG_TYPE,
3641
3997
  authorize,
3642
3998
  calculateAge,
3643
3999
  changeCreatorOwner,
@@ -4753,6 +5109,7 @@ ${this.zone || ""}`;
4753
5109
  QMeta,
4754
5110
  Repo,
4755
5111
  Service,
5112
+ ServiceBulkWrite,
4756
5113
  Status,
4757
5114
  StatusDocument,
4758
5115
  TemplateCompiler,
@@ -4763,7 +5120,8 @@ ${this.zone || ""}`;
4763
5120
  WebAppResponse,
4764
5121
  getQLogEnv,
4765
5122
  makeApiResponse,
4766
- makeService
5123
+ makeService,
5124
+ makeServiceBulkWrite
4767
5125
  }, Symbol.toStringTag, { value: "Module" }));
4768
5126
  const index = {
4769
5127
  ...helpers,
@@ -4778,6 +5136,7 @@ ${this.zone || ""}`;
4778
5136
  exports2.ErrorDetail = ErrorDetail;
4779
5137
  exports2.ExcelImportHelper = ExcelImportHelper;
4780
5138
  exports2.KeyValueObject = KeyValueObject;
5139
+ exports2.LOG_TYPE = LOG_TYPE;
4781
5140
  exports2.LogRecord = LogRecord;
4782
5141
  exports2.Metadata = Metadata;
4783
5142
  exports2.PushEnvelope = PushEnvelope;
@@ -4787,6 +5146,7 @@ ${this.zone || ""}`;
4787
5146
  exports2.QMeta = QMeta;
4788
5147
  exports2.Repo = Repo;
4789
5148
  exports2.Service = Service;
5149
+ exports2.ServiceBulkWrite = ServiceBulkWrite;
4790
5150
  exports2.Status = Status;
4791
5151
  exports2.StatusDocument = StatusDocument;
4792
5152
  exports2.TemplateCompiler = TemplateCompiler;
@@ -4821,6 +5181,7 @@ ${this.zone || ""}`;
4821
5181
  exports2.isConvertibleToNumber = isConvertibleToNumber;
4822
5182
  exports2.makeApiResponse = makeApiResponse;
4823
5183
  exports2.makeService = makeService;
5184
+ exports2.makeServiceBulkWrite = makeServiceBulkWrite;
4824
5185
  exports2.mergeArraysByKey = mergeArraysByKey;
4825
5186
  exports2.objectHelper = objectHelper;
4826
5187
  exports2.pMap = pMap;