diff options
Diffstat (limited to 'server/models/utils.ts')
-rw-r--r-- | server/models/utils.ts | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/server/models/utils.ts b/server/models/utils.ts index a478bc62b..98170a00e 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts | |||
@@ -1,26 +1,29 @@ | |||
1 | import { Sequelize } from 'sequelize-typescript' | 1 | import { Sequelize } from 'sequelize-typescript' |
2 | import * as validator from 'validator' | 2 | import * as validator from 'validator' |
3 | import { OrderItem } from 'sequelize' | ||
4 | import { Col } from 'sequelize/types/lib/utils' | ||
3 | 5 | ||
4 | type SortType = { sortModel: any, sortValue: string } | 6 | type SortType = { sortModel: any, sortValue: string } |
5 | 7 | ||
6 | // Translate for example "-name" to [ [ 'name', 'DESC' ], [ 'id', 'ASC' ] ] | 8 | // Translate for example "-name" to [ [ 'name', 'DESC' ], [ 'id', 'ASC' ] ] |
7 | function getSort (value: string, lastSort: string[] = [ 'id', 'ASC' ]) { | 9 | function getSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { |
8 | let { direction, field } = buildDirectionAndField(value) | 10 | const { direction, field } = buildDirectionAndField(value) |
11 | |||
12 | let finalField: string | Col | ||
9 | 13 | ||
10 | if (field.toLowerCase() === 'match') { // Search | 14 | if (field.toLowerCase() === 'match') { // Search |
11 | field = Sequelize.col('similarity') | 15 | finalField = Sequelize.col('similarity') |
16 | } else { | ||
17 | finalField = field | ||
12 | } | 18 | } |
13 | 19 | ||
14 | return [ [ field, direction ], lastSort ] | 20 | return [ [ finalField, direction ], lastSort ] |
15 | } | 21 | } |
16 | 22 | ||
17 | function getVideoSort (value: string, lastSort: string[] = [ 'id', 'ASC' ]) { | 23 | function getVideoSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { |
18 | let { direction, field } = buildDirectionAndField(value) | 24 | const { direction, field } = buildDirectionAndField(value) |
19 | 25 | ||
20 | // Alias | 26 | if (field.toLowerCase() === 'trending') { // Sort by aggregation |
21 | if (field.toLowerCase() === 'match') { // Search | ||
22 | field = Sequelize.col('similarity') | ||
23 | } else if (field.toLowerCase() === 'trending') { // Sort by aggregation | ||
24 | return [ | 27 | return [ |
25 | [ Sequelize.fn('COALESCE', Sequelize.fn('SUM', Sequelize.col('VideoViews.views')), '0'), direction ], | 28 | [ Sequelize.fn('COALESCE', Sequelize.fn('SUM', Sequelize.col('VideoViews.views')), '0'), direction ], |
26 | 29 | ||
@@ -30,15 +33,24 @@ function getVideoSort (value: string, lastSort: string[] = [ 'id', 'ASC' ]) { | |||
30 | ] | 33 | ] |
31 | } | 34 | } |
32 | 35 | ||
33 | const firstSort = typeof field === 'string' ? | 36 | let finalField: string | Col |
34 | field.split('.').concat([ direction ]) : | 37 | |
35 | [ field, direction ] | 38 | // Alias |
39 | if (field.toLowerCase() === 'match') { // Search | ||
40 | finalField = Sequelize.col('similarity') | ||
41 | } else { | ||
42 | finalField = field | ||
43 | } | ||
44 | |||
45 | const firstSort = typeof finalField === 'string' | ||
46 | ? finalField.split('.').concat([ direction ]) as any // FIXME: sequelize typings | ||
47 | : [ finalField, direction ] | ||
36 | 48 | ||
37 | return [ firstSort, lastSort ] | 49 | return [ firstSort, lastSort ] |
38 | } | 50 | } |
39 | 51 | ||
40 | function getSortOnModel (model: any, value: string, lastSort: string[] = [ 'id', 'ASC' ]) { | 52 | function getSortOnModel (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { |
41 | let [ firstSort ] = getSort(value) | 53 | const [ firstSort ] = getSort(value) |
42 | 54 | ||
43 | if (model) return [ [ model, firstSort[0], firstSort[1] ], lastSort ] | 55 | if (model) return [ [ model, firstSort[0], firstSort[1] ], lastSort ] |
44 | return [ firstSort, lastSort ] | 56 | return [ firstSort, lastSort ] |
@@ -52,7 +64,9 @@ function isOutdated (model: { createdAt: Date, updatedAt: Date }, refreshInterva | |||
52 | return (now - createdAtTime) > refreshInterval && (now - updatedAtTime) > refreshInterval | 64 | return (now - createdAtTime) > refreshInterval && (now - updatedAtTime) > refreshInterval |
53 | } | 65 | } |
54 | 66 | ||
55 | function throwIfNotValid (value: any, validator: (value: any) => boolean, fieldName = 'value') { | 67 | function throwIfNotValid (value: any, validator: (value: any) => boolean, fieldName = 'value', nullable = false) { |
68 | if (nullable && (value === null || value === undefined)) return | ||
69 | |||
56 | if (validator(value) === false) { | 70 | if (validator(value) === false) { |
57 | throw new Error(`"${value}" is not a valid ${fieldName}.`) | 71 | throw new Error(`"${value}" is not a valid ${fieldName}.`) |
58 | } | 72 | } |
@@ -131,7 +145,7 @@ function searchTrigramNormalizeCol (col: string) { | |||
131 | } | 145 | } |
132 | 146 | ||
133 | function buildDirectionAndField (value: string) { | 147 | function buildDirectionAndField (value: string) { |
134 | let field: any | 148 | let field: string |
135 | let direction: 'ASC' | 'DESC' | 149 | let direction: 'ASC' | 'DESC' |
136 | 150 | ||
137 | if (value.substring(0, 1) === '-') { | 151 | if (value.substring(0, 1) === '-') { |