@questwork/q-utilities 0.1.34 → 0.1.35

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();
@@ -2203,9 +2540,10 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2203
2540
  for (let rowIndex = 0; rowIndex < worksheetData.length; rowIndex++) {
2204
2541
  const row = worksheetData[rowIndex];
2205
2542
  const rawData = this.getRawDataFromHeaders(row, dataSource.headerConfigs);
2206
- let excelRow = this.createExcelRow(rawData, rowIndex + dataStartRow);
2543
+ let excelRow = this.createExcelRow(rawData, getRowIndex(row, rowIndexKey));
2207
2544
  const ctx = Object.assign({ dataSets: result.dataSets }, context);
2208
2545
  const handlers = [
2546
+ (row2) => this.checkRequired(row2, dataSource.headerConfigs, headers),
2209
2547
  (row2) => this.checkDuplicated(row2, dataSource, seenPrimaryKeys),
2210
2548
  (row2) => this.isIgnore(row2, ctx, dataSource.isIgnore),
2211
2549
  (row2) => this.transform(row2, dataSource.headerConfigs, headers),
@@ -2213,7 +2551,7 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2213
2551
  ];
2214
2552
  for (const handler of handlers) {
2215
2553
  excelRow = handler(excelRow);
2216
- if (excelRow.errorLogs.length > 0 || excelRow.ignoreLog) {
2554
+ if (excelRow.errorLogs.length > 0 || excelRow.ignoreLog || excelRow.isDuplicated()) {
2217
2555
  break;
2218
2556
  }
2219
2557
  }
@@ -2227,10 +2565,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2227
2565
  }
2228
2566
  static createExcelRow(row, rowIndex) {
2229
2567
  return new DataWrapper({
2230
- // data: { ...row },
2231
2568
  rawData: row,
2232
2569
  rowIndex,
2233
- errorLogs: []
2570
+ logs: []
2234
2571
  });
2235
2572
  }
2236
2573
  static getRawDataFromHeaders(excelRow, headerConfigs = []) {
@@ -2246,25 +2583,28 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2246
2583
  }
2247
2584
  const { ignore, reason } = isIgnore({ rawData: row.rawData, rowIndex: row.rowIndex, ctx });
2248
2585
  if (ignore) {
2249
- row.setIgnoreLog({
2250
- rowIndex: row.rowIndex,
2251
- column: "",
2252
- message: reason || "",
2253
- type: "IGNORE"
2254
- });
2586
+ row.addIgnoreLog(reason || "");
2587
+ }
2588
+ return row;
2589
+ }
2590
+ static checkRequired(row, headerConfigs = [], headers = []) {
2591
+ const rawData = { ...row.rawData };
2592
+ for (const config of headerConfigs) {
2593
+ const value = rawData[config.name];
2594
+ if (config.required && (value === null || value === void 0 || value === "")) {
2595
+ row.addError({
2596
+ column: getExcelColumnName(headers.indexOf(config.name)),
2597
+ message: `${config.name} is required.`,
2598
+ type: LOG_TYPE.REQUIRED_ERROR
2599
+ });
2600
+ }
2255
2601
  }
2256
2602
  return row;
2257
2603
  }
2258
2604
  static checkDuplicated(row, dataSource, seenPrimaryKeys) {
2259
2605
  const primaryKey = dataSource.primaryKeys.map((key) => row.rawData[key]).join("-");
2260
2606
  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
- });
2607
+ row.addDuplicatedLog(`Duplicated with row ${seenPrimaryKeys.get(primaryKey) || 0}.`);
2268
2608
  } else {
2269
2609
  seenPrimaryKeys.set(primaryKey, row.rowIndex);
2270
2610
  }
@@ -2274,26 +2614,13 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2274
2614
  const rawData = { ...row.rawData };
2275
2615
  const transformedData = {};
2276
2616
  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
