musora-content-services 1.0.105 → 1.0.107
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 +4 -0
- package/package.json +1 -1
- package/src/contentTypeConfig.js +1 -1
- package/src/filterBuilder.js +122 -0
- package/src/services/sanity.js +199 -84
- package/test/sanityQueryService.test.js +207 -17
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [1.0.107](https://github.com/railroadmedia/musora-content-services/compare/v1.0.106...v1.0.107) (2024-09-19)
|
|
6
|
+
|
|
7
|
+
### [1.0.106](https://github.com/railroadmedia/musora-content-services/compare/v1.0.105...v1.0.106) (2024-09-19)
|
|
8
|
+
|
|
5
9
|
### [1.0.105](https://github.com/railroadmedia/musora-content-services/compare/v1.0.104...v1.0.105) (2024-09-19)
|
|
6
10
|
|
|
7
11
|
### [1.0.104](https://github.com/railroadmedia/musora-content-services/compare/v1.0.103...v1.0.104) (2024-09-18)
|
package/package.json
CHANGED
package/src/contentTypeConfig.js
CHANGED
|
@@ -289,7 +289,7 @@ function getFieldsForContentType(contentType, asQueryString=true) {
|
|
|
289
289
|
function filtersToGroq(filters) {
|
|
290
290
|
const groq = filters.map(field => {
|
|
291
291
|
let [key, value] = field.split(',');
|
|
292
|
-
if(key && value){
|
|
292
|
+
if(key && value && field.split(',').length === 2){
|
|
293
293
|
switch (key) {
|
|
294
294
|
case 'difficulty':
|
|
295
295
|
return `&& difficulty_string == "${value}"`;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export class FilterBuilder {
|
|
4
|
+
|
|
5
|
+
STATUS_SCHEDULED = 'scheduled';
|
|
6
|
+
|
|
7
|
+
constructor(
|
|
8
|
+
filter = '',
|
|
9
|
+
{
|
|
10
|
+
user = undefined,
|
|
11
|
+
availableContentStatuses = [],
|
|
12
|
+
bypassPermissions = false,
|
|
13
|
+
pullFutureContent = false,
|
|
14
|
+
getFutureContentOnly = false,
|
|
15
|
+
getFutureScheduledContentsOnly = false,
|
|
16
|
+
|
|
17
|
+
}={}) {
|
|
18
|
+
this.user = user;
|
|
19
|
+
this.availableContentStatuses = availableContentStatuses;
|
|
20
|
+
this.bypassPermissions = bypassPermissions;
|
|
21
|
+
this.pullFutureContent = pullFutureContent;
|
|
22
|
+
this.getFutureContentOnly = getFutureContentOnly;
|
|
23
|
+
this.getFutureScheduledContentsOnly = getFutureScheduledContentsOnly;
|
|
24
|
+
this.filter = filter;
|
|
25
|
+
this.debug = process.env.DEBUG === 'true' || false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
static withOnlyFilterAvailableStatuses(filter, availableContentStatuses) {
|
|
30
|
+
return new FilterBuilder(filter,{
|
|
31
|
+
availableContentStatuses,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
buildFilter() {
|
|
36
|
+
if (this.debug) console.log('baseFilter', this.filter);
|
|
37
|
+
const filter = this
|
|
38
|
+
._applyContentStatuses()
|
|
39
|
+
._applyPermissions()
|
|
40
|
+
._applyPublishingDateRestrictions()
|
|
41
|
+
._trimAmpersands() // just in case
|
|
42
|
+
.filter;
|
|
43
|
+
if (this.debug) console.log('finalFilter', filter);
|
|
44
|
+
return filter;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_applyContentStatuses() {
|
|
48
|
+
// This must be run before _applyPublishDateRestrictions()
|
|
49
|
+
if (this.availableContentStatuses.length === 0) return this;
|
|
50
|
+
// I'm not sure if I'm 100% on this logic, but this is my intepretation of the ContentRepository logic
|
|
51
|
+
if (this.getFutureScheduledContentsOnly && this.availableContentStatuses.includes(this.STATUS_SCHEDULED)) {
|
|
52
|
+
// we must pull in future content here, otherwise we'll restrict on content this is published in the past and remove any scheduled content
|
|
53
|
+
this.pullFutureContent = true;
|
|
54
|
+
const now = new Date().toISOString();
|
|
55
|
+
let statuses = [...this.availableContentStatuses];
|
|
56
|
+
statuses.splice(statuses.indexOf(this.STATUS_SCHEDULED));
|
|
57
|
+
this._andWhere(`(status in ${arrayToStringRepresentation(statuses)} || (status == '${this.STATUS_SCHEDULED}' && published_on >= '${now}'))`)
|
|
58
|
+
|
|
59
|
+
} else {
|
|
60
|
+
this._andWhere(`status in ${arrayToStringRepresentation(this.availableContentStatuses)}`);
|
|
61
|
+
}
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
_applyPermissions() {
|
|
66
|
+
if (this.bypassPermissions) return this;
|
|
67
|
+
// TODO these need to be pulled from the user and reference either ID, or railcontent_id
|
|
68
|
+
const requiredPermissions = this._getUserPermissions();
|
|
69
|
+
if (requiredPermissions.length === 0) return this;
|
|
70
|
+
// handle pullSongsContent, I think the flagging on this needs to be backwards compared to BE
|
|
71
|
+
// if using id, switch railcontent_id to _id in the below query
|
|
72
|
+
this._andWhere(`references(*[_type == 'permission' && railcontent_id in ${arrayToRawRepresentation(requiredPermissions)}]._id)`);
|
|
73
|
+
return this;
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
_getUserPermissions() {
|
|
78
|
+
// TODO need user store up and running to complete this, until then just null check
|
|
79
|
+
return this?.user?.permissions ?? [];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_applyPublishingDateRestrictions() {
|
|
83
|
+
const now = new Date().toISOString();
|
|
84
|
+
if (this.getFutureContentOnly) {
|
|
85
|
+
this._andWhere(`published_on >= '${now}'`);
|
|
86
|
+
} else if (!this.pullFutureContent) {
|
|
87
|
+
this._andWhere(`published_on <= '${now}'`);
|
|
88
|
+
} else {
|
|
89
|
+
const date = new Date();
|
|
90
|
+
const theFuture = new Date(date.setMonth(date.getMonth() + 18));
|
|
91
|
+
this._andWhere(`published_on <= '${theFuture}'`);
|
|
92
|
+
}
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_andWhere(query) {
|
|
97
|
+
const leadingAmpersand = this.filter ? ' && ' : '';
|
|
98
|
+
this.filter += leadingAmpersand + query;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
_orWhere(query) {
|
|
102
|
+
if (!this.filter) throw new Error("invalid query, _orWhere needs to be called on an existing query");
|
|
103
|
+
this.filter += ` || (${query})`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
_trimAmpersands() {
|
|
107
|
+
this.filter = this.filter.trim();
|
|
108
|
+
while( this.filter.charAt(0) === '&' || this.filter.charAt(0) === ' ' ) this.filter = this.filter.substring(1);
|
|
109
|
+
while( this.filter.charAt(this.filter.length) === '&' || this.filter.charAt(this.filter.length) === ' ' ) this.filter = this.filter.slice(-1);
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function arrayToStringRepresentation(arr) {
|
|
117
|
+
return '[' + arr.map(item => `'${item}'`).join(',') + ']';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function arrayToRawRepresentation(arr) {
|
|
121
|
+
return '[' + arr.map(item => `${item}`).join(',') + ']';
|
|
122
|
+
}
|
package/src/services/sanity.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
import {globalConfig} from "./config";
|
|
17
17
|
|
|
18
18
|
import { fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent.js';
|
|
19
|
+
import {arrayToStringRepresentation, FilterBuilder} from "../filterBuilder";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Fetch a song by its document ID from Sanity.
|
|
@@ -29,12 +30,15 @@ import { fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent
|
|
|
29
30
|
* .catch(error => console.error(error));
|
|
30
31
|
*/
|
|
31
32
|
export async function fetchSongById(documentId) {
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
const fields = getFieldsForContentType('song');
|
|
34
|
+
const filterParams = {};
|
|
35
|
+
const query = buildQuery(
|
|
36
|
+
`_type == "song" && railcontent_id == ${documentId}`,
|
|
37
|
+
filterParams,
|
|
38
|
+
fields,
|
|
39
|
+
{
|
|
40
|
+
isSingle: true,
|
|
41
|
+
});
|
|
38
42
|
return fetchSanity(query, false);
|
|
39
43
|
}
|
|
40
44
|
|
|
@@ -50,10 +54,11 @@ export async function fetchSongById(documentId) {
|
|
|
50
54
|
* .catch(error => console.error(error));
|
|
51
55
|
*/
|
|
52
56
|
export async function fetchArtists(brand) {
|
|
57
|
+
const filter = new FilterBuilder(`_type == "song" && brand == "${brand}" && references(^._id)`).buildFilter();
|
|
53
58
|
const query = `
|
|
54
59
|
*[_type == "artist"]{
|
|
55
60
|
name,
|
|
56
|
-
"lessonsCount": count(*[
|
|
61
|
+
"lessonsCount": count(*[${filter}])
|
|
57
62
|
}[lessonsCount > 0]`;
|
|
58
63
|
return fetchSanity(query, true);
|
|
59
64
|
}
|
|
@@ -254,23 +259,32 @@ export async function fetchWorkouts(brand) {
|
|
|
254
259
|
*/
|
|
255
260
|
export async function fetchNewReleases(brand, { page = 1, limit = 10, sort="-published_on" } = {}) {
|
|
256
261
|
const newTypes = getNewReleasesTypes(brand);
|
|
257
|
-
const typesString =
|
|
262
|
+
const typesString = arrayToStringRepresentation(newTypes);
|
|
258
263
|
const start = (page - 1) * limit;
|
|
259
264
|
const end = start + limit;
|
|
260
265
|
const sortOrder = getSortOrder(sort);
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
266
|
+
const filter = `_type in ${typesString} && brand == '${brand}'`;
|
|
267
|
+
const fields = `
|
|
268
|
+
"id": railcontent_id,
|
|
269
|
+
title,
|
|
270
|
+
"image": thumbnail.asset->url,
|
|
271
|
+
"artist_name": instructor[0]->name,
|
|
272
|
+
"artists": instructor[]->name,
|
|
273
|
+
difficulty,
|
|
274
|
+
difficulty_string,
|
|
275
|
+
length_in_seconds,
|
|
276
|
+
published_on,
|
|
277
|
+
"type": _type,
|
|
278
|
+
web_url_path,`;
|
|
279
|
+
const filterParams = {};
|
|
280
|
+
const query = buildQuery(
|
|
281
|
+
filter,
|
|
282
|
+
filterParams,
|
|
283
|
+
fields,
|
|
284
|
+
{
|
|
285
|
+
sortOrder: sortOrder,
|
|
286
|
+
end: end,
|
|
287
|
+
});
|
|
274
288
|
return fetchSanity(query, true);
|
|
275
289
|
}
|
|
276
290
|
|
|
@@ -291,11 +305,11 @@ export async function fetchNewReleases(brand, { page = 1, limit = 10, sort="-pub
|
|
|
291
305
|
*/
|
|
292
306
|
export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {}) {
|
|
293
307
|
const liveTypes = getUpcomingEventsTypes(brand);
|
|
294
|
-
const typesString =
|
|
308
|
+
const typesString = arrayToStringRepresentation(liveTypes);
|
|
295
309
|
const now = getSanityDate(new Date());
|
|
296
310
|
const start = (page - 1) * limit;
|
|
297
311
|
const end = start + limit;
|
|
298
|
-
const
|
|
312
|
+
const fields = `
|
|
299
313
|
"id": railcontent_id,
|
|
300
314
|
title,
|
|
301
315
|
"image": thumbnail.asset->url,
|
|
@@ -306,8 +320,16 @@ export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {})
|
|
|
306
320
|
length_in_seconds,
|
|
307
321
|
published_on,
|
|
308
322
|
"type": _type,
|
|
309
|
-
web_url_path
|
|
310
|
-
|
|
323
|
+
web_url_path,`;
|
|
324
|
+
const query = buildRawQuery(
|
|
325
|
+
`_type in ${typesString} && brand == '${brand}' && published_on > '${now}' && status == 'scheduled'`,
|
|
326
|
+
fields,
|
|
327
|
+
{
|
|
328
|
+
sortOrder: 'published_on asc',
|
|
329
|
+
start: start,
|
|
330
|
+
end: end,
|
|
331
|
+
},
|
|
332
|
+
);
|
|
311
333
|
return fetchSanity(query, true);
|
|
312
334
|
}
|
|
313
335
|
|
|
@@ -354,6 +376,7 @@ export async function fetchScheduledReleases(brand, { page = 1, limit = 10 }) {
|
|
|
354
376
|
* Fetch content by a specific Railcontent ID.
|
|
355
377
|
*
|
|
356
378
|
* @param {string} id - The Railcontent ID of the content to fetch.
|
|
379
|
+
* @param {string} contentType - The document type of content to fetch
|
|
357
380
|
* @returns {Promise<Object|null>} - A promise that resolves to the content object or null if not found.
|
|
358
381
|
*
|
|
359
382
|
* @example
|
|
@@ -362,10 +385,16 @@ export async function fetchScheduledReleases(brand, { page = 1, limit = 10 }) {
|
|
|
362
385
|
* .catch(error => console.error(error));
|
|
363
386
|
*/
|
|
364
387
|
export async function fetchByRailContentId(id, contentType) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
388
|
+
|
|
389
|
+
const query = buildRawQuery(
|
|
390
|
+
`railcontent_id == ${id} && _type == '${contentType}'`,
|
|
391
|
+
getFieldsForContentType(contentType),
|
|
392
|
+
{
|
|
393
|
+
isSingle: true,
|
|
394
|
+
},
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
return fetchSanity(query, false);
|
|
369
398
|
}
|
|
370
399
|
|
|
371
400
|
/**
|
|
@@ -382,6 +411,7 @@ export async function fetchByRailContentId(id, contentType) {
|
|
|
382
411
|
*/
|
|
383
412
|
export async function fetchByRailContentIds(ids, contentType = undefined) {
|
|
384
413
|
const idsString = ids.join(',');
|
|
414
|
+
|
|
385
415
|
const query = `*[railcontent_id in [${idsString}]]{
|
|
386
416
|
${getFieldsForContentType(contentType)}
|
|
387
417
|
}`
|
|
@@ -437,6 +467,9 @@ export async function fetchAll(brand, type, {
|
|
|
437
467
|
const start = (page - 1) * limit;
|
|
438
468
|
const end = start + limit;
|
|
439
469
|
|
|
470
|
+
// Construct the type filter
|
|
471
|
+
const typeFilter = type ? `&& _type == '${type}'` : "";
|
|
472
|
+
|
|
440
473
|
// Construct the search filter
|
|
441
474
|
const searchFilter = searchTerm
|
|
442
475
|
? groupBy !== "" ?
|
|
@@ -465,8 +498,8 @@ export async function fetchAll(brand, type, {
|
|
|
465
498
|
let webUrlPath = 'artists';
|
|
466
499
|
query = `
|
|
467
500
|
{
|
|
468
|
-
"total": count(*[_type == '${groupBy}' && count(*[
|
|
469
|
-
"entity": *[_type == '${groupBy}' && count(*[
|
|
501
|
+
"total": count(*[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]),
|
|
502
|
+
"entity": *[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]
|
|
470
503
|
{
|
|
471
504
|
'id': _id,
|
|
472
505
|
'type': _type,
|
|
@@ -486,16 +519,16 @@ export async function fetchAll(brand, type, {
|
|
|
486
519
|
let webUrlPath = (groupBy == 'genre')?'/genres':'';
|
|
487
520
|
query = `
|
|
488
521
|
{
|
|
489
|
-
"total": count(*[_type == '${groupBy}' && count(*[
|
|
490
|
-
"entity": *[_type == '${groupBy}' && count(*[
|
|
522
|
+
"total": count(*[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]),
|
|
523
|
+
"entity": *[_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0]
|
|
491
524
|
{
|
|
492
525
|
'id': _id,
|
|
493
526
|
'type': _type,
|
|
494
527
|
name,
|
|
495
528
|
'head_shot_picture_url': thumbnail_url.asset->url,
|
|
496
529
|
'web_url_path': select(defined(web_url_path)=> web_url_path +'?included_fieds[]=type,${type}',!defined(web_url_path)=> '/${brand}${webUrlPath}/'+name+'/${webUrlPathType}'),
|
|
497
|
-
'all_lessons_count': count(*[
|
|
498
|
-
'lessons': *[
|
|
530
|
+
'all_lessons_count': count(*[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id),
|
|
531
|
+
'lessons': *[brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]{
|
|
499
532
|
${fieldsString},
|
|
500
533
|
${groupBy}
|
|
501
534
|
}[0...10]
|
|
@@ -506,10 +539,10 @@ export async function fetchAll(brand, type, {
|
|
|
506
539
|
} else {
|
|
507
540
|
query = `
|
|
508
541
|
{
|
|
509
|
-
"entity": *[
|
|
542
|
+
"entity": *[brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}] | order(${sortOrder}) [${start}...${end}] {
|
|
510
543
|
${fieldsString},
|
|
511
544
|
},
|
|
512
|
-
"total": count(*[
|
|
545
|
+
"total": count(*[brand == "${brand}" ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}])
|
|
513
546
|
}
|
|
514
547
|
`;
|
|
515
548
|
}
|
|
@@ -617,8 +650,8 @@ export async function fetchChildren(railcontentId, contentType) {
|
|
|
617
650
|
${getFieldsForContentType(contentType)}
|
|
618
651
|
},
|
|
619
652
|
}[0..1]`;
|
|
620
|
-
let parent = await fetchSanity(query,
|
|
621
|
-
return parent[
|
|
653
|
+
let parent = await fetchSanity(query, false);
|
|
654
|
+
return parent['children'] ?? [];
|
|
622
655
|
}
|
|
623
656
|
|
|
624
657
|
/**
|
|
@@ -634,8 +667,8 @@ export async function fetchParentByRailContentId(railcontentId) {
|
|
|
634
667
|
})
|
|
635
668
|
])
|
|
636
669
|
}[0...1]`;
|
|
637
|
-
let child = await fetchSanity(query,
|
|
638
|
-
return child[
|
|
670
|
+
let child = await fetchSanity(query, false);
|
|
671
|
+
return child['parents'][0] ?? [];
|
|
639
672
|
}
|
|
640
673
|
|
|
641
674
|
/**
|
|
@@ -656,9 +689,16 @@ export async function fetchMethods(brand) {
|
|
|
656
689
|
* @returns {Promise<Object|null>} - The fetched foundation data or null if not found.
|
|
657
690
|
*/
|
|
658
691
|
export async function fetchFoundation(slug) {
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
692
|
+
const filterParams = {};
|
|
693
|
+
const query = buildQuery(
|
|
694
|
+
`_type == 'foundation' && slug.current == "${slug}"`,
|
|
695
|
+
filterParams,
|
|
696
|
+
getFieldsForContentType('foundation'),
|
|
697
|
+
{
|
|
698
|
+
sortOrder: 'published_on asc',
|
|
699
|
+
isSingle: true,
|
|
700
|
+
}
|
|
701
|
+
);
|
|
662
702
|
return fetchSanity(query, false);
|
|
663
703
|
}
|
|
664
704
|
|
|
@@ -761,7 +801,6 @@ export async function fetchMethodPreviousNextLesson(railcontentId, methodId) {
|
|
|
761
801
|
* @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
|
|
762
802
|
*/
|
|
763
803
|
export async function fetchMethodChildrenIds(railcontentId) {
|
|
764
|
-
//TODO: Implement getByParentId include sum XP
|
|
765
804
|
const query = `*[_type == 'learning-path' && railcontent_id == ${railcontentId}]{
|
|
766
805
|
'children': child[]-> {
|
|
767
806
|
'id': railcontent_id,
|
|
@@ -774,7 +813,7 @@ export async function fetchMethodChildrenIds(railcontentId) {
|
|
|
774
813
|
}
|
|
775
814
|
}`;
|
|
776
815
|
let allChildren = await fetchSanity(query, false);
|
|
777
|
-
return getChildrenToDepth(allChildren, 4)
|
|
816
|
+
return getChildrenToDepth(allChildren, 4);
|
|
778
817
|
}
|
|
779
818
|
|
|
780
819
|
function getChildrenToDepth(parent, depth = 1)
|
|
@@ -823,8 +862,8 @@ export async function fetchNextPreviousLesson(railcontentId) {
|
|
|
823
862
|
* .catch(error => console.error(error));
|
|
824
863
|
*/
|
|
825
864
|
export async function fetchLessonContent(railContentId) {
|
|
826
|
-
|
|
827
|
-
|
|
865
|
+
const filterParams = {};
|
|
866
|
+
const fields = `title,
|
|
828
867
|
published_on,
|
|
829
868
|
"type":_type,
|
|
830
869
|
"resources": resource,
|
|
@@ -860,8 +899,19 @@ export async function fetchLessonContent(railContentId) {
|
|
|
860
899
|
},
|
|
861
900
|
${assignmentsField}
|
|
862
901
|
video,
|
|
863
|
-
length_in_seconds
|
|
864
|
-
|
|
902
|
+
length_in_seconds,
|
|
903
|
+
mp3_no_drums_no_click_url,
|
|
904
|
+
mp3_no_drums_yes_click_url,
|
|
905
|
+
mp3_yes_drums_no_click_url,
|
|
906
|
+
mp3_yes_drums_yes_click_url,`;
|
|
907
|
+
const query = buildQuery(
|
|
908
|
+
`railcontent_id == ${railContentId}`,
|
|
909
|
+
filterParams,
|
|
910
|
+
fields,
|
|
911
|
+
{
|
|
912
|
+
isSingle: true,
|
|
913
|
+
}
|
|
914
|
+
);
|
|
865
915
|
return fetchSanity(query, false);
|
|
866
916
|
}
|
|
867
917
|
|
|
@@ -920,10 +970,16 @@ export async function fetchRelatedMethodLessons(railContentId, brand) {
|
|
|
920
970
|
*/
|
|
921
971
|
export async function fetchAllPacks(brand, sort = "-published_on", searchTerm = "") {
|
|
922
972
|
const sortOrder = getSortOrder(sort);
|
|
923
|
-
|
|
924
|
-
const
|
|
925
|
-
|
|
926
|
-
|
|
973
|
+
const filter = `_type == 'pack' && brand == '${brand}' && title match "${searchTerm}*"`
|
|
974
|
+
const filterParams = {};
|
|
975
|
+
const query = buildQuery(
|
|
976
|
+
filter,
|
|
977
|
+
filterParams,
|
|
978
|
+
getFieldsForContentType('pack'),
|
|
979
|
+
{
|
|
980
|
+
sortOrder: sortOrder,
|
|
981
|
+
}
|
|
982
|
+
);
|
|
927
983
|
return fetchSanity(query, true);
|
|
928
984
|
}
|
|
929
985
|
|
|
@@ -933,11 +989,7 @@ export async function fetchAllPacks(brand, sort = "-published_on", searchTerm =
|
|
|
933
989
|
* @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
|
|
934
990
|
*/
|
|
935
991
|
export async function fetchPackAll(railcontentId) {
|
|
936
|
-
|
|
937
|
-
const query = `*[railcontent_id == ${railcontentId}]{
|
|
938
|
-
${getFieldsForContentType('pack')}
|
|
939
|
-
} | order(published_on asc)[0...1]`
|
|
940
|
-
return fetchSanity(query, false);
|
|
992
|
+
return fetchByRailContentId(railcontentId, 'pack');
|
|
941
993
|
}
|
|
942
994
|
|
|
943
995
|
export async function fetchLiveEvent(brand) {
|
|
@@ -1013,7 +1065,7 @@ export async function fetchPackChildren(railcontentId) {
|
|
|
1013
1065
|
export async function fetchChallengeOverview(id) {
|
|
1014
1066
|
// WIP
|
|
1015
1067
|
const query = `*[railcontent_id == ${id}]{
|
|
1016
|
-
${getFieldsForContentType("challenge"
|
|
1068
|
+
${getFieldsForContentType("challenge")}
|
|
1017
1069
|
"lessons": child[]->{
|
|
1018
1070
|
"id": railcontent_id,
|
|
1019
1071
|
title,
|
|
@@ -1024,7 +1076,7 @@ export async function fetchChallengeOverview(id) {
|
|
|
1024
1076
|
difficulty,
|
|
1025
1077
|
"type": _type,
|
|
1026
1078
|
}
|
|
1027
|
-
}`;
|
|
1079
|
+
} [0...1]`;
|
|
1028
1080
|
return fetchSanity(query, false);
|
|
1029
1081
|
}
|
|
1030
1082
|
|
|
@@ -1044,18 +1096,21 @@ export async function fetchCoachLessons(brand, id, {
|
|
|
1044
1096
|
page = 1,
|
|
1045
1097
|
limit = 20,
|
|
1046
1098
|
} = {}) {
|
|
1047
|
-
const fieldsString =
|
|
1099
|
+
const fieldsString = getFieldsForContentType();
|
|
1048
1100
|
const start = (page - 1) * limit;
|
|
1049
1101
|
const end = start + limit;
|
|
1050
|
-
const searchFilter = searchTerm ? `&& title match "${searchTerm}*"`: ''
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1102
|
+
const searchFilter = searchTerm ? `&& title match "${searchTerm}*"`: ''
|
|
1103
|
+
const filter = `brand == '${brand}' ${searchFilter} && references(*[_type=='instructor' && railcontent_id == ${id}]._id)`;
|
|
1104
|
+
sortOrder = getSortOrder(sortOrder);
|
|
1105
|
+
const query = buildEntityAndTotalQuery(
|
|
1106
|
+
filter,
|
|
1107
|
+
fieldsString,
|
|
1108
|
+
{
|
|
1109
|
+
sortOrder: sortOrder,
|
|
1110
|
+
start: start,
|
|
1111
|
+
end: end,
|
|
1112
|
+
},
|
|
1113
|
+
);
|
|
1059
1114
|
return fetchSanity(query, true);
|
|
1060
1115
|
}
|
|
1061
1116
|
|
|
@@ -1070,10 +1125,7 @@ export async function fetchCoachLessons(brand, id, {
|
|
|
1070
1125
|
* .catch(error => console.error(error));
|
|
1071
1126
|
*/
|
|
1072
1127
|
export async function fetchCourseOverview(id) {
|
|
1073
|
-
|
|
1074
|
-
${getFieldsForContentType("course", true)}
|
|
1075
|
-
}`
|
|
1076
|
-
return fetchSanity(query, false);
|
|
1128
|
+
return fetchByRailContentId(id, 'course');
|
|
1077
1129
|
}
|
|
1078
1130
|
|
|
1079
1131
|
/**
|
|
@@ -1094,21 +1146,23 @@ export async function fetchByReference(brand, {
|
|
|
1094
1146
|
limit = 20,
|
|
1095
1147
|
includedFields = [],
|
|
1096
1148
|
} = {}) {
|
|
1097
|
-
const fieldsString =
|
|
1149
|
+
const fieldsString = getFieldsForContentType();
|
|
1098
1150
|
const start = (page - 1) * limit;
|
|
1099
1151
|
const end = start + limit;
|
|
1100
1152
|
const searchFilter = searchTerm ? `&& title match "${searchTerm}*"`: '';
|
|
1101
1153
|
const includedFieldsFilter = includedFields.length > 0
|
|
1102
1154
|
? includedFields.join(' && ')
|
|
1103
1155
|
: "";
|
|
1104
|
-
|
|
1105
|
-
const query =
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1156
|
+
const filter = `brand == '${brand}' ${searchFilter} && references(*[${includedFieldsFilter}]._id)`;
|
|
1157
|
+
const query = buildEntityAndTotalQuery(
|
|
1158
|
+
filter,
|
|
1159
|
+
fieldsString,
|
|
1160
|
+
{
|
|
1161
|
+
sortOrder: getSortOrder(sortOrder),
|
|
1162
|
+
start: start,
|
|
1163
|
+
end: end,
|
|
1164
|
+
},
|
|
1165
|
+
);
|
|
1112
1166
|
return fetchSanity(query, true);
|
|
1113
1167
|
}
|
|
1114
1168
|
|
|
@@ -1312,3 +1366,64 @@ function checkSanityConfig(config) {
|
|
|
1312
1366
|
}
|
|
1313
1367
|
|
|
1314
1368
|
|
|
1369
|
+
function buildRawQuery(
|
|
1370
|
+
filter = '',
|
|
1371
|
+
fields = '...',
|
|
1372
|
+
{
|
|
1373
|
+
sortOrder = 'published_on desc',
|
|
1374
|
+
start = 0,
|
|
1375
|
+
end = 10,
|
|
1376
|
+
isSingle = false,
|
|
1377
|
+
}
|
|
1378
|
+
) {
|
|
1379
|
+
const sortString = sortOrder ? `order(${sortOrder})` : '';
|
|
1380
|
+
const countString = isSingle ? '[0...1]' : `[${start}...${end}]`;
|
|
1381
|
+
const query = `*[${filter}]{
|
|
1382
|
+
${fields}
|
|
1383
|
+
} | ${sortString}${countString}`
|
|
1384
|
+
return query;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
function buildQuery(
|
|
1389
|
+
baseFilter = '',
|
|
1390
|
+
filterParams = {},
|
|
1391
|
+
fields = '...',
|
|
1392
|
+
{
|
|
1393
|
+
sortOrder = 'published_on desc',
|
|
1394
|
+
start = 0,
|
|
1395
|
+
end = 10,
|
|
1396
|
+
isSingle = false,
|
|
1397
|
+
},
|
|
1398
|
+
) {
|
|
1399
|
+
const filter = new FilterBuilder(baseFilter, filterParams).buildFilter();
|
|
1400
|
+
return buildRawQuery(filter, fields, {sortOrder, start, end, isSingle});
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
function buildEntityAndTotalQuery(
|
|
1404
|
+
filter = '',
|
|
1405
|
+
fields = '...',
|
|
1406
|
+
{
|
|
1407
|
+
sortOrder = 'published_on desc',
|
|
1408
|
+
start = 0,
|
|
1409
|
+
end = 10,
|
|
1410
|
+
isSingle = false,
|
|
1411
|
+
},
|
|
1412
|
+
) {
|
|
1413
|
+
const sortString = sortOrder ? `order(${sortOrder})` : '';
|
|
1414
|
+
const countString = isSingle ? '[0...1]' : `[${start}...${end}]`;
|
|
1415
|
+
const query = `{
|
|
1416
|
+
"entity": *[${filter}] | ${sortString}${countString}
|
|
1417
|
+
{
|
|
1418
|
+
${fields}
|
|
1419
|
+
},
|
|
1420
|
+
"total": count(*[${filter}])
|
|
1421
|
+
}`;
|
|
1422
|
+
return query;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
|
|
1429
|
+
|
|
@@ -9,33 +9,34 @@ const {
|
|
|
9
9
|
fetchAllSongs,
|
|
10
10
|
fetchSongFilterOptions,
|
|
11
11
|
fetchSongCount,
|
|
12
|
-
fetchWorkouts,
|
|
13
12
|
fetchNewReleases,
|
|
14
13
|
fetchUpcomingEvents,
|
|
15
14
|
fetchByRailContentId,
|
|
16
15
|
fetchByRailContentIds,
|
|
17
16
|
fetchAll,
|
|
18
17
|
fetchAllFilterOptions,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
fetchFoundation,
|
|
19
|
+
fetchMethods,
|
|
20
|
+
fetchMethod,
|
|
22
21
|
fetchRelatedLessons,
|
|
22
|
+
fetchAllPacks,
|
|
23
23
|
fetchPackAll,
|
|
24
|
-
fetchPackChildren,
|
|
25
24
|
fetchLessonContent,
|
|
26
|
-
|
|
27
|
-
fetchParentByRailContentId,
|
|
25
|
+
fetchCourseOverview,
|
|
28
26
|
fetchChildren,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
fetchAllPacks,
|
|
33
|
-
fetchPacksAll,
|
|
27
|
+
fetchParentByRailContentId,
|
|
28
|
+
fetchLiveEvent,
|
|
29
|
+
fetchChallengeOverview,
|
|
34
30
|
fetchCoachLessons,
|
|
35
31
|
fetchByReference,
|
|
36
|
-
fetchScheduledReleases
|
|
32
|
+
fetchScheduledReleases,
|
|
33
|
+
getSortOrder,
|
|
37
34
|
} = require('../src/services/sanity.js');
|
|
38
35
|
|
|
36
|
+
const {
|
|
37
|
+
FilterBuilder,
|
|
38
|
+
} = require('../src/filterBuilder.js');
|
|
39
|
+
|
|
39
40
|
describe('Sanity Queries', function () {
|
|
40
41
|
beforeEach(() => {
|
|
41
42
|
const config = {
|
|
@@ -73,7 +74,14 @@ describe('Sanity Queries', function () {
|
|
|
73
74
|
|
|
74
75
|
test('fetchByRailContentId', async () => {
|
|
75
76
|
const id = 380094;
|
|
76
|
-
const response = await fetchByRailContentId(id);
|
|
77
|
+
const response = await fetchByRailContentId(id, "song");
|
|
78
|
+
expect(response.id).toBe(id);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('fetchChallengeOverview', async () => {
|
|
82
|
+
const id = 402197;
|
|
83
|
+
const response = await fetchChallengeOverview(id);
|
|
84
|
+
expect(response.lessons).toBeDefined();
|
|
77
85
|
expect(response.id).toBe(id);
|
|
78
86
|
});
|
|
79
87
|
|
|
@@ -88,12 +96,36 @@ describe('Sanity Queries', function () {
|
|
|
88
96
|
|
|
89
97
|
});
|
|
90
98
|
|
|
99
|
+
test('fetchUpcomingEvents', async () => {
|
|
100
|
+
const response = await fetchUpcomingEvents('drumeo', {});
|
|
101
|
+
expect(response.length).toBeGreaterThan(0);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('fetchUpcomingNewReleases', async () => {
|
|
105
|
+
const response = await fetchNewReleases('drumeo');
|
|
106
|
+
expect(response.length).toBeGreaterThan(0);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
|
|
91
110
|
test('fetchLessonContent', async () => {
|
|
92
111
|
const id = 380094;
|
|
93
112
|
const response = await fetchLessonContent(id);
|
|
94
113
|
expect(response.id).toBe(id);
|
|
95
114
|
});
|
|
96
115
|
|
|
116
|
+
|
|
117
|
+
test('fetchCourseOverview', async () => {
|
|
118
|
+
const id = 310414;
|
|
119
|
+
const response = await fetchCourseOverview(id);
|
|
120
|
+
expect(response.id).toBe(id);
|
|
121
|
+
expect(response.type).toBe('course');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('fetchSongCount', async () => {
|
|
125
|
+
const response = await fetchSongCount('drumeo');
|
|
126
|
+
expect(response).toBeGreaterThan(1000);
|
|
127
|
+
});
|
|
128
|
+
|
|
97
129
|
test('fetchAllSongs', async () => {
|
|
98
130
|
const response = await fetchAllSongs('drumeo', {});
|
|
99
131
|
log(response);
|
|
@@ -102,6 +134,13 @@ describe('Sanity Queries', function () {
|
|
|
102
134
|
expect(response.entity[0].instrumentless).toBeDefined();
|
|
103
135
|
});
|
|
104
136
|
|
|
137
|
+
test('fetchSongFilterOptions', async () => {
|
|
138
|
+
const response = await fetchSongFilterOptions('drumeo', {});
|
|
139
|
+
log(response);
|
|
140
|
+
expect(response.genre).toBeDefined();
|
|
141
|
+
expect(response.difficulty).toBeDefined();
|
|
142
|
+
});
|
|
143
|
+
|
|
105
144
|
test('fetchAllSongsGroupByArtist', async () => {
|
|
106
145
|
const response = await fetchAllSongs('drumeo', {groupBy:"artist"});
|
|
107
146
|
expect(response.entity[0].lessons[0].soundslice).toBeDefined();
|
|
@@ -110,6 +149,12 @@ describe('Sanity Queries', function () {
|
|
|
110
149
|
}, 100000);
|
|
111
150
|
|
|
112
151
|
|
|
152
|
+
test('fetchNewReleases', async () => {
|
|
153
|
+
const response = await fetchNewReleases('drumeo');
|
|
154
|
+
log(response);
|
|
155
|
+
expect(response[0].id).toBeDefined();
|
|
156
|
+
});
|
|
157
|
+
|
|
113
158
|
test('fetchAllWorkouts', async () => {
|
|
114
159
|
const response = await fetchAll('drumeo', 'workout',{});
|
|
115
160
|
log(response);
|
|
@@ -159,10 +204,10 @@ describe('Sanity Queries', function () {
|
|
|
159
204
|
|
|
160
205
|
test('fetchRelatedLessons', async () => {
|
|
161
206
|
const id = 380094;
|
|
162
|
-
const document = await fetchByRailContentId(id);
|
|
207
|
+
const document = await fetchByRailContentId(id, 'song');
|
|
163
208
|
let artist = document.artist.name;
|
|
164
209
|
const response = await fetchRelatedLessons(id, 'singeo');
|
|
165
|
-
let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id);
|
|
210
|
+
let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id, 'song');
|
|
166
211
|
// match on artist or any genre
|
|
167
212
|
let isMatch = artist === relatedDoc.artist.name;
|
|
168
213
|
isMatch = isMatch || document.genre.some((genre) => {
|
|
@@ -274,7 +319,7 @@ describe('Sanity Queries', function () {
|
|
|
274
319
|
});
|
|
275
320
|
|
|
276
321
|
test('fetchCoachLessons', async () => {
|
|
277
|
-
const response = await fetchCoachLessons('drumeo',
|
|
322
|
+
const response = await fetchCoachLessons('drumeo',411493, {});
|
|
278
323
|
expect(response.entity.length).toBeGreaterThan(0);
|
|
279
324
|
});
|
|
280
325
|
|
|
@@ -311,3 +356,148 @@ describe('Sanity Queries', function () {
|
|
|
311
356
|
expect(response.entity[0].web_url_path).toContain('/drumeo/coaches/');
|
|
312
357
|
});
|
|
313
358
|
});
|
|
359
|
+
|
|
360
|
+
describe('Filter Builder', function () {
|
|
361
|
+
|
|
362
|
+
test('baseConstructor', async () => {
|
|
363
|
+
const filter = 'railcontent_id = 111'
|
|
364
|
+
let builder = new FilterBuilder(filter);
|
|
365
|
+
let finalFilter = builder.buildFilter(filter);
|
|
366
|
+
let clauses = spliceFilterForAnds(finalFilter);
|
|
367
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
368
|
+
expect(clauses[1].field).toBe('published_on');
|
|
369
|
+
|
|
370
|
+
builder = new FilterBuilder();
|
|
371
|
+
finalFilter = builder.buildFilter(filter);
|
|
372
|
+
clauses = spliceFilterForAnds(finalFilter);
|
|
373
|
+
expect(clauses[0].field).toBe('published_on');
|
|
374
|
+
expect(clauses[0].operator).toBe('<=');
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test('withOnlyFilterAvailableStatuses', async () => {
|
|
378
|
+
const filter = 'railcontent_id = 111'
|
|
379
|
+
const builder = FilterBuilder.withOnlyFilterAvailableStatuses(filter,['published', 'unlisted']);
|
|
380
|
+
const finalFilter = builder.buildFilter();
|
|
381
|
+
const clauses = spliceFilterForAnds(finalFilter);
|
|
382
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
383
|
+
expect(clauses[1].field).toBe('status');
|
|
384
|
+
expect(clauses[1].operator).toBe('in');
|
|
385
|
+
// not sure I like this
|
|
386
|
+
expect(clauses[1].condition).toBe("['published','unlisted']");
|
|
387
|
+
expect(clauses[2].field).toBe('published_on');
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test('withContentStatusAndFutureScheduledContent', async () => {
|
|
391
|
+
const filter = 'railcontent_id = 111'
|
|
392
|
+
const builder = new FilterBuilder(filter,{
|
|
393
|
+
availableContentStatuses: ['published', 'unlisted', 'scheduled'],
|
|
394
|
+
getFutureScheduledContentsOnly: true});
|
|
395
|
+
const finalFilter = builder.buildFilter();
|
|
396
|
+
const clauses = spliceFilterForAnds(finalFilter);
|
|
397
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
398
|
+
expect(clauses[1].field).toBe('(status'); // extra ( because it's a multi part filter
|
|
399
|
+
expect(clauses[1].operator).toBe('in');
|
|
400
|
+
// getFutureScheduledContentsOnly doesn't make a filter that's splicable, so we match on the more static string
|
|
401
|
+
const expected = "['published','unlisted'] || (status == 'scheduled' && published_on >=";
|
|
402
|
+
console.log(clauses[1].condition);
|
|
403
|
+
console.log(expected)
|
|
404
|
+
const isMatch = finalFilter.includes(expected);
|
|
405
|
+
expect(isMatch).toBeTruthy();
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test('withUserPermissions', async () => {
|
|
409
|
+
const filter = 'railcontent_id = 111'
|
|
410
|
+
const builder = new FilterBuilder(filter,
|
|
411
|
+
{ user: {
|
|
412
|
+
user: {},
|
|
413
|
+
permissions: [91, 92],
|
|
414
|
+
}});
|
|
415
|
+
const finalFilter = builder.buildFilter();
|
|
416
|
+
const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
|
|
417
|
+
const isMatch = finalFilter.includes(expected);
|
|
418
|
+
expect(isMatch).toBeTruthy();
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
test('withUserPermissionsForPlusUser', async () => {
|
|
422
|
+
const filter = 'railcontent_id = 111'
|
|
423
|
+
const builder = new FilterBuilder(filter,
|
|
424
|
+
{
|
|
425
|
+
user: getPlusUser()
|
|
426
|
+
});
|
|
427
|
+
const finalFilter = builder.buildFilter();
|
|
428
|
+
const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
|
|
429
|
+
const isMatch = finalFilter.includes(expected);
|
|
430
|
+
expect(isMatch).toBeTruthy();
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test('withPermissionBypass', async () => {
|
|
434
|
+
const filter = 'railcontent_id = 111'
|
|
435
|
+
const builder = new FilterBuilder(filter,
|
|
436
|
+
{
|
|
437
|
+
user: getPlusUser(),
|
|
438
|
+
bypassPermissions:true
|
|
439
|
+
});
|
|
440
|
+
const finalFilter = builder.buildFilter();
|
|
441
|
+
const expected = "references(*[_type == 'permission' && railcontent_id in [91,92]]._id)"
|
|
442
|
+
const isMatch = finalFilter.includes(expected);
|
|
443
|
+
expect(isMatch).toBeFalsy();
|
|
444
|
+
const clauses = spliceFilterForAnds(finalFilter);
|
|
445
|
+
expect(clauses[0].field).toBe('railcontent_id');
|
|
446
|
+
expect(clauses[1].field).toBe('published_on');
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
test('withPublishOnRestrictions', async () => {
|
|
451
|
+
// testing dates is a pain more frustration than I'm willing to deal with, so I'm just testing operators.
|
|
452
|
+
|
|
453
|
+
const filter = 'railcontent_id = 111'
|
|
454
|
+
let builder = new FilterBuilder(filter, {
|
|
455
|
+
user: {},
|
|
456
|
+
pullFutureContent: true,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
let finalFilter = builder.buildFilter();
|
|
460
|
+
let clauses = spliceFilterForAnds(finalFilter);
|
|
461
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
462
|
+
|
|
463
|
+
expect(clauses[1].field).toBe('published_on');
|
|
464
|
+
expect(clauses[1].operator).toBe('<=');
|
|
465
|
+
const restrictionDate = new Date(clauses[1].condition)
|
|
466
|
+
const now = new Date();
|
|
467
|
+
expect(now.getTime()).toBeLessThan(restrictionDate.getTime());
|
|
468
|
+
|
|
469
|
+
builder = new FilterBuilder(filter,
|
|
470
|
+
{
|
|
471
|
+
user: {},
|
|
472
|
+
getFutureContentOnly: true,
|
|
473
|
+
});
|
|
474
|
+
finalFilter = builder.buildFilter();
|
|
475
|
+
clauses = spliceFilterForAnds(finalFilter);
|
|
476
|
+
expect(clauses[0].phrase).toBe(filter);
|
|
477
|
+
expect(clauses[1].field).toBe('published_on');
|
|
478
|
+
expect(clauses[1].operator).toBe('>=');
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
function getPlusUser() {
|
|
482
|
+
return {
|
|
483
|
+
permissions: [91,92],
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function spliceFilterForAnds(filter) {
|
|
488
|
+
// this will not correctly split complex filters with && and || conditions.
|
|
489
|
+
let phrases = filter.split(' && ');
|
|
490
|
+
let clauses= [];
|
|
491
|
+
phrases.forEach((phrase) => {
|
|
492
|
+
let field = phrase.substring(0, phrase.indexOf(' '));
|
|
493
|
+
//if(field.charAt(0) === '(' ) field = field.substring(1);
|
|
494
|
+
const temp = phrase.substring(phrase.indexOf(' ') + 1);
|
|
495
|
+
const operator = temp.substring(0, temp.indexOf(' '));
|
|
496
|
+
let condition = temp.substring(temp.indexOf(' ') + 1);
|
|
497
|
+
//if(condition.charAt(condition.length) === ')') condition = condition.slice(-1);
|
|
498
|
+
clauses.push({phrase, field, operator, condition});
|
|
499
|
+
});
|
|
500
|
+
return clauses;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
});
|