musora-content-services 1.0.19 → 1.0.20

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.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "1.0.19",
3
+ "version": "1.0.20",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/publish.sh CHANGED
File without changes
@@ -0,0 +1,30 @@
1
+ let contentTypeConfig = {
2
+ 'song': {
3
+ 'fields': [
4
+ '"artist_name": artist->name',
5
+ 'soundslice',
6
+ 'instrumentless'
7
+ ],
8
+ 'relationships': {
9
+ 'artist': {
10
+ isOneToOne: true
11
+ }
12
+ }
13
+ },
14
+ 'challenge':{
15
+ 'fields':[
16
+ 'enrollment_start_time',
17
+ 'enrollment_end_time',
18
+ 'registration_url',
19
+ '"lesson_count": child_count',
20
+ '"primary_cta_text": select(dateTime(published_on) > dateTime(now()) && dateTime(enrollment_start_time) > dateTime(now()) => "Notify Me", "Start Challenge")',
21
+ 'challenge_state',
22
+ 'challenge_state_text',
23
+ ]
24
+ }
25
+ }
26
+
27
+
28
+ module.exports = {
29
+ contentTypeConfig
30
+ }
package/src/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ const {contentTypeConfig} = require('../src/contentTypeConfig.js');
2
+
1
3
  let globalConfig = {};
2
4
 
