@adobe/spacecat-shared-data-access 3.17.0 → 3.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [@adobe/spacecat-shared-data-access-v3.19.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.18.0...@adobe/spacecat-shared-data-access-v3.19.0) (2026-03-13)
2
+
3
+ ### Features
4
+
5
+ * **data-access:** add PRE_ONBOARDING status to PlgOnboarding entity ([#1433](https://github.com/adobe/spacecat-shared/issues/1433)) ([69b35d7](https://github.com/adobe/spacecat-shared/commit/69b35d77c5f0b2c67ed153227f60198527e530d4))
6
+
7
+ ## [@adobe/spacecat-shared-data-access-v3.18.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.17.0...@adobe/spacecat-shared-data-access-v3.18.0) (2026-03-12)
8
+
9
+ ### Features
10
+
11
+ * **data-access:** add saveMany() to BaseCollection for chunked bulk upsert ([#1428](https://github.com/adobe/spacecat-shared/issues/1428)) ([802bfec](https://github.com/adobe/spacecat-shared/commit/802bfecb21981e577fc1e72b38c24002edcd8bb1))
12
+
1
13
  ## [@adobe/spacecat-shared-data-access-v3.17.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v3.16.0...@adobe/spacecat-shared-data-access-v3.17.0) (2026-03-12)
2
14
 
3
15
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-data-access",
3
- "version": "3.17.0",
3
+ "version": "3.19.0",
4
4
  "description": "Shared modules of the Spacecat Services - Data Access",
5
5
  "type": "module",
6
6
  "engines": {
@@ -876,6 +876,48 @@ class BaseCollection {
876
876
  }
877
877
  }
878
878
 
879
+ /**
880
+ * Saves multiple model instances to the database in chunked batches.
881
+ * Each chunk is persisted via a single PostgREST upsert call, avoiding
882
+ * the thundering-herd problem caused by N concurrent individual saves.
883
+ *
884
+ * Chunks are processed sequentially. If a chunk fails, the error is
885
+ * propagated immediately — chunks already persisted are NOT rolled back.
886
+ * Callers must account for partial saves on failure.
887
+ *
888
+ * @param {BaseModel[]} items - Model instances with in-memory mutations to persist.
889
+ * @param {Object} [options] - Options.
890
+ * @param {number} [options.chunkSize=25] - Max items per upsert request.
891
+ * Keep low for entities with large payloads (e.g. Suggestion.data JSONB).
892
+ * @returns {Promise<void>}
893
+ * @throws {DataAccessError} If any chunk fails. Previously completed chunks
894
+ * are already persisted — callers must account for partial saves.
895
+ */
896
+ async saveMany(items, { chunkSize = 25 } = {}) {
897
+ if (!isNonEmptyArray(items)) {
898
+ return;
899
+ }
900
+
901
+ const effectiveChunkSize = Math.max(1, Math.floor(chunkSize)) || 25;
902
+ const totalChunks = Math.ceil(items.length / effectiveChunkSize);
903
+
904
+ if (totalChunks > 1) {
905
+ this.log.info(`[${this.entityName}] saveMany: saving ${items.length} items in ${totalChunks} chunks of ${effectiveChunkSize}`);
906
+ }
907
+
908
+ for (let i = 0; i < items.length; i += effectiveChunkSize) {
909
+ const chunkIndex = Math.floor(i / effectiveChunkSize) + 1;
910
+ const chunk = items.slice(i, i + effectiveChunkSize);
911
+ try {
912
+ // eslint-disable-next-line no-await-in-loop
913
+ await this._saveMany(chunk);
914
+ } catch (error) {
915
+ this.log.error(`[${this.entityName}] saveMany: chunk ${chunkIndex}/${totalChunks} failed — ${i} of ${items.length} items already persisted`);
916
+ throw error;
917
+ }
918
+ }
919
+ }
920
+
879
921
  async _saveMany(items) {
880
922
  if (!isNonEmptyArray(items)) {
881
923
  const message = `Failed to save many [${this.entityName}]: items must be a non-empty array`;
@@ -62,7 +62,8 @@ export interface BatchGetOptions {
62
62
  export interface BaseCollection<T extends BaseModel> {
63
63
  _onCreate(item: T): void;
64
64
  _onCreateMany(items: MultiStatusCreateResult<T>): void;
65
- _saveMany(items: T[]): Promise<T[]>;
65
+ _saveMany(items: T[]): Promise<void>;
66
+ saveMany(items: T[], options?: { chunkSize?: number }): Promise<void>;
66
67
  all(sortKeys?: object, options?: QueryOptions): Promise<T[] | PaginatedResult<T>>;
67
68
  allByIndexKeys(keys: object, options?: QueryOptions): Promise<T[] | PaginatedResult<T>>;
68
69
  batchGetByKeys(keys: object[], options?: BatchGetOptions): Promise<{ data: T[]; unprocessed: object[] }>;
@@ -13,6 +13,7 @@
13
13
  import type { BaseCollection, BaseModel } from '../index';
14
14
 
15
15
  export type PlgOnboardingStatus =
16
+ | 'PRE_ONBOARDING'
16
17
  | 'IN_PROGRESS'
17
18
  | 'ONBOARDED'
18
19
  | 'ERROR'
@@ -27,6 +27,7 @@ class PlgOnboarding extends BaseModel {
27
27
  static DOMAIN_PATTERN = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/;
28
28
 
29
29
  static STATUSES = {
30
+ PRE_ONBOARDING: 'PRE_ONBOARDING',
30
31
  IN_PROGRESS: 'IN_PROGRESS',
31
32
  ONBOARDED: 'ONBOARDED',
32
33
  ERROR: 'ERROR',
@@ -18,3 +18,16 @@ export {
18
18
  Site,
19
19
  SiteCollection,
20
20
  };
21
+
22
+ export {
23
+ Config,
24
+ configSchema,
25
+ validateConfiguration,
26
+ extractWellKnownTags,
27
+ IMPORT_TYPES,
28
+ IMPORT_DESTINATIONS,
29
+ IMPORT_SOURCES,
30
+ IMPORT_TYPE_SCHEMAS,
31
+ DEFAULT_IMPORT_CONFIGS,
32
+ DEFAULT_CONFIG,
33
+ } from './config.js';
@@ -55,7 +55,7 @@ class SuggestionCollection extends BaseCollection {
55
55
  suggestion.setStatus(status);
56
56
  });
57
57
 
58
- await this._saveMany(suggestions);
58
+ await this.saveMany(suggestions);
59
59
 
60
60
  return suggestions;
61
61
  }