musora-content-services 1.0.115 → 1.0.118

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.
Files changed (57) hide show
  1. package/.github/workflows/node.js.yml +0 -0
  2. package/CHANGELOG.md +6 -0
  3. package/README.md +0 -0
  4. package/babel.config.js +0 -0
  5. package/docs/config.js.html +0 -0
  6. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  7. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  8. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  9. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  10. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  11. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  13. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  14. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  15. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  16. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  17. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  18. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  19. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  23. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  24. package/docs/index.html +0 -0
  25. package/docs/module-Config.html +0 -0
  26. package/docs/module-Railcontent-Services.html +0 -0
  27. package/docs/module-Sanity-Services.html +0 -0
  28. package/docs/railcontent.js.html +0 -0
  29. package/docs/sanity.js.html +0 -0
  30. package/docs/scripts/collapse.js +0 -0
  31. package/docs/scripts/commonNav.js +0 -0
  32. package/docs/scripts/linenumber.js +0 -0
  33. package/docs/scripts/nav.js +0 -0
  34. package/docs/scripts/polyfill.js +0 -0
  35. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  36. package/docs/scripts/prettify/lang-css.js +0 -0
  37. package/docs/scripts/prettify/prettify.js +0 -0
  38. package/docs/scripts/search.js +0 -0
  39. package/docs/styles/jsdoc.css +0 -0
  40. package/docs/styles/prettify.css +0 -0
  41. package/jest.config.js +0 -0
  42. package/jsdoc.json +0 -0
  43. package/package.json +2 -1
  44. package/src/contentMetaData.js +1091 -0
  45. package/src/contentTypeConfig.js +45 -1414
  46. package/src/filterBuilder.js +0 -0
  47. package/src/index.d.ts +137 -88
  48. package/src/index.js +135 -97
  49. package/src/services/config.js +1 -0
  50. package/src/services/railcontent.js +24 -12
  51. package/src/services/sanity.js +178 -77
  52. package/src/services/userContext.js +0 -0
  53. package/test/localStorageMock.js +0 -0
  54. package/test/log.js +0 -0
  55. package/test/sanityQueryService.test.js +154 -2
  56. package/test/userContext.test.js +0 -0
  57. package/tools/generate-index.js +85 -0
@@ -11,13 +11,17 @@ import {
11
11
  getFieldsForContentType,
12
12
  filtersToGroq,
13
13
  getUpcomingEventsTypes,
14
- getNewReleasesTypes,
15
14
  showsTypes,
16
- contentMetadata
15
+ getNewReleasesTypes,
17
16
  } from "../contentTypeConfig";
17
+
18
+ import {
19
+ processMetadata,
20
+ } from "../contentMetaData";
21
+
18
22
  import {globalConfig} from "./config";
19
23
 