3
5
  /**
@@ -11,7 +13,7 @@ let globalConfig = {};
11
13
  * @param {string} config.version - The API version to use.
12
14
  * @param {boolean} [config.debug=false] - Optional flag to enable debug mode, which logs the query and results.
13
15
  * @param {boolean} [config.useCachedAPI=true] - Optional flag to disable cached API.
14
- *
16
+ *
15
17
  * @example
16
18
  * // Initialize the Sanity service in your app.js
17
19
  * initializeSanityService({
@@ -179,7 +181,7 @@ async function fetchRelatedSongs(brand, songId) {
179
181
  * @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
180
182
  * @param {string} [params.groupBy=""] - The field to group the results by.
181
183
  * @returns {Promise<Object|null>} - The fetched song data or null if not found.
182
- *
184
+ *
183
185
  * @example
184
186
  * fetchAllSongs('drumeo', {
185
187
  * page: 2,
@@ -200,124 +202,7 @@ async function fetchAllSongs(brand, {
200
202
  includedFields = [],
201
203
  groupBy = ""
202
204
  }) {
203
- console.log('groupBy', groupBy)
204
- const start = (page - 1) * limit;
205
- const end = start + limit;
206
-
207
- // Construct the search filter
208
- const searchFilter = searchTerm
209
- ? `&& (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
210
- : "";
211
-
212
- // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
213
- const includedFieldsFilter = includedFields.length > 0
214
- ? includedFields.map(field => {
215
- let [key, value] = field.split(',');
216
- if (key === 'difficulty') {
217
- key = 'difficulty_string';
218
- }
219
- return `&& ${key} == "${value}"`;
220
- }).join(' ')
221
- : "";
222
-
223
- // Determine the sort order
224
- let sortOrder;
225
- switch (sort) {
226
- case "slug":
227
- sortOrder = "artist->name asc";
228
- break;
229
- case "published_on":
230
- sortOrder = "published_on desc";
231
- break;
232
- case "-published_on":
233
- sortOrder = "published_on asc";
234
- break;
235
- case "-slug":
236
- sortOrder = "artist->name desc";
237
- break;
238
- case "-popularity":
239
- sortOrder = "popularity desc";
240
- break;
241
- default:
242
- sortOrder = "published_on asc";
243
- break;
244
- }
245
-
246
- // Determine the group by clause
247
- let query = "";
248
- if (groupBy === "artist") {
249
- query = `
250
- {
251
- "total": count(*[_type == 'artist' && count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id) > 0]),
252
- "entity": *[_type == 'artist' && count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id) > 0]
253
- {
254
- 'id': _id,
255
- 'type': _type,
256
- name,
257
- 'head_shot_picture_url': thumbnail_url.asset->url,
258
- 'all_lessons_count': count(*[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]._id),
259
- 'lessons': *[_type == 'song' && brand == '${brand}' && ^._id == artist._ref ]{
260
- "id": railcontent_id,
261
- "type": _type,
262
- title,
263
- "thumbnail_url": thumbnail.asset->url,
264
- "artist_name": artist->name,
265
- difficulty_string,
266
- published_on,
267
- soundslice,
268
- instrumentless,
269
- }[0...10]
270
- }
271
- |order(${sortOrder})
272
- [${start}...${end}]
273
- }`;
274
- } else if (groupBy === "style") {
275
- query = `
276
- {
277
- "total": count(*[_type == 'genre' && count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id) > 0]),
278
- "entity":
279
- *[_type == 'genre' && count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id)>0]
280
- {
281
- 'id': _id,
282
- 'type': _type,
283
- name,
284
- 'head_shot_picture_url': thumbnail_url.asset->url,
285
- 'all_lessons_count': count(*[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]._id),
286
- 'lessons': *[_type == 'song' && brand == '${brand}' && ^._id in genre[]._ref ]{
287
- "id": railcontent_id,
288
- "type": _type,
289
- title,
290
- "thumbnail_url": thumbnail.asset->url,
291
- "artist_name": artist->name,
292
- difficulty_string,
293
- published_on,
294
- soundslice,
295
- instrumentless,
296
- }[0...10]
297
- }
298
- |order(${sortOrder})
299
- [${start}...${end}]
300
- }`;
301
- } else {
302
- query = `
303
- {
304
- "entity": *[_type == 'song' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}] | order(${sortOrder}) [${start}...${end}] {
305
- "id": railcontent_id,
306
- "type": _type,
307
- title,
308
- "thumbnail_url": thumbnail.asset->url,
309
- "artist_name": artist->name,
310
- difficulty_string,
311
- published_on,
312
- soundslice,
313
- instrumentless,
314
- },
315
- "total": count(*[_type == 'song' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}])
316
- }
317
- `;
318
- }
319
-
320
- return fetchSanity(query, true);
205
+ return fetchAll(brand, 'song', {page, limit, searchTerm, sort, includedFields, groupBy});
321
206
  }
322
207
 
323
208
  /**
@@ -581,7 +466,7 @@ async function fetchByRailContentIds(ids) {
581
466
  * @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
582
467
  * @param {string} [params.groupBy=""] - The field to group the results by (e.g., 'artist', 'genre').
583
468
  * @returns {Promise<Object|null>} - The fetched content data or null if not found.
584
- *
469
+ *
585
470
  * @example
586
471
  * fetchAll('drumeo', 'song', {
587
472
  * page: 2,
@@ -602,6 +487,9 @@ async function fetchAll(brand, type, {
602
487
  includedFields = [],
603
488
  groupBy = ""
604
489
  }) {
490
+ let config = contentTypeConfig[type] ?? {};
491
+ let additionalFields = config?.fields ?? [];
492
+ let isGroupByOneToOne = (groupBy ? config?.relationships[groupBy]?.isOneToOne : false) ?? false;
605
493
  const start = (page - 1) * limit;
606
494
  const end = start + limit;
607
495
 
@@ -644,10 +532,20 @@ async function fetchAll(brand, type, {
644
532
  break;
645
533
  }
646
534
 
535
+ let defaultFields = ['railcontent_id',
536
+ 'title',
537
+ '"image": thumbnail.asset->url',
538
+ 'difficulty',
539
+ 'difficulty_string',
540
+ 'web_url_path',
541
+ 'published_on'];
542
+
543
+ let fields = defaultFields.concat(additionalFields);
544
+ let fieldsString = fields.join(',');
545
+
647
546
  // Determine the group by clause
648
547
  let query = "";
649
- let manyReference = true; //TODO: define whether reference is one to one or one to many
650
- if (groupBy !== "" && !manyReference) {
548
+ if (groupBy !== "" && isGroupByOneToOne) {
651
549
  query = `
652
550
  {
653
551
  "total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id) > 0]),
@@ -659,20 +557,14 @@ async function fetchAll(brand, type, {
659
557
  'head_shot_picture_url': thumbnail_url.asset->url,
660
558
  'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id),
661
559
  'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]{
662
- railcontent_id,
663
- title,
664
- "image": thumbnail.asset->url,
665
- difficulty,
666
- difficulty_string,
667
- web_url_path,
668
- published_on,
669
- ${groupBy}
560
+ ${fieldsString},
561
+ ${groupBy}
670
562
  }[0...10]
671
563
  }
672
564
  |order(${sortOrder})
673
565
  [${start}...${end}]
674
566
  }`;
675
- } else if (groupBy !== "" && manyReference) {
567
+ } else if (groupBy !== "") {
676
568
  query = `
677
569
  {
678
570
  "total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref]._id)>0]),
@@ -684,14 +576,8 @@ async function fetchAll(brand, type, {
684
576
  'head_shot_picture_url': thumbnail_url.asset->url,
685
577
  'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]._id),
686
578
  'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]{
687
- railcontent_id,
688
- title,
689
- "image": thumbnail.asset->url,
690
- difficulty,
691
- difficulty_string,
692
- web_url_path,
693
- published_on,
694
- ${groupBy}
579
+ ${fieldsString},
580
+ ${groupBy}
695
581
  }[0...10]
696
582
  }
697
583
  |order(${sortOrder})
@@ -701,20 +587,14 @@ async function fetchAll(brand, type, {
701
587
  query = `
702
588
  {
703
589
  "entity": *[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}] | order(${sortOrder}) [${start}...${end}] {
704
- railcontent_id,
705
- title,
706
- "image": thumbnail.asset->url,
707
- difficulty,
708
- difficulty_string,
709
- web_url_path,
710
- published_on
590
+ ${fieldsString}
711
591
  },
712
592
  "total": count(*[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}])
713
593
  }
714
594
  `;
715
595
  }
716
596
 
717
- return fetchSanity(query, false);
597
+ return fetchSanity(query, true);
718
598
  }
719
599
 
720
600
  /**
@@ -739,14 +619,14 @@ async function fetchAll(brand, type, {
739
619
  * .catch(error => console.error(error));
740
620
  */