2617
  try {
2290
2618
  transformedData[config.name] = typeof config.transform === "function" ? config.transform(rawData[config.name]) : rawData[config.name];
2291
2619
  } catch (error) {
2292
2620
  row.addError({
2293
- rowIndex: row.rowIndex,
2294
2621
  column: getExcelColumnName(headers.indexOf(config.name)),
2295
- message: `transform ${config.name} failed`,
2296
- type: "TRANSFORM"
2622
+ message: `Transform ${config.name} failed: ${error.message}`,
2623
+ type: LOG_TYPE.TRANSFORM_ERROR
2297
2624
  });
2298
2625
  }
2299
2626
  }
@@ -2311,10 +2638,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2311
2638
  return row.setData(result);
2312
2639
  } catch (error) {
2313
2640
  row.addError({
2314
- rowIndex: row.rowIndex,
2315
2641
  column: "",
2316
- message: `convert failed`,
2317
- type: "CONVERT"
2642
+ message: `Convert failed: ${error.message}`,
2643
+ type: LOG_TYPE.CONVERT_ERROR
2318
2644
  });
2319
2645
  }
2320
2646
  return row;
@@ -2340,6 +2666,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2340
2666
  if (checkExisted && typeof checkExisted === "function") {
2341
2667
  updatedDataSet = await checkExisted({ dataSet: updatedDataSet, ctx });
2342
2668
  }
2669
+ if (dataSource.orphanBehavior === "DELETE" && dataSource.checkOrphans && typeof dataSource.checkOrphans === "function") {
2670
+ await dataSource.checkOrphans({ dataSet: updatedDataSet, ctx });
2671
+ }
2343
2672
  if (handleData && typeof handleData === "function") {
2344
2673
  updatedDataSet = await handleData({ dataSet: updatedDataSet, dataSource, ctx });
2345
2674
  } else {
@@ -2362,6 +2691,9 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2362
2691
  }
2363
2692
  return result;
2364
2693
  }
2694
+ function getRowIndex(row, rowIndexKey) {
2695
+ return row[rowIndexKey || "__rowNum"] || 0;
2696
+ }
2365
2697
  function customHandler({ responseHelper, handler, ignoreError = false }) {
2366
2698
  return async (reqOrCtx, resOrNext, nextInExpress) => {
2367
2699
  const isKoa = typeof resOrNext === "function" && !nextInExpress;
@@ -2624,6 +2956,26 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2624
2956
  }
2625
2957
  return options;
2626
2958
  }
2959
+ async bulkWriteDocs({ operations, config, systemLog }) {
2960
+ const log = _makeLog({
2961
+ systemLog,
2962
+ label: "REPO_BULK_WRITE",
2963
+ message: `fn ${this._classname}.prototype.bulkWriteDocs`,
2964
+ input: [{ operations: { ...operations }, config: { ...config }, systemLog: { ...systemLog } }]
2965
+ });
2966
+ const sharedOptions = {
2967
+ ...this._sharedOptions,
2968
+ ...config
2969
+ };
2970
+ try {
2971
+ const result = await this.model.bulkWriteDocs(operations, sharedOptions);
2972
+ log({ level: "info", output: { ...result } });
2973
+ return result;
2974
+ } catch (err) {
2975
+ log({ level: "warn", output: err.toString() });
2976
+ throw err;
2977
+ }
2978
+ }
2627
2979
  async deleteOne({ id }) {
2628
2980
  try {
2629
2981
  const result = await this.model.deleteOne({ _id: id });
@@ -2907,6 +3259,27 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
2907
3259
  }
2908
3260
  return new Service({ repo });
2909
3261
  }
