@adobe/spacecat-shared-data-access 2.42.0 → 2.43.1

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,17 @@
1
+ # [@adobe/spacecat-shared-data-access-v2.43.1](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.43.0...@adobe/spacecat-shared-data-access-v2.43.1) (2025-08-04)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * mark formSource optional in SiteTopForm model ([#884](https://github.com/adobe/spacecat-shared/issues/884)) ([7ea285b](https://github.com/adobe/spacecat-shared/commit/7ea285b59809e4983ec6337b9544be57ed62148e))
7
+
8
+ # [@adobe/spacecat-shared-data-access-v2.43.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.42.0...@adobe/spacecat-shared-data-access-v2.43.0) (2025-07-30)
9
+
10
+
11
+ ### Features
12
+
13
+ * Add `'never'` to job intervals ([#885](https://github.com/adobe/spacecat-shared/issues/885)) ([#886](https://github.com/adobe/spacecat-shared/issues/886)) ([07a92ce](https://github.com/adobe/spacecat-shared/commit/07a92ce2659e27a85058d1d40942ec7e8b8897e3))
14
+
1
15
  # [@adobe/spacecat-shared-data-access-v2.42.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.41.0...@adobe/spacecat-shared-data-access-v2.42.0) (2025-07-29)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-data-access",
3
- "version": "2.42.0",
3
+ "version": "2.43.1",
4
4
  "description": "Shared modules of the Spacecat Services - Data Access",
5
5
  "type": "module",
6
6
  "engines": {
@@ -31,6 +31,7 @@ class Configuration extends BaseModel {
31
31
  };
32
32
 
33
33
  static JOB_INTERVALS = {
34
+ NEVER: 'never', // allows to enable imports without scheduling them.
34
35
  EVERY_HOUR: 'every-hour',
35
36
  DAILY: 'daily',
36
37
  WEEKLY: 'weekly',
@@ -22,6 +22,49 @@ import BaseCollection from '../base/base.collection.js';
22
22
  * @extends BaseCollection
23
23
  */
24
24
  class SiteTopFormCollection extends BaseCollection {
25
+ /**
26
+ * Override create method to validate URL presence and handle optional formSource
27
+ * @param {Object} item - The data for the entity to be created
28
+ * @param {Object} [options] - Additional options for the creation process
29
+ * @returns {Promise<BaseModel>} - A promise that resolves to the created model instance
30
+ * @throws {Error} - Throws an error if URL is not present
31
+ */
32
+ async create(item, options = {}) {
33
+ if (!hasText(item?.url)) {
34
+ throw new Error('URL is required and cannot be empty');
35
+ }
36
+
37
+ // If formSource is not provided or empty, set it as empty string (default value)
38
+ const processedItem = {
39
+ ...item,
40
+ formSource: hasText(item.formSource) ? item.formSource : '',
41
+ };
42
+
43
+ return super.create(processedItem, options);
44
+ }
45
+
46
+ /**
47
+ * Override createMany method to validate URLs and handle optional formSource
48
+ * @param {Array<Object>} newItems - An array of data for the entities to be created
49
+ * @param {BaseModel} [parent] - Optional parent entity
50
+ * @returns {Promise<Object>} - A promise that resolves to created and error items
51
+ */
52
+ async createMany(newItems, parent = null) {
53
+ // Validate and process items
54
+ const processedItems = newItems.map((item) => {
55
+ if (!hasText(item?.url)) {
56
+ throw new Error('URL is required and cannot be empty for all items');
57
+ }
58
+
59
+ return {
60
+ ...item,
61
+ formSource: hasText(item.formSource) ? item.formSource : '',
62
+ };
63
+ });
64
+
65
+ return super.createMany(processedItems, parent);
66
+ }
67
+
25
68
  async removeForSiteId(siteId, source) {
26
69
  if (!hasText(siteId)) {
27
70
  throw new Error('SiteId is required');
@@ -42,20 +85,81 @@ class SiteTopFormCollection extends BaseCollection {
42
85
  }
43
86
  }
44
87
 
45
- async removeByUrlAndFormSource(url, formSource) {
88
+ /**
89
+ * Remove forms by URL and optional formSource
90
+ * @param {string} url - The URL to match
91
+ * @param {string} [formSource] - The formSource to match (optional, defaults to empty string)
92
+ * @returns {Promise<void>}
93
+ */
94
+ async removeByUrlAndFormSource(url, formSource = '') {
46
95
  if (!hasText(url)) {
47
96
  throw new Error('URL is required');
48
97
  }
49
- if (!hasText(formSource)) {
50
- throw new Error('FormSource is required');
51
- }
52
98
 
53
- const formToRemove = await this.findByUrlAndFormSource(url, formSource);
99
+ // Handle both cases: when formSource is provided and when it's not
100
+ let formToRemove;
101
+
102
+ if (hasText(formSource)) {
103
+ formToRemove = await this.findByUrlAndFormSource(url, formSource);
104
+ } else {
105
+ // Find forms by URL where formSource is empty string (default)
106
+ formToRemove = await this.findByUrlAndFormSource(url, '');
107
+ }
54
108
 
55
109
  if (formToRemove) {
56
110
  await this.removeByIds([formToRemove.getId()]);
57
111
  }
58
112
  }
113
+
114
+ /**
115
+ * Find forms by URL, handling optional formSource
116
+ * @param {string} url - The URL to search for
117
+ * @param {string} [formSource] - The formSource to search for
118
+ * (optional, defaults to empty string)
119
+ * @returns {Promise<BaseModel|null>} - The found form or null
120
+ */
121
+ async findByUrlAndFormSource(url, formSource = '') {
122
+ if (!hasText(url)) {
123
+ throw new Error('URL is required');
124
+ }
125
+
126
+ try {
127
+ const searchFormSource = hasText(formSource) ? formSource : '';
128
+
129
+ // First try to find with the provided formSource
130
+ let indexKeys = {
131
+ url,
132
+ formSource: searchFormSource,
133
+ };
134
+
135
+ let result = await this.findByIndexKeys(indexKeys, {
136
+ index: 'spacecat-data-gsi2pk-gsi2sk',
137
+ });
138
+
139
+ // If not found and searching for empty string, also try with null
140
+ // This handles legacy data that might have null formSource
141
+ if (!result && searchFormSource === '') {
142
+ try {
143
+ indexKeys = {
144
+ url,
145
+ formSource: null,
146
+ };
147
+
148
+ result = await this.findByIndexKeys(indexKeys, {
149
+ index: 'spacecat-data-gsi2pk-gsi2sk',
150
+ });
151
+ } catch (legacyError) {
152
+ // If the null search also fails, ignore and return the original null result
153
+ this.log.debug(`Legacy null formSource search failed: ${legacyError.message}`);
154
+ }
155
+ }
156
+
157
+ return result;
158
+ } catch (error) {
159
+ this.log.error(`Failed to find form by URL and formSource: ${error.message}`);
160
+ return null;
161
+ }
162
+ }
59
163
  }
60
164
 
61
165
  export default SiteTopFormCollection;
@@ -40,7 +40,8 @@ const schema = new SchemaBuilder(SiteTopForm, SiteTopFormCollection)
40
40
  })
41
41
  .addAttribute('formSource', {
42
42
  type: 'string',
43
- required: true,
43
+ required: false,
44
+ default: '',
44
45
  })
45
46
  .addAttribute('traffic', {
46
47
  type: 'number',