741
621
  async function fetchAllFilterOptions(
742
- brand,
743
- filters,
744
- style,
745
- artist,
746
- contentType,
747
- term
748
- ){
749
- const query = `
622
+ brand,
623
+ filters,
624
+ style,
625
+ artist,
626
+ contentType,
627
+ term
628
+ ) {
629
+ const query = `
750
630
  {
751
631
  "meta": {
752
632
  "totalResults": count(*[_type == '${contentType}' && brand == "${brand}" && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} ${filters}
@@ -772,7 +652,7 @@ async function fetchAllFilterOptions(
772
652
  }
773
653
  `;
774
654
 
775
- return fetchSanity(query, false);
655
+ return fetchSanity(query, false);
776
656
  }
777
657
 
778
658
  /**
@@ -852,7 +732,7 @@ async function fetchNextPreviousLesson(railcontentId) {
852
732
  * Fetch the page data for a specific lesson by Railcontent ID.
853
733
  * @param {string} railContentId - The Railcontent ID of the current lesson.
854
734
  * @returns {Promise<Object|null>} - The fetched page data or null if found.
855
- *
735
+ *
856
736
  * @example
857
737
  * fetchLessonContent('lesson123')
858
738
  * .then(data => console.log(data))
@@ -932,7 +812,7 @@ async function fetchPackAll(railcontentId) {
932
812
  * Fetch all children of a specific pack by Railcontent ID.
933
813
  * @param {string} railcontentId - The Railcontent ID of the pack.
934
814
  * @returns {Promise<Array<Object>|null>} - The fetched pack children data or null if not found.
935
- *
815
+ *
936
816
  * @example
937
817
  * fetchPackChildren('pack123')
938
818
  * .then(children => console.log(children))
@@ -956,38 +836,38 @@ async function fetchPackChildren(railcontentId) {
956
836
  * .catch(error => console.error(error));
957
837
  */
958
838
  async function fetchSanity(query, isList) {
959
- // Check the config object before proceeding
960
- if (!checkConfig(globalConfig)) {
961
- return null;
962
- }
839
+ // Check the config object before proceeding
840
+ if (!checkConfig(globalConfig)) {
841
+ return null;
842
+ }
963
843
 
964
- if (globalConfig.debug) {
965
- console.log("fetchSanity Query:", query);
966
- }
844
+ if (globalConfig.debug) {
845
+ console.log("fetchSanity Query:", query);
846
+ }
967
847
 
968
- const encodedQuery = encodeURIComponent(query);
969
- const api = globalConfig.useCachedAPI ? 'apicdn' : 'api'
970
- const url = `https://${globalConfig.projectId}.${api}.sanity.io/v${globalConfig.version}/data/query/${globalConfig.dataset}?query=${encodedQuery}`;
971
- const headers = {
972
- 'Authorization': `Bearer ${globalConfig.token}`,
973
- 'Content-Type': 'application/json'
974
- };
848
+ const encodedQuery = encodeURIComponent(query);
849
+ const api = globalConfig.useCachedAPI ? 'apicdn' : 'api'
850
+ const url = `https://${globalConfig.projectId}.${api}.sanity.io/v${globalConfig.version}/data/query/${globalConfig.dataset}?query=${encodedQuery}`;
851
+ const headers = {
852
+ 'Authorization': `Bearer ${globalConfig.token}`,
853
+ 'Content-Type': 'application/json'
854
+ };
975
855
 
976
- try {
977
- const response = await fetch(url, {headers});
978
- const result = await response.json();
979
- if (result.result) {
980
- if (globalConfig.debug) {
981
- console.log("fetchSanity Results:", result);
982
- }
983
- return isList ? result.result : result.result[0];
984
- } else {
985
- throw new Error('No results found');
986
- }
987
- } catch (error) {
988
- console.error('fetchSanity: Fetch error:', error);
989
- return null;
990
- }
856
+ try {
857
+ const response = await fetch(url, {headers});
858
+ const result = await response.json();
859
+ if (result.result) {
860
+ if (globalConfig.debug) {
861
+ console.log("fetchSanity Results:", result);
862
+ }
863
+ return isList ? result.result : result.result[0];
864
+ } else {
865
+ throw new Error('No results found');
866
+ }
867
+ } catch (error) {
868
+ console.error('fetchSanity: Fetch error:', error);
869
+ return null;
870
+ }
991
871
  }
992
872
 
993
873
 
@@ -79,6 +79,41 @@ describe('Sanity Queries', function () {
79
79
  expect(response.railcontent_id).toBe(id);
80
80
  });
81
81
 
82
+ test('fetchAllSongs', async () => {
83
+ const response = await fetchAllSongs('drumeo', {});
84
+ console.log(response);
85
+ expect(response.entity[0].soundslice).toBeDefined();
86
+ expect(response.entity[0].artist_name).toBeDefined();
87
+ expect(response.entity[0].instrumentless).toBeDefined();
88
+ });
89
+
90
+ test('fetchAllSongsGroupByArtist', async () => {
91
+ const response = await fetchAllSongs('drumeo', {groupBy:"artist"});
92
+ expect(response.entity[0].lessons[0].soundslice).toBeDefined();
93
+ expect(response.entity[0].lessons[0].artist_name).toBeDefined();
94
+ expect(response.entity[0].lessons[0].instrumentless).toBeDefined();
95
+ }, 100000);
96
+
97
+
98
+ test('fetchAllWorkouts', async () => {
99
+ const response = await fetchAll('drumeo', 'workout',{});
100
+ console.log(response);
101
+ expect(response.entity[0].railcontent_id).toBeDefined();
102
+ });
103
+
104
+ test('fetchAllChallenges', async () => {
105
+ const response = await fetchAll('drumeo', 'challenge',{});
106
+ console.log(response);
107
+ expect(response.entity[0].registration_url).toBeDefined();
108
+ expect(response.entity[0].enrollment_start_time).toBeDefined();
109
+ expect(response.entity[0].enrollment_end_time).toBeDefined();
110
+
111
+ expect(response.entity[0].lesson_count).toBeDefined();
112
+ expect(response.entity[0].primary_cta_text).toBeDefined();
113
+ expect(response.entity[0].challenge_state).toBeDefined();
114
+ expect(response.entity[0].challenge_state_text).toBeDefined();
115
+
116
+ });
82
117
  // test('fetchRelatedLessons', async () => {
83
118
  // const id = 380094;
84
119
  // const response = await fetchRelatedLessons(id, 'singeo', 'song');