@nuskin/contentstack-lib 2.1.0-pa-1117.11 → 2.1.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/.releaserc +1 -1
- package/README.md +20 -0
- package/__tests__/api.spec.js +197 -28
- package/docs/CHANGELOG.md +1 -1
- package/package.json +1 -1
- package/src/api.js +139 -28
package/.releaserc
CHANGED
package/README.md
CHANGED
|
@@ -54,6 +54,26 @@ const [
|
|
|
54
54
|
mergeWithFallback: true
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
// Query a multiple-entry content type by one or more fields.
|
|
58
|
+
const shippingForms = await Stack.getMultiEntriesByFields(
|
|
59
|
+
'shipping_address_form',
|
|
60
|
+
{
|
|
61
|
+
country_code: 'US',
|
|
62
|
+
locale: 'en-us'
|
|
63
|
+
},
|
|
64
|
+
true
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// Convenience wrapper when you only expect one result.
|
|
68
|
+
const shippingForm = await Stack.getMultiEntryByFields(
|
|
69
|
+
'shipping_address_form',
|
|
70
|
+
{
|
|
71
|
+
country_code: 'US',
|
|
72
|
+
locale: 'en-us'
|
|
73
|
+
},
|
|
74
|
+
true
|
|
75
|
+
);
|
|
76
|
+
|
|
57
77
|
// We could possibly add functionality to return the list of regions markets and languages in a single object structure
|
|
58
78
|
```
|
|
59
79
|
|
package/__tests__/api.spec.js
CHANGED
|
@@ -16,6 +16,7 @@ const mockPromiseResult = jest.fn();
|
|
|
16
16
|
const mockSinglePromiseResult = jest.fn();
|
|
17
17
|
const mockStack = jest.fn();
|
|
18
18
|
const mockContainedIn = jest.fn();
|
|
19
|
+
const mockWhere = jest.fn();
|
|
19
20
|
const mockIncludeReference = jest.fn();
|
|
20
21
|
const mockFetch = jest.fn();
|
|
21
22
|
|
|
@@ -55,6 +56,7 @@ beforeEach(() => {
|
|
|
55
56
|
})
|
|
56
57
|
})),
|
|
57
58
|
containedIn: mockContainedIn,
|
|
59
|
+
where: mockWhere,
|
|
58
60
|
includeReference: mockIncludeReference,
|
|
59
61
|
toJSON: jest.fn(() => ({
|
|
60
62
|
find: mockPromiseResult
|
|
@@ -62,48 +64,123 @@ beforeEach(() => {
|
|
|
62
64
|
};
|
|
63
65
|
|
|
64
66
|
mockContainedIn.mockImplementation(() => mockQuery);
|
|
67
|
+
mockWhere.mockImplementation(() => mockQuery);
|
|
65
68
|
mockIncludeReference.mockImplementation(() => mockQuery);
|
|
66
69
|
mockStack.mockImplementation(() => ({
|
|
67
|
-
ContentType: () => ({
|
|
70
|
+
ContentType: (contentType) => ({
|
|
68
71
|
Query: () => mockQuery,
|
|
69
|
-
fetch: mockFetch
|
|
72
|
+
fetch: () => mockFetch(contentType)
|
|
70
73
|
})
|
|
71
74
|
}));
|
|
72
75
|
|
|
73
|
-
mockFetch.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
{
|
|
77
|
-
uid: 'countries',
|
|
78
|
-
data_type: 'reference'
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
uid: 'details',
|
|
82
|
-
data_type: 'group',
|
|
76
|
+
mockFetch.mockImplementation((contentType) => {
|
|
77
|
+
const schemas = {
|
|
78
|
+
shipping_address_form: {
|
|
79
|
+
content_type: {
|
|
83
80
|
schema: [
|
|
84
81
|
{
|
|
85
|
-
uid: '
|
|
86
|
-
data_type: 'reference'
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
uid: 'promo_blocks',
|
|
92
|
-
data_type: 'blocks',
|
|
93
|
-
blocks: [
|
|
82
|
+
uid: 'countries',
|
|
83
|
+
data_type: 'reference',
|
|
84
|
+
reference_to: 'market'
|
|
85
|
+
},
|
|
94
86
|
{
|
|
95
|
-
uid: '
|
|
87
|
+
uid: 'details',
|
|
88
|
+
data_type: 'group',
|
|
96
89
|
schema: [
|
|
97
90
|
{
|
|
98
|
-
uid: '
|
|
99
|
-
data_type: 'reference'
|
|
91
|
+
uid: 'address_form',
|
|
92
|
+
data_type: 'reference',
|
|
93
|
+
reference_to: 'address_form'
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
uid: 'promo_blocks',
|
|
99
|
+
data_type: 'blocks',
|
|
100
|
+
blocks: [
|
|
101
|
+
{
|
|
102
|
+
uid: 'hero',
|
|
103
|
+
schema: [
|
|
104
|
+
{
|
|
105
|
+
uid: 'banner',
|
|
106
|
+
data_type: 'reference',
|
|
107
|
+
reference_to: 'banner'
|
|
108
|
+
}
|
|
109
|
+
]
|
|
100
110
|
}
|
|
101
111
|
]
|
|
102
112
|
}
|
|
103
113
|
]
|
|
104
114
|
}
|
|
105
|
-
|
|
106
|
-
|
|
115
|
+
},
|
|
116
|
+
address_form: {
|
|
117
|
+
content_type: {
|
|
118
|
+
schema: [
|
|
119
|
+
{
|
|
120
|
+
uid: 'address_elements',
|
|
121
|
+
data_type: 'reference',
|
|
122
|
+
reference_to: 'address_form_field'
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
market: {
|
|
128
|
+
content_type: {
|
|
129
|
+
schema: []
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
banner: {
|
|
133
|
+
content_type: {
|
|
134
|
+
schema: []
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
address_form_field: {
|
|
138
|
+
content_type: {
|
|
139
|
+
schema: [
|
|
140
|
+
{
|
|
141
|
+
uid: 'field_config',
|
|
142
|
+
data_type: 'reference',
|
|
143
|
+
reference_to: 'field_config'
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
field_config: {
|
|
149
|
+
content_type: {
|
|
150
|
+
schema: [
|
|
151
|
+
{
|
|
152
|
+
uid: 'validation_rule',
|
|
153
|
+
data_type: 'reference',
|
|
154
|
+
reference_to: 'validation_rule'
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
validation_rule: {
|
|
160
|
+
content_type: {
|
|
161
|
+
schema: [
|
|
162
|
+
{
|
|
163
|
+
uid: 'too_deep_reference',
|
|
164
|
+
data_type: 'reference',
|
|
165
|
+
reference_to: 'too_deep_reference'
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
too_deep_reference: {
|
|
171
|
+
content_type: {
|
|
172
|
+
schema: [
|
|
173
|
+
{
|
|
174
|
+
uid: 'should_not_be_included',
|
|
175
|
+
data_type: 'reference',
|
|
176
|
+
reference_to: 'market'
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return Promise.resolve(schemas[contentType] || {content_type: {schema: []}});
|
|
107
184
|
});
|
|
108
185
|
|
|
109
186
|
jest.mock("contentstack", () => ({Stack: mockStack}));
|
|
@@ -113,6 +190,7 @@ afterEach(() => {
|
|
|
113
190
|
mockSinglePromiseResult.mockReset();
|
|
114
191
|
mockPromiseResult.mockReset();
|
|
115
192
|
mockContainedIn.mockReset();
|
|
193
|
+
mockWhere.mockReset();
|
|
116
194
|
mockIncludeReference.mockReset();
|
|
117
195
|
mockFetch.mockReset();
|
|
118
196
|
//jest.resetAllMocks(); don't reset the mockStack function
|
|
@@ -222,10 +300,13 @@ describe("ContentstackApi", () => {
|
|
|
222
300
|
const {getStack} = require('../src/api');
|
|
223
301
|
const Stack = getStack('dev');
|
|
224
302
|
await Stack.getMultiEntries('shipping_address_form', true, ['United States']);
|
|
225
|
-
expect(mockFetch).toHaveBeenCalledTimes(
|
|
303
|
+
expect(mockFetch).toHaveBeenCalledTimes(6);
|
|
226
304
|
expect(mockIncludeReference).toHaveBeenCalledWith([
|
|
227
305
|
'countries',
|
|
228
306
|
'details.address_form',
|
|
307
|
+
'details.address_form.address_elements',
|
|
308
|
+
'details.address_form.address_elements.field_config',
|
|
309
|
+
'details.address_form.address_elements.field_config.validation_rule',
|
|
229
310
|
'promo_blocks.hero.banner'
|
|
230
311
|
]);
|
|
231
312
|
});
|
|
@@ -236,16 +317,104 @@ describe("ContentstackApi", () => {
|
|
|
236
317
|
const Stack = getStack('test');
|
|
237
318
|
await Stack.getMultiEntries('shipping_address_form', true, ['United States']);
|
|
238
319
|
await Stack.getMultiEntries('shipping_address_form', true, ['Canada']);
|
|
239
|
-
expect(mockFetch).toHaveBeenCalledTimes(
|
|
320
|
+
expect(mockFetch).toHaveBeenCalledTimes(6);
|
|
240
321
|
expect(mockIncludeReference).toHaveBeenNthCalledWith(1, [
|
|
241
322
|
'countries',
|
|
242
323
|
'details.address_form',
|
|
324
|
+
'details.address_form.address_elements',
|
|
325
|
+
'details.address_form.address_elements.field_config',
|
|
326
|
+
'details.address_form.address_elements.field_config.validation_rule',
|
|
243
327
|
'promo_blocks.hero.banner'
|
|
244
328
|
]);
|
|
245
329
|
expect(mockIncludeReference).toHaveBeenNthCalledWith(2, [
|
|
246
330
|
'countries',
|
|
247
331
|
'details.address_form',
|
|
332
|
+
'details.address_form.address_elements',
|
|
333
|
+
'details.address_form.address_elements.field_config',
|
|
334
|
+
'details.address_form.address_elements.field_config.validation_rule',
|
|
248
335
|
'promo_blocks.hero.banner'
|
|
249
336
|
]);
|
|
250
337
|
});
|
|
338
|
+
|
|
339
|
+
test('getMultiEntries limits automatic reference traversal to four levels deep', async () => {
|
|
340
|
+
mockPromiseResult.mockResolvedValueOnce([[{title: 'United States'}]]);
|
|
341
|
+
const {getStack} = require('../src/api');
|
|
342
|
+
const Stack = getStack('stage');
|
|
343
|
+
await Stack.getMultiEntries('shipping_address_form', true, ['United States']);
|
|
344
|
+
expect(mockIncludeReference).toHaveBeenCalledWith([
|
|
345
|
+
'countries',
|
|
346
|
+
'details.address_form',
|
|
347
|
+
'details.address_form.address_elements',
|
|
348
|
+
'details.address_form.address_elements.field_config',
|
|
349
|
+
'details.address_form.address_elements.field_config.validation_rule',
|
|
350
|
+
'promo_blocks.hero.banner'
|
|
351
|
+
]);
|
|
352
|
+
expect(mockIncludeReference).not.toHaveBeenCalledWith(expect.arrayContaining([
|
|
353
|
+
'details.address_form.address_elements.field_config.validation_rule.too_deep_reference',
|
|
354
|
+
'details.address_form.address_elements.field_config.validation_rule.too_deep_reference.should_not_be_included'
|
|
355
|
+
]));
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test('getMultiEntriesByFields applies where filters for scalar values', async () => {
|
|
359
|
+
mockPromiseResult.mockResolvedValueOnce([[{title: 'United States'}]]);
|
|
360
|
+
const {getStack} = require('../src/api');
|
|
361
|
+
const Stack = getStack('prod');
|
|
362
|
+
await Stack.getMultiEntriesByFields('market', {
|
|
363
|
+
country_code: 'US',
|
|
364
|
+
locale: 'en-us'
|
|
365
|
+
});
|
|
366
|
+
expect(mockWhere).toHaveBeenNthCalledWith(1, 'country_code', 'US');
|
|
367
|
+
expect(mockWhere).toHaveBeenNthCalledWith(2, 'locale', 'en-us');
|
|
368
|
+
expect(mockContainedIn).not.toHaveBeenCalled();
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
test('getMultiEntriesByFields applies containedIn for array values', async () => {
|
|
372
|
+
mockPromiseResult.mockResolvedValueOnce([[{title: 'United States'}]]);
|
|
373
|
+
const {getStack} = require('../src/api');
|
|
374
|
+
const Stack = getStack('dev');
|
|
375
|
+
await Stack.getMultiEntriesByFields('market', {
|
|
376
|
+
title: ['United States', 'Canada'],
|
|
377
|
+
locale: 'en-us'
|
|
378
|
+
});
|
|
379
|
+
expect(mockContainedIn).toHaveBeenCalledWith('title', ['United States', 'Canada']);
|
|
380
|
+
expect(mockWhere).toHaveBeenCalledWith('locale', 'en-us');
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test('getMultiEntriesByFields resolves include refs when requested', async () => {
|
|
384
|
+
mockPromiseResult.mockResolvedValueOnce([[{title: 'United States'}]]);
|
|
385
|
+
const {getStack} = require('../src/api');
|
|
386
|
+
const Stack = getStack('stage');
|
|
387
|
+
await Stack.getMultiEntriesByFields('shipping_address_form', {
|
|
388
|
+
country_code: 'US',
|
|
389
|
+
locale: 'en-us'
|
|
390
|
+
}, true);
|
|
391
|
+
expect(mockIncludeReference).toHaveBeenCalledWith([
|
|
392
|
+
'countries',
|
|
393
|
+
'details.address_form',
|
|
394
|
+
'details.address_form.address_elements',
|
|
395
|
+
'details.address_form.address_elements.field_config',
|
|
396
|
+
'details.address_form.address_elements.field_config.validation_rule',
|
|
397
|
+
'promo_blocks.hero.banner'
|
|
398
|
+
]);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test('getMultiEntriesByFields throws when fields are missing', async () => {
|
|
402
|
+
const {getStack} = require('../src/api');
|
|
403
|
+
const Stack = getStack('dev');
|
|
404
|
+
await expect(Stack.getMultiEntriesByFields('market')).rejects.toStrictEqual(
|
|
405
|
+
new Error('Call to getMultiEntriesByFields: fields are required')
|
|
406
|
+
);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
test('getMultiEntryByFields returns the first matching entry', async () => {
|
|
410
|
+
mockPromiseResult.mockResolvedValueOnce([[
|
|
411
|
+
{title: 'United States'},
|
|
412
|
+
{title: 'Canada'}
|
|
413
|
+
]]);
|
|
414
|
+
const {getStack} = require('../src/api');
|
|
415
|
+
const Stack = getStack('test');
|
|
416
|
+
await expect(Stack.getMultiEntryByFields('market', {
|
|
417
|
+
locale: 'en-us'
|
|
418
|
+
})).resolves.toStrictEqual({title: 'United States'});
|
|
419
|
+
});
|
|
251
420
|
});
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
# [2.1.0
|
|
1
|
+
# [2.1.0](https://code.tls.nuskin.io/ns-am/utility/npm/contentstack-lib/compare/v2.0.2...v2.1.0) (2026-06-26)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuskin/contentstack-lib",
|
|
3
|
-
"version": "2.1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "This project contains configuration and api code to access Contentstack, to be shared between the backend (AWS Lambda) and frontend (Vue, etc).",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
package/src/api.js
CHANGED
|
@@ -9,6 +9,8 @@ const {contentstack: prodEnvConfig} = require(`../config/prod.json`);
|
|
|
9
9
|
let env = null;
|
|
10
10
|
let Stack = null;
|
|
11
11
|
const referenceFieldCache = new Map();
|
|
12
|
+
const contentTypeSchemaCache = new Map();
|
|
13
|
+
const MAX_REFERENCE_DEPTH = 4;
|
|
12
14
|
|
|
13
15
|
const COMMON_LANGUAGES = {
|
|
14
16
|
'da': 'da-dk',
|
|
@@ -174,33 +176,80 @@ async function getSingletonEntries(options) {
|
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return schema
|
|
179
|
+
async function _getContentTypeSchema(contentType) {
|
|
180
|
+
if (contentTypeSchemaCache.has(contentType)) {
|
|
181
|
+
return contentTypeSchemaCache.get(contentType);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const contentTypeSchema = await Stack.ContentType(contentType).fetch();
|
|
185
|
+
const schema = contentTypeSchema.content_type.schema || [];
|
|
186
|
+
contentTypeSchemaCache.set(contentType, schema);
|
|
187
|
+
return schema;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function _collectReferenceFieldPathsForSchema(schema = [], parentPath = '', visited = new Set(), depth = 0) {
|
|
191
|
+
const allPaths = [];
|
|
192
|
+
|
|
193
|
+
for (const field of schema) {
|
|
186
194
|
const currentPath = parentPath ? `${parentPath}.${field.uid}` : field.uid;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
195
|
+
|
|
196
|
+
if (Array.isArray(field.schema)) {
|
|
197
|
+
const nestedSchemaPaths = await _collectReferenceFieldPathsForSchema(field.schema, currentPath, visited, depth);
|
|
198
|
+
allPaths.push(...nestedSchemaPaths);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (field.data_type === 'blocks' && Array.isArray(field.blocks)) {
|
|
202
|
+
for (const block of field.blocks) {
|
|
203
|
+
if (Array.isArray(block.schema)) {
|
|
204
|
+
const blockPaths = await _collectReferenceFieldPathsForSchema(
|
|
205
|
+
block.schema,
|
|
206
|
+
`${currentPath}.${block.uid}`,
|
|
207
|
+
visited,
|
|
208
|
+
depth
|
|
209
|
+
);
|
|
210
|
+
allPaths.push(...blockPaths);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (field.data_type === 'reference') {
|
|
216
|
+
const currentDepth = depth + 1;
|
|
217
|
+
if (currentDepth > MAX_REFERENCE_DEPTH) {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
allPaths.push(currentPath);
|
|
221
|
+
const referenceTargets = Array.isArray(field.reference_to) ?
|
|
222
|
+
field.reference_to :
|
|
223
|
+
field.reference_to ? [field.reference_to] : [];
|
|
224
|
+
|
|
225
|
+
if (currentDepth >= MAX_REFERENCE_DEPTH) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (const referencedContentType of referenceTargets) {
|
|
230
|
+
const nestedReferencePaths = await _collectReferenceFieldPathsForContentType(
|
|
231
|
+
referencedContentType,
|
|
232
|
+
currentPath,
|
|
233
|
+
visited,
|
|
234
|
+
currentDepth
|
|
235
|
+
);
|
|
236
|
+
allPaths.push(...nestedReferencePaths);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return [...new Set(allPaths)];
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function _collectReferenceFieldPathsForContentType(contentType, parentPath = '', visited = new Set(), depth = 0) {
|
|
245
|
+
const visitKey = `${contentType}|${parentPath}|${depth}`;
|
|
246
|
+
if (visited.has(visitKey)) {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
visited.add(visitKey);
|
|
250
|
+
|
|
251
|
+
const schema = await _getContentTypeSchema(contentType);
|
|
252
|
+
return _collectReferenceFieldPathsForSchema(schema, parentPath, visited, depth);
|
|
204
253
|
}
|
|
205
254
|
|
|
206
255
|
/**
|
|
@@ -231,12 +280,26 @@ async function _resolveIncludeRefs(contentType, includeRefs) {
|
|
|
231
280
|
return referenceFieldCache.get(contentType);
|
|
232
281
|
}
|
|
233
282
|
|
|
234
|
-
const
|
|
235
|
-
const referenceFields = _collectReferenceFieldPaths(contentTypeSchema.content_type.schema);
|
|
283
|
+
const referenceFields = await _collectReferenceFieldPathsForContentType(contentType);
|
|
236
284
|
referenceFieldCache.set(contentType, referenceFields);
|
|
237
285
|
return referenceFields;
|
|
238
286
|
}
|
|
239
287
|
|
|
288
|
+
/**
|
|
289
|
+
* Apply field filters to a query. Scalar values use where(), arrays use containedIn().
|
|
290
|
+
* @param {Object} query
|
|
291
|
+
* @param {Object<string, string|string[]>} fields
|
|
292
|
+
* @return {Object}
|
|
293
|
+
* @private
|
|
294
|
+
*/
|
|
295
|
+
function _applyFieldFilters(query, fields) {
|
|
296
|
+
return Object.entries(fields).reduce((currentQuery, [field, value]) => {
|
|
297
|
+
return Array.isArray(value) ?
|
|
298
|
+
currentQuery.containedIn(field, value) :
|
|
299
|
+
currentQuery.where(field, value);
|
|
300
|
+
}, query);
|
|
301
|
+
}
|
|
302
|
+
|
|
240
303
|
/**
|
|
241
304
|
* Gets all the specified entries for a multiple content type
|
|
242
305
|
* @param {string} contentType
|
|
@@ -264,6 +327,51 @@ const getMultiEntries = async (contentType, includeRefs, values) => {
|
|
|
264
327
|
}
|
|
265
328
|
};
|
|
266
329
|
|
|
330
|
+
/**
|
|
331
|
+
* Gets entries for a multiple content type filtered by one or more fields.
|
|
332
|
+
* @param {string} contentType
|
|
333
|
+
* @param {Object<string, string|string[]>} fields
|
|
334
|
+
* @param {boolean|string|string[]=} includeRefs
|
|
335
|
+
* @return {Promise<Object[]>}
|
|
336
|
+
*/
|
|
337
|
+
const getMultiEntriesByFields = async (contentType, fields, includeRefs) => {
|
|
338
|
+
if (!fields || !Object.keys(fields).length) {
|
|
339
|
+
throw new Error('Call to getMultiEntriesByFields: fields are required');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
const resolvedIncludeRefs = await _resolveIncludeRefs(contentType, includeRefs);
|
|
344
|
+
let query = _applyFieldFilters(
|
|
345
|
+
Stack
|
|
346
|
+
.ContentType(contentType)
|
|
347
|
+
.Query(),
|
|
348
|
+
fields
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
if (resolvedIncludeRefs.length) {
|
|
352
|
+
query = query.includeReference(resolvedIncludeRefs);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const [results] = await query.toJSON().find();
|
|
356
|
+
return results;
|
|
357
|
+
} catch (err) {
|
|
358
|
+
console.error(err);
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Gets the first matching entry for a multiple content type filtered by fields.
|
|
365
|
+
* @param {string} contentType
|
|
366
|
+
* @param {Object<string, string|string[]>} fields
|
|
367
|
+
* @param {boolean|string|string[]=} includeRefs
|
|
368
|
+
* @return {Promise<Object|undefined>}
|
|
369
|
+
*/
|
|
370
|
+
const getMultiEntryByFields = async (contentType, fields, includeRefs) => {
|
|
371
|
+
const results = await getMultiEntriesByFields(contentType, fields, includeRefs);
|
|
372
|
+
return results[0];
|
|
373
|
+
};
|
|
374
|
+
|
|
267
375
|
/**
|
|
268
376
|
* Returns contentstack Stack object initialized with the api key, deliveryToken, and extended with custom functionality
|
|
269
377
|
* @param {'dev' | 'test' | 'stage' | 'prod'} envrnmnt
|
|
@@ -284,12 +392,15 @@ function getStack(envrnmnt) {
|
|
|
284
392
|
|
|
285
393
|
env = envrnmnt;
|
|
286
394
|
referenceFieldCache.clear();
|
|
395
|
+
contentTypeSchemaCache.clear();
|
|
287
396
|
const {apiKey: api_key, deliveryToken: delivery_token, environment} = getConfig(env);
|
|
288
397
|
Stack = Contentstack.Stack({api_key, delivery_token, environment});
|
|
289
398
|
|
|
290
399
|
// extend the Stack with a custom function to get translations
|
|
291
400
|
Stack.getSingletonEntries = getSingletonEntries;
|
|
292
401
|
Stack.getMultiEntries = getMultiEntries;
|
|
402
|
+
Stack.getMultiEntriesByFields = getMultiEntriesByFields;
|
|
403
|
+
Stack.getMultiEntryByFields = getMultiEntryByFields;
|
|
293
404
|
|
|
294
405
|
return Stack;
|
|
295
406
|
}
|