3262
+ class ServiceBulkWrite extends Service {
3263
+ constructor({ repo }) {
3264
+ super({ repo });
3265
+ }
3266
+ static get _classname() {
3267
+ return "ServiceBulkWrite";
3268
+ }
3269
+ async bulkWriteDocs({ operations, config }) {
3270
+ const result = await this.repo.bulkWriteDocs({ operations, config });
3271
+ return result;
3272
+ }
3273
+ }
3274
+ function makeServiceBulkWrite({ repo }) {
3275
+ if (repo === void 0) {
3276
+ throw new Error("repo is required.");
3277
+ }
3278
+ if (repo._superclass !== Repo._superclass) {
3279
+ throw new Error("repo is not an instance of Repo.");
3280
+ }
3281
+ return new ServiceBulkWrite({ repo });
3282
+ }
2910
3283
  async function generalPost({ body = {}, GeneralModel, UniqueKeyGenerator: UniqueKeyGenerator2, resourceInfo }) {
2911
3284
  const { resources, data, globalShared = {}, shared = {}, relationship = {} } = body;
2912
3285
  const _resourceInfo = resourceInfo || body.resourceInfo;
@@ -3027,27 +3400,6 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
3027
3400
  return acc;
3028
3401
  }, {});
3029
3402
  }
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
3403
  function mergeArraysByKey(arr1, arr2) {
3052
3404
  const safeArr1 = Array.isArray(arr1) ? arr1 : [];
3053
3405
  const safeArr2 = Array.isArray(arr2) ? arr2 : [];
@@ -3638,6 +3990,7 @@ ${index2 + 1}. Character: ${JSON.stringify(match.character)}`);
3638
3990
  __proto__: null,
3639
3991
  CheckResult,
3640
3992
  ExcelImportHelper,
3993
+ LOG_TYPE,
3641
3994
  authorize,
3642
3995
  calculateAge,
3643
3996
  changeCreatorOwner,
@@ -4753,6 +5106,7 @@ ${this.zone || ""}`;
4753
5106
  QMeta,
4754
5107
  Repo,
4755
5108
  Service,
5109
+ ServiceBulkWrite,
4756
5110
  Status,
4757
5111
  StatusDocument,
4758
5112
  TemplateCompiler,
@@ -4763,7 +5117,8 @@ ${this.zone || ""}`;
4763
5117
  WebAppResponse,
4764
5118
  getQLogEnv,
4765
5119
  makeApiResponse,
4766
- makeService
5120
+ makeService,
5121
+ makeServiceBulkWrite
4767
5122
  }, Symbol.toStringTag, { value: "Module" }));
4768
5123
  const index = {
4769
5124
  ...helpers,
@@ -4778,6 +5133,7 @@ ${this.zone || ""}`;
4778
5133
  exports2.ErrorDetail = ErrorDetail;
4779
5134
  exports2.ExcelImportHelper = ExcelImportHelper;
4780
5135
  exports2.KeyValueObject = KeyValueObject;
5136
+ exports2.LOG_TYPE = LOG_TYPE;
4781
5137
  exports2.LogRecord = LogRecord;
4782
5138
  exports2.Metadata = Metadata;
4783
5139
  exports2.PushEnvelope = PushEnvelope;
@@ -4787,6 +5143,7 @@ ${this.zone || ""}`;
4787
5143
  exports2.QMeta = QMeta;
4788
5144
  exports2.Repo = Repo;
4789
5145
  exports2.Service = Service;
5146
+ exports2.ServiceBulkWrite = ServiceBulkWrite;
4790
5147
  exports2.Status = Status;
4791
5148
  exports2.StatusDocument = StatusDocument;
4792
5149
  exports2.TemplateCompiler = TemplateCompiler;
@@ -4821,6 +5178,7 @@ ${this.zone || ""}`;
4821
5178
  exports2.isConvertibleToNumber = isConvertibleToNumber;
4822
5179
  exports2.makeApiResponse = makeApiResponse;
4823
5180
  exports2.makeService = makeService;
5181
+ exports2.makeServiceBulkWrite = makeServiceBulkWrite;
4824
5182
  exports2.mergeArraysByKey = mergeArraysByKey;
4825
5183
  exports2.objectHelper = objectHelper;
4826
5184
  exports2.pMap = pMap;