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