20
- import { fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent.js';
24
+ import { fetchUserPermissions, fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent.js';
21
25
  import {arrayToStringRepresentation, FilterBuilder} from "../filterBuilder";
22
26
 
23
27
  /**
@@ -495,58 +499,51 @@ export async function fetchAll(brand, type, {
495
499
 
496
500
  // Determine the group by clause
497
501
  let query = "";
502
+ let entityFieldsString = "";
503
+ let filter = "";
498
504
  if (groupBy !== "" && isGroupByOneToOne) {
499
- let webUrlPath = 'artists';
500
- query = `
501
- {
502
- "total": count(*[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]),
503
- "entity": *[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]
504
- {
505
+ const webUrlPath = 'artists';
506
+ const lessonsFilter = `_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ${searchFilter} ${includedFieldsFilter} ${progressFilter}`;
507
+ entityFieldsString = `
505
508
  'id': _id,
506
509
  'type': _type,
507
510
  name,
508
511
  'head_shot_picture_url': thumbnail_url.asset->url,
509
512
  'web_url_path': '/${brand}/${webUrlPath}/'+name+'?included_fieds[]=type,${type}',
510
- 'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id),
511
- 'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ${searchFilter} ${includedFieldsFilter} ${progressFilter}]{
513
+ 'all_lessons_count': count(*[${lessonsFilter}]._id),
514
+ 'lessons': *[${lessonsFilter}]{
512
515
  ${fieldsString},
513
516
  ${groupBy}
514
517
  }[0...20]
515
- }
516
- |order(${sortOrder})
517
- [${start}...${end}]
518
- }`;
518
+ `;
519
+ filter = `_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0`;
519
520
  } else if (groupBy !== "") {
520
- let webUrlPath = (groupBy == 'genre')?'/genres':'';
521
- query = `
522
- {
523
- "total": count(*[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]),
524
- "entity": *[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]
525
- {
521
+ const webUrlPath = (groupBy == 'genre')?'/genres':'';
522
+ const lessonsFilter = `brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}`;
523
+ entityFieldsString = `
526
524
  'id': _id,
527
525
  'type': _type,
528
526
  name,
529
527
  'head_shot_picture_url': thumbnail_url.asset->url,
530
528
  'web_url_path': select(defined(web_url_path)=> web_url_path +'?included_fieds[]=type,${type}',!defined(web_url_path)=> '/${brand}${webUrlPath}/'+name+'/${webUrlPathType}'),
531
- 'all_lessons_count': count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id),
532
- 'lessons': *[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]{
529
+ 'all_lessons_count': count(*[${lessonsFilter}]._id),
530
+ 'lessons': *[${lessonsFilter}]{
533
531
  ${fieldsString},
534
532
  ${groupBy}
535
- }[0...20]
536
- }
537
- |order(${sortOrder})
538
- [${start}...${end}]
539
- }`;
533
+ }[0...20]`;
534
+ filter = `_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0`;
540
535
  } else {
541
- query = `
542
- {
543
- "entity": *[brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}] | order(${sortOrder}) [${start}...${end}] {
544
- ${fieldsString},
545
- },
546
- "total": count(*[brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}])
547
- }
548
- `;
536
+ filter = `brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}`
537
+ entityFieldsString = fieldsString;
549
538
  }
539
+ query = buildEntityAndTotalQuery(
540
+ filter,
541
+ entityFieldsString,
542
+ {
543
+ sortOrder: sortOrder,
544
+ start: start,
545
+ end: end,
546
+ });
550
547
 
551
548
  return fetchSanity(query, true);
552
549
  }
@@ -597,40 +594,39 @@ export function getSortOrder(sort= '-published_on', groupBy)
597
594
  */
598
595
  export async function fetchAllFilterOptions(
599
596
  brand,
600
- filters,
597
+ filters = [],
601
598
  style,
602
599
  artist,
603
600
  contentType,
604
601
  term,
605
602
  progressIds = undefined
606
603
  ) {
604
+ filters = Array.isArray(filters) ? filters : [];
607
605
  const includedFieldsFilter = filters?.length > 0 ? filtersToGroq(filters) : undefined;
608
606
 
609
607
  const progressFilter = progressIds !== undefined ?
610
608
  `&& railcontent_id in [${progressIds.join(',')}]` : "";
611
609
 
612
610
  const commonFilter = `_type == '${contentType}' && brand == "${brand}"${style ? ` && '${style}' in genre[]->name` : ''}${artist ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${includedFieldsFilter ? includedFieldsFilter : ''}`;
611
+ const metaData = processMetadata(brand, contentType, true);
612
+ const allowableFilters = metaData?.allowableFilters || [];
613
+
614
+ const dynamicFilterOptions = allowableFilters.map(filter => {
615
+ // Create a modified common filter for each allowable filter
616
+ let includedFieldsFilterWithoutSelectedOption = filters?.length > 0 ? filtersToGroq(filters, filter) : undefined;
617
+ const commonFilterWithoutSelectedOption = `_type == '${contentType}' && brand == "${brand}"${(style && filter !== "style") ? ` && '${style}' in genre[]->name` : ''}${(artist && filter !== "artist") ? ` && artist->name == '${artist}'` : ''} ${includedFieldsFilterWithoutSelectedOption ? includedFieldsFilterWithoutSelectedOption : ''}`;
618
+
619
+ // Call getFilterOptions with the modified common filter
620
+ return getFilterOptions(filter, commonFilterWithoutSelectedOption, contentType);
621
+ }).join(' ');
622
+
613
623
  const query = `
614
624
  {
615
625
  "meta": {
616
626
  "totalResults": count(*[${commonFilter}
617
627
  ${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
618
628
  "filterOptions": {
619
- "difficulty": [
620
- {"type": "Introductory", "count": count(*[${commonFilter} && difficulty_string == "Introductory"])},
621
- {"type": "Beginner", "count": count(*[${commonFilter} && difficulty_string == "Beginner"])},
622
- {"type": "Intermediate", "count": count(*[${commonFilter} && difficulty_string == "Intermediate" ])},
623
- {"type": "Advanced", "count": count(*[${commonFilter} && difficulty_string == "Advanced" ])},
624
- {"type": "Expert", "count": count(*[${commonFilter} && difficulty_string == "Expert" ])}
625
- ][count > 0],
626
- "instrumentless": [
627
- {"type": "Full Song Only", "count": count(*[${commonFilter} && instrumentless == false ])},
628
- {"type": "Instrument Removed", "count": count(*[${commonFilter} && instrumentless == true ])}
629
- ][count > 0],
630
- "genre": *[_type == 'genre' && '${contentType}' in filter_types] {
631
- "type": name,
632
- "count": count(*[${commonFilter} && references(^._id)])
633
- }[count > 0]
629
+ ${dynamicFilterOptions}
634
630
  }
635
631
  }
636
632
  }`;
@@ -971,10 +967,11 @@ export async function fetchAllPacks(brand, sort = "-published_on", searchTerm =
971
967
  const sortOrder = getSortOrder(sort);
972
968
  const filter = `_type == 'pack' && brand == '${brand}' && title match "${searchTerm}*"`
973
969
  const filterParams = {};
970
+ const fields = getFieldsForContentType('pack');
974
971
  const query = buildQuery(
975
972
  filter,
976
973
  filterParams,
977
- fields,
974
+ getFieldsForContentType('pack'),
978
975
  {
979
976
  logo_image_url: 'logo_image_url.asset->url',
980
977
  sortOrder: sortOrder,
@@ -1249,13 +1246,13 @@ export async function fetchGenreLessons(brand, name, contentType, {
1249
1246
  }
1250
1247
 
1251
1248
 
1252
-
1253
1249
  /**
1254
- * Fetch data from the Sanity API based on a provided query.
1255
1250
  *
1256
1251
  * @param {string} query - The GROQ query to execute against the Sanity API.
1257
1252
  * @param {boolean} isList - Whether to return an array or a single result.
1258
- * @returns {Promise<Object|null>} - A promise that resolves to the fetched data or null if an error occurs or no results are found.
1253
+ * @param {Function} [customPostProcess=null] - custom post process callback
1254
+ * @param {boolean} [processNeedAccess=true] - execute the needs_access callback
1255
+ * @returns {Promise<*|null>} - A promise that resolves to the fetched data or null if an error occurs or no results are found.
1259
1256
  *
1260
1257
  * @example
1261
1258
  * const query = `*[_type == "song"]{title, artist->name}`;
@@ -1263,7 +1260,13 @@ export async function fetchGenreLessons(brand, name, contentType, {
1263
1260
  * .then(data => console.log(data))
1264
1261
  * .catch(error => console.error(error));
1265
1262
  */
1266
- export async function fetchSanity(query, isList) {
1263
+
1264
+ export async function fetchSanity(query,
1265
+ isList,
1266
+ { customPostProcess = null,
1267
+ processNeedAccess = true,} = {}
1268
+ ) {
1269
+
1267
1270
  // Check the config object before proceeding
1268
1271
  if (!checkSanityConfig(globalConfig)) {
1269
1272
  return null;
@@ -1291,7 +1294,9 @@ export async function fetchSanity(query, isList) {
1291
1294
  if (globalConfig.sanityConfig.debug) {
1292
1295
  console.log("fetchSanity Results:", result);
1293
1296
  }
1294
- return isList ? result.result : result.result[0];
1297
+ let results = isList ? result.result : result.result[0];
1298
+ results = processNeedAccess ? await needsAccessDecorator(results) : results;
1299
+ return customPostProcess ? customPostProcess(results) : results;
1295
1300
  } else {
1296
1301
  throw new Error('No results found');
1297
1302
  }
@@ -1301,6 +1306,41 @@ export async function fetchSanity(query, isList) {
1301
1306
  }
1302
1307
  }
1303
1308
 
1309
+ async function needsAccessDecorator(results)
1310
+ {
1311
+ if (globalConfig.sanityConfig.useDummyRailContentMethods) return results;
1312
+ let userPermissions = await getUserPermissions();
1313
+ userPermissions = new Set(userPermissions);
1314
+ if (Array.isArray(results)) {
1315
+ results.forEach((result) => {
1316
+ result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
1317
+ });
1318
+ } else {
1319
+ results['need_access'] = doesUserNeedAccessToContent(results, userPermissions);
1320
+ }
1321
+ return results;
1322
+ }
1323
+
1324
+ function doesUserNeedAccessToContent(result, userPermissions)
1325
+ {
1326
+ const permissions = new Set(result.permission_id ?? []);
1327
+ if (permissions.length === 0) {
1328
+ return false;
1329
+ }
1330
+ for (let permission of permissions) {
1331
+ if (userPermissions.has(permission)) {
1332
+ return false;
1333
+ }
1334
+ }
1335
+ return true;
1336
+ }
1337
+
1338
+ async function getUserPermissions()
1339
+ {
1340
+ return await fetchUserPermissions();
1341
+ }
1342
+
1343
+
1304
1344
  /**
1305
1345
  * Fetch CatalogueMetadata from Sanity. This information may be duplicated in the contentTypeConfig.js.
1306
1346
  * It's an ongoing discussion (Aug 2024), but it's been included here if necessary
@@ -1352,7 +1392,7 @@ export async function fetchShowsData(brand) {
1352
1392
  }
1353
1393
 
1354
1394
  /**
1355
- * Fetch metadata from the contentTypeConfig.js based on brand and type.
1395
+ * Fetch metadata from the contentMetaData.js based on brand and type.
1356
1396
  *
1357
1397
  * @param {string} brand - The brand for which to fetch metadata.
1358
1398
  * @param {string} type - The type for which to fetch metadata.
@@ -1463,27 +1503,88 @@ function buildEntityAndTotalQuery(
1463
1503
  }`;
1464
1504
  return query;
1465
1505
  }
1466
- function processMetadata(brand, type, withFilters = false) {
1467
- const metadataElement = contentMetadata[brand]?.[type];
1468
- if (!metadataElement) {
1469
- return null;
1506
+
1507
+
1508
+ function getFilterOptions(option, commonFilter,contentType){
1509
+ let filterGroq = '';
1510
+ switch (option) {
1511
+ case "difficulty":
1512
+ filterGroq = `
1513
+ "difficulty": [
1514
+ {"type": "Introductory", "count": count(*[${commonFilter} && difficulty_string == "Introductory"])},
1515
+ {"type": "Beginner", "count": count(*[${commonFilter} && difficulty_string == "Beginner"])},
1516
+ {"type": "Intermediate", "count": count(*[${commonFilter} && difficulty_string == "Intermediate" ])},
1517
+ {"type": "Advanced", "count": count(*[${commonFilter} && difficulty_string == "Advanced" ])},
1518
+ {"type": "Expert", "count": count(*[${commonFilter} && difficulty_string == "Expert" ])}
1519
+ ][count > 0],`;
1520
+ break;
1521
+ case "genre":
1522
+ case "essential":
1523
+ case "focus":
1524
+ case "theory":
1525
+ case "topic":
1526
+ case "lifestyle":
1527
+ case "creativity":
1528
+ filterGroq = `
1529
+ "${option}": *[_type == '${option}' && '${contentType}' in filter_types] {
1530
+ "type": name,
1531
+ "count": count(*[${commonFilter} && references(^._id)])
1532
+ }[count > 0],`;
1533
+ break;
1534
+ case "instrumentless":
1535
+ filterGroq = `
1536
+ "${option}": [
1537
+ {"type": "Full Song Only", "count": count(*[${commonFilter} && instrumentless == false ])},
1538
+ {"type": "Instrument Removed", "count": count(*[${commonFilter} && instrumentless == true ])}
1539
+ ][count > 0],`;
1540
+ break;
1541
+ case "gear":
1542
+ filterGroq = `
1543
+ "${option}": [
1544
+ {"type": "Practice Pad", "count": count(*[${commonFilter} && gear match 'Practice Pad' ])},
1545
+ {"type": "Drum-Set", "count": count(*[${commonFilter} && gear match 'Drum-Set'])}
1546
+ ][count > 0],`;
1547
+ break;
1548
+ case "bpm":
1549
+ filterGroq = `
1550
+ "${option}": [
1551
+ {"type": "50-90", "count": count(*[${commonFilter} && bpm > 50 && bpm < 91])},
1552
+ {"type": "91-120", "count": count(*[${commonFilter} && bpm > 90 && bpm < 121])},
1553
+ {"type": "121-150", "count": count(*[${commonFilter} && bpm > 120 && bpm < 151])},
1554
+ {"type": "151-180", "count": count(*[${commonFilter} && bpm > 150 && bpm < 181])},
1555
+ {"type": "180+", "count": count(*[${commonFilter} && bpm > 180])},
1556
+ ][count > 0],`;
1557
+ break;
1558
+ default:
1559
+ filterGroq = "";
1560
+ break;
1470
1561
  }
1471
- const processedData = {
1472
- type,
1473
- thumbnailUrl: metadataElement.thumbnailUrl || null,
1474
- name: metadataElement.name || null,
1475
- description: metadataElement.description || null
1476
- };
1477
-
1478
- if (withFilters) {
1479
- Object.keys(metadataElement).forEach(key => {
1480
- if ( !['thumbnailUrl', 'name', 'description'].includes(key) ) {
1481
- processedData[key] = metadataElement[key];
1482
- }
1483
- });
1562
+
1563
+ return filterGroq;
1564
+ }
1565
+
1566
+ function cleanUpGroq(query) {
1567
+ // Split the query into clauses based on the logical operators
1568
+ const clauses = query.split(/(\s*&&|\s*\|\|)/).map(clause => clause.trim());
1569
+
1570
+ // Filter out empty clauses
1571
+ const filteredClauses = clauses.filter(clause => clause.length > 0);
1572
+
1573
+ // Check if there are valid conditions in the clauses
1574
+ const hasConditions = filteredClauses.some(clause => !clause.match(/^\s*&&\s*|\s*\|\|\s*$/));
1575
+
1576
+ if (!hasConditions) {
1577
+ // If no valid conditions, return an empty string or the original query
1578
+ return '';
1484
1579
  }
1485
1580
 
1486
- return processedData;
1581
+ // Remove occurrences of '&& ()'
1582
+ const cleanedQuery = filteredClauses.join(' ')
1583
+ .replace(/&&\s*\(\)/g, '')
1584
+ .replace(/(\s*&&|\s*\|\|)(?=\s*[\s()]*$|(?=\s*&&|\s*\|\|))/g, '')
1585
+ .trim();
1586
+
1587
+ return cleanedQuery;
1487
1588
  }
1488
1589
 
1489
1590
 
File without changes
File without changes
package/test/log.js CHANGED
File without changes
@@ -1,4 +1,6 @@
1
1
  import {initializeService} from '../src/services/config.js';
2
+ import {getFieldsForContentType} from "../src/contentTypeConfig";
3
+ import {fetchSanity} from "../src/services/sanity";
2
4
  import {log} from './log.js';
3
5
 
4
6
  const {
@@ -14,6 +16,7 @@ const {
14
16
  fetchByRailContentId,
15
17
  fetchByRailContentIds,
16
18
  fetchAll,
19
+ fetchAllOld,
17
20
  fetchAllFilterOptions,
18
21
  fetchFoundation,
19
22
  fetchMethods,
@@ -39,6 +42,10 @@ const {
39
42
  FilterBuilder,
40
43
  } = require('../src/filterBuilder.js');
41
44
 
45
+ const {
46
+ processMetadata,
47
+ } = require('../src/contentMetaData.js');
48
+
42
49
  describe('Sanity Queries', function () {
43
50
  beforeEach(() => {
44
51
  const config = {
@@ -48,7 +55,8 @@ describe('Sanity Queries', function () {
48
55
  dataset: process.env.SANITY_DATASET,
49
56
  useCachedAPI: process.env.SANITY_USE_CACHED_API === 'true' || true,
50
57
  version: '2021-06-07',
51
- debug: process.env.DEBUG === 'true' || false
58
+ debug: process.env.DEBUG === 'true' || false,
59
+ useDummyRailContentMethods: true,
52
60
  }
53
61
  };
54
62
  initializeService(config);
@@ -61,6 +69,7 @@ describe('Sanity Queries', function () {
61
69
 
62
70
  });
63
71
 
72
+
64
73
  test('fetchArtists', async () => {
65
74
  const response = await fetchArtists('drumeo');
66
75
  const artistNames = response.map((x) => x.name);
@@ -72,9 +81,29 @@ describe('Sanity Queries', function () {
72
81
  const response = await fetchSongArtistCount('drumeo');
73
82
  log(response);
74
83
  expect(response).toBeGreaterThan(1000);
84
+ }, 10000);
85
+
86
+ test('fetchSanity-WithPostProcess', async () => {
87
+ const id = 380094;
88
+ const query = `*[railcontent_id == ${id}]{
89
+ ${getFieldsForContentType('song')}
90
+ }`
91
+ const newSlug = 'keysmash1';
92
+ const newField = 1
93
+ const postProcess = (result) => {
94
+ result['new_field'] = newField;
95
+ result['slug'] = newSlug;
96
+ return result;
97
+ };
98
+ const response = await fetchSanity(query, false, {customPostProcess: postProcess});
99
+ log(response);
100
+ expect(response.id).toBe(id);
101
+ expect(response.new_field).toBe(newField);
102
+ expect(response.slug).toBe(newSlug);
75
103
  });
76
104
 
77
- test('fetchByRailContentId', async () => {
105
+
106
+ test('fetchSanityPostProcess', async () => {
78
107
  const id = 380094;
79
108
  const response = await fetchByRailContentId(id, "song");
80
109
  expect(response.id).toBe(id);
@@ -85,6 +114,7 @@ describe('Sanity Queries', function () {
85
114
  const response = await fetchChallengeOverview(id);
86
115
  expect(response.lessons).toBeDefined();
87
116
  expect(response.id).toBe(id);
117
+
88
118
  });
89
119
 
90
120
  test('fetchByRailContentIds', async () => {
@@ -327,6 +357,37 @@ describe('Sanity Queries', function () {
327
357
 
328
358
  test('fetchAll-IncludedFields', async () => {
329
359
  let response = await fetchAll('drumeo', 'instructor',{includedFields: ['is_active']});
360
+ console.log(response);
361
+ expect(response.entity.length).toBeGreaterThan(0);
362
+ });
363
+
364
+ test('fetchAll-IncludedFields-multiple', async () => {
365
+ let response = await fetchAll('drumeo', 'course',{includedFields: ['essential,Dynamics','essential,Timing','difficulty,Beginner']});
366
+ log(response);
367
+ expect(response.entity.length).toBeGreaterThan(0);
368
+ });
369
+
370
+ test('fetchAll-IncludedFields-playalong-multiple', async () => {
371
+ let response = await fetchAll('drumeo', 'play-along',{includedFields: ['bpm,91-120','bpm,181+','genre,Blues']});
372
+ log(response);
373
+ expect(response.entity.length).toBeGreaterThan(0);
374
+ });
375
+
376
+ test('fetchAll-IncludedFields-rudiment-multiple-gear', async () => {
377
+ let response = await fetchAll('drumeo', 'rudiment',{includedFields: ['gear,Drum-Set','gear,Practice Pad']});
378
+ log(response);
379
+ expect(response.entity.length).toBeGreaterThan(0);
380
+ });
381
+
382
+ test('fetchAll-IncludedFields-coaches-multiple-focus', async () => {
383
+ let response = await fetchAll('drumeo', 'instructor',{includedFields: ['focus,drumline','focus,recording']});
384
+ log(response);
385
+ expect(response.entity.length).toBeGreaterThan(0);
386
+ });
387
+
388
+ test('fetchAll-IncludedFields-songs-multiple-instrumentless', async () => {
389
+ let response = await fetchAll('drumeo', 'song',{includedFields: ['instrumentless,true','instrumentless,false']});
390
+ log(response);
330
391
  expect(response.entity.length).toBeGreaterThan(0);
331
392
  });
332
393
 
@@ -517,4 +578,95 @@ describe('Filter Builder', function () {
517
578
  return clauses;
518
579
  }
519
580
 
581
+ test('fetchAllFilterOptions', async () => {
582
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'song', '');
583
+ log(response);
584
+ expect(response.meta.filterOptions.difficulty).toBeDefined();
585
+ expect(response.meta.filterOptions.genre).toBeDefined();
586
+ expect(response.meta.filterOptions.lifestyle).toBeDefined();
587
+ expect(response.meta.filterOptions.instrumentless).toBeDefined();
588
+ });
589
+
590
+ test('fetchAllFilterOptions-Rudiment', async () => {
591
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'rudiment', '');
592
+ log(response);
593
+ expect(response.meta.filterOptions.gear).toBeDefined();
594
+ expect(response.meta.filterOptions.genre).toBeDefined();
595
+ expect(response.meta.filterOptions.topic).toBeDefined();
596
+ });
597
+ test('fetchAllFilterOptions-PlayAlong', async () => {
598
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'play-along', '');
599
+ log(response);
600
+ expect(response.meta.filterOptions.difficulty).toBeDefined();
601
+ expect(response.meta.filterOptions.genre).toBeDefined();
602
+ expect(response.meta.filterOptions.bpm).toBeDefined();
603
+ });
604
+
605
+ test('fetchAllFilterOptions-Coaches', async () => {
606
+ let response = await fetchAllFilterOptions('drumeo', [], '', '', 'instructor', '');
607
+ log(response);
608
+ expect(response.meta.filterOptions.focus).toBeDefined();
609
+ expect(response.meta.filterOptions.focus.length).toBeGreaterThan(0);
610
+ expect(response.meta.filterOptions.genre).toBeDefined();
611
+ expect(response.meta.filterOptions.genre.length).toBeGreaterThan(0);
612
+ });
613
+
614
+ test('fetchAllFilterOptions-filter-selected', async () => {
615
+ let response = await fetchAllFilterOptions('drumeo', ['theory,notation','theory,time signatures','creativity,Grooves','creativity,Fills & Chops','difficulty,Beginner','difficulty,Intermediate','difficulty,Expert'], '', '', 'course', '');
616
+ log(response);
617
+ expect(response.meta.filterOptions).toBeDefined();
618
+ });
619
+ });
620
+
621
+ describe('MetaData', function () {
622
+
623
+ test('customBrandTypeExists', async () => {
624
+ const metaData = processMetadata('guitareo', 'recording');
625
+ expect(metaData.type).toBe('recording');
626
+ expect(metaData.name).toBe('Archives');
627
+ expect(metaData.description).toBeDefined();
628
+ });
629
+
630
+ test('invalidContentType', async () => {
631
+ const metaData = processMetadata('guitareo', 'not a real type');
632
+ expect(metaData).toBeNull();
633
+ });
634
+
635
+ test('onlyCommon', async () => {
636
+ const guitareoMetaData = processMetadata('guitareo', 'challenge');
637
+ const drumeoMetaData = processMetadata('drumeo', 'challenge');
638
+ expect(guitareoMetaData).toStrictEqual(drumeoMetaData);
639
+ expect(guitareoMetaData.type).toBe('challenge');
640
+ expect(guitareoMetaData.name).toBe('Challenges');
641
+ });
642
+
643
+ test('withCommon', async () => {
644
+ const guitareoMetaData = processMetadata('guitareo', 'instructor');
645
+ const drumeoMetaData = processMetadata('drumeo', 'instructor');
646
+ expect(guitareoMetaData.description).not.toBe(drumeoMetaData.description);
647
+ guitareoMetaData.description = ''
648
+ drumeoMetaData.description = ''
649
+ expect(guitareoMetaData).toStrictEqual(drumeoMetaData);
650
+ });
651
+
652
+ test('withWithoutFilters', async () => {
653
+ let metaData = processMetadata('singeo', 'student-review', true);
654
+ expect(metaData.type).toBeDefined()
655
+ expect(metaData.name).toBeDefined()
656
+ expect(metaData.description).toBeDefined();
657
+ expect(metaData.thumbnailUrl).toBeDefined();
658
+ expect(metaData.tabs).toBeDefined();
659
+ metaData = processMetadata('singeo', 'student-review', false);
660
+ expect(metaData.type).toBeDefined()
661
+ expect(metaData.name).toBeDefined()
662
+ expect(metaData.description).toBeDefined();
663
+ expect(metaData.tabs).not.toBeDefined();
664
+ });
665
+
666
+ test('nulled', async () => {
667
+ let metaData = processMetadata('drumeo', 'student-review');
668
+ expect(metaData).toBeNull();
669
+ metaData = processMetadata('singeo', 'student-review');
670
+ expect(metaData).not.toBeNull();
671
+ });
520
672
  });
File without changes