velocious 1.0.466 → 1.0.467
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/README.md +2 -1
- package/build/configuration.js +2 -2
- package/build/database/pool/async-tracked-multi-connection.js +7 -2
- package/build/database/pool/single-multi-use.js +38 -0
- package/build/frontend-model-controller.js +162 -56
- package/build/frontend-models/query.js +55 -33
- package/build/src/configuration.js +3 -3
- package/build/src/database/pool/async-tracked-multi-connection.d.ts.map +1 -1
- package/build/src/database/pool/async-tracked-multi-connection.js +9 -3
- package/build/src/database/pool/single-multi-use.d.ts +1 -0
- package/build/src/database/pool/single-multi-use.d.ts.map +1 -1
- package/build/src/database/pool/single-multi-use.js +34 -1
- package/build/src/frontend-model-controller.d.ts +45 -5
- package/build/src/frontend-model-controller.d.ts.map +1 -1
- package/build/src/frontend-model-controller.js +155 -57
- package/build/src/frontend-models/query.d.ts +8 -0
- package/build/src/frontend-models/query.d.ts.map +1 -1
- package/build/src/frontend-models/query.js +53 -34
- package/build/src/utils/ransack.d.ts +11 -3
- package/build/src/utils/ransack.d.ts.map +1 -1
- package/build/src/utils/ransack.js +42 -23
- package/build/utils/ransack.js +44 -22
- package/package.json +1 -1
- package/src/configuration.js +2 -2
- package/src/database/pool/async-tracked-multi-connection.js +7 -2
- package/src/database/pool/single-multi-use.js +38 -0
- package/src/frontend-model-controller.js +162 -56
- package/src/frontend-models/query.js +55 -33
- package/src/utils/ransack.js +44 -22
|
@@ -5,6 +5,28 @@ import {normalizeRansackGroup, parseRansackSort} from "../utils/ransack.js"
|
|
|
5
5
|
import {isModelScopeDescriptor} from "../utils/model-scope.js"
|
|
6
6
|
import isPlainObject from "../utils/plain-object.js"
|
|
7
7
|
|
|
8
|
+
/** Error raised when a frontend-model query descriptor is malformed. */
|
|
9
|
+
export class FrontendModelQueryError extends Error {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a frontend-model query error.
|
|
12
|
+
* @param {string} message - Error message.
|
|
13
|
+
*/
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message)
|
|
16
|
+
|
|
17
|
+
this.name = "FrontendModelQueryError"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Builds a query descriptor error.
|
|
23
|
+
* @param {string} message - Error message.
|
|
24
|
+
* @returns {FrontendModelQueryError} - Query descriptor error.
|
|
25
|
+
*/
|
|
26
|
+
function frontendModelQueryError(message) {
|
|
27
|
+
return new FrontendModelQueryError(message)
|
|
28
|
+
}
|
|
29
|
+
|
|
8
30
|
/**
|
|
9
31
|
* FrontendModelSearch type.
|
|
10
32
|
* @typedef {object} FrontendModelSearch
|
|
@@ -376,7 +398,7 @@ export function normalizeSearchOperator(operator) {
|
|
|
376
398
|
const supportedOperators = new Set(["eq", "like", "notEq", "gt", "gteq", "lt", "lteq"])
|
|
377
399
|
|
|
378
400
|
if (!supportedOperators.has(normalizedOperator)) {
|
|
379
|
-
throw
|
|
401
|
+
throw frontendModelQueryError(`search operator must be one of: eq, like, notEq, gt, gteq, lt, lteq, >, >=, <, <= (got: ${operator})`)
|
|
380
402
|
}
|
|
381
403
|
|
|
382
404
|
return /** @type {"eq" | "like" | "notEq" | "gt" | "gteq" | "lt" | "lteq"} */ (normalizedOperator)
|
|
@@ -400,7 +422,7 @@ function mergeJoinRecord(targetJoins, incomingJoins) {
|
|
|
400
422
|
}
|
|
401
423
|
|
|
402
424
|
if (!isPlainObject(incomingValue)) {
|
|
403
|
-
throw
|
|
425
|
+
throw frontendModelQueryError(`Invalid join value for ${relationshipName}: ${typeof incomingValue}`)
|
|
404
426
|
}
|
|
405
427
|
|
|
406
428
|
if (isPlainObject(existingValue)) {
|
|
@@ -433,7 +455,7 @@ export function normalizeJoins(joins) {
|
|
|
433
455
|
|
|
434
456
|
for (const joinEntry of joins) {
|
|
435
457
|
if (!isPlainObject(joinEntry)) {
|
|
436
|
-
throw
|
|
458
|
+
throw frontendModelQueryError(`Invalid joins entry type: ${typeof joinEntry}`)
|
|
437
459
|
}
|
|
438
460
|
|
|
439
461
|
mergeJoinRecord(normalized, normalizeJoins(joinEntry))
|
|
@@ -443,7 +465,7 @@ export function normalizeJoins(joins) {
|
|
|
443
465
|
}
|
|
444
466
|
|
|
445
467
|
if (!isPlainObject(joins)) {
|
|
446
|
-
throw
|
|
468
|
+
throw frontendModelQueryError(`Invalid joins type: ${typeof joins}`)
|
|
447
469
|
}
|
|
448
470
|
|
|
449
471
|
/**
|
|
@@ -462,7 +484,7 @@ export function normalizeJoins(joins) {
|
|
|
462
484
|
continue
|
|
463
485
|
}
|
|
464
486
|
|
|
465
|
-
throw
|
|
487
|
+
throw frontendModelQueryError(`Invalid join definition for "${relationshipName}": ${typeof relationshipJoin}`)
|
|
466
488
|
}
|
|
467
489
|
|
|
468
490
|
return normalized
|
|
@@ -497,13 +519,13 @@ export function normalizeJoins(joins) {
|
|
|
497
519
|
*/
|
|
498
520
|
function normalizeSortDirection(direction) {
|
|
499
521
|
if (typeof direction !== "string") {
|
|
500
|
-
throw
|
|
522
|
+
throw frontendModelQueryError(`Invalid sort direction type: ${typeof direction}`)
|
|
501
523
|
}
|
|
502
524
|
|
|
503
525
|
const normalizedDirection = direction.trim().toLowerCase()
|
|
504
526
|
|
|
505
527
|
if (normalizedDirection !== "asc" && normalizedDirection !== "desc") {
|
|
506
|
-
throw
|
|
528
|
+
throw frontendModelQueryError(`Invalid sort direction: ${direction}`)
|
|
507
529
|
}
|
|
508
530
|
|
|
509
531
|
return normalizedDirection
|
|
@@ -551,14 +573,14 @@ function parseSortString(sortValue, path = []) {
|
|
|
551
573
|
const trimmed = sortValue.trim()
|
|
552
574
|
|
|
553
575
|
if (trimmed.length < 1) {
|
|
554
|
-
throw
|
|
576
|
+
throw frontendModelQueryError("sort value must be a non-empty string")
|
|
555
577
|
}
|
|
556
578
|
|
|
557
579
|
if (trimmed.startsWith("-")) {
|
|
558
580
|
const column = trimmed.slice(1).trim()
|
|
559
581
|
|
|
560
582
|
if (column.length < 1) {
|
|
561
|
-
throw
|
|
583
|
+
throw frontendModelQueryError(`Invalid sort definition: ${sortValue}`)
|
|
562
584
|
}
|
|
563
585
|
|
|
564
586
|
return {
|
|
@@ -571,13 +593,13 @@ function parseSortString(sortValue, path = []) {
|
|
|
571
593
|
const sortParts = trimmed.split(/\s+/).filter(Boolean)
|
|
572
594
|
|
|
573
595
|
if (sortParts.length > 2) {
|
|
574
|
-
throw
|
|
596
|
+
throw frontendModelQueryError(`Invalid sort definition: ${sortValue}`)
|
|
575
597
|
}
|
|
576
598
|
|
|
577
599
|
const column = sortParts[0]
|
|
578
600
|
|
|
579
601
|
if (column.length < 1) {
|
|
580
|
-
throw
|
|
602
|
+
throw frontendModelQueryError(`Invalid sort definition: ${sortValue}`)
|
|
581
603
|
}
|
|
582
604
|
|
|
583
605
|
const direction = sortParts.length === 2
|
|
@@ -602,7 +624,7 @@ function parseSortTuple(sortValue, path = []) {
|
|
|
602
624
|
const column = columnValue.trim()
|
|
603
625
|
|
|
604
626
|
if (column.length < 1) {
|
|
605
|
-
throw
|
|
627
|
+
throw frontendModelQueryError("sort tuple column must be a non-empty string")
|
|
606
628
|
}
|
|
607
629
|
|
|
608
630
|
return {
|
|
@@ -641,12 +663,12 @@ function normalizeSortObject(sortValue, path) {
|
|
|
641
663
|
|
|
642
664
|
if (Array.isArray(sortEntry)) {
|
|
643
665
|
if (sortEntry.length < 1) {
|
|
644
|
-
throw
|
|
666
|
+
throw frontendModelQueryError(`Invalid sort definition for "${sortKey}": empty array`)
|
|
645
667
|
}
|
|
646
668
|
|
|
647
669
|
for (const nestedSortEntry of sortEntry) {
|
|
648
670
|
if (!sortTuple(nestedSortEntry)) {
|
|
649
|
-
throw
|
|
671
|
+
throw frontendModelQueryError(`Invalid sort definition for "${sortKey}": expected [column, direction] tuples`)
|
|
650
672
|
}
|
|
651
673
|
|
|
652
674
|
normalizedSorts.push(parseSortTuple(nestedSortEntry, [...path, sortKey]))
|
|
@@ -659,7 +681,7 @@ function normalizeSortObject(sortValue, path) {
|
|
|
659
681
|
continue
|
|
660
682
|
}
|
|
661
683
|
|
|
662
|
-
throw
|
|
684
|
+
throw frontendModelQueryError(`Invalid sort definition for "${sortKey}": ${typeof sortEntry}`)
|
|
663
685
|
}
|
|
664
686
|
|
|
665
687
|
return normalizedSorts
|
|
@@ -724,13 +746,13 @@ export function normalizeSort(sort) {
|
|
|
724
746
|
continue
|
|
725
747
|
}
|
|
726
748
|
|
|
727
|
-
throw
|
|
749
|
+
throw frontendModelQueryError(`Invalid sort entry type: ${typeof sortEntry}`)
|
|
728
750
|
}
|
|
729
751
|
|
|
730
752
|
return normalized
|
|
731
753
|
}
|
|
732
754
|
|
|
733
|
-
throw
|
|
755
|
+
throw frontendModelQueryError(`Invalid sort type: ${typeof sort}`)
|
|
734
756
|
}
|
|
735
757
|
|
|
736
758
|
/**
|
|
@@ -743,7 +765,7 @@ function parseGroupString(groupValue, path = []) {
|
|
|
743
765
|
const trimmed = groupValue.trim()
|
|
744
766
|
|
|
745
767
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
|
|
746
|
-
throw
|
|
768
|
+
throw frontendModelQueryError(`Invalid group column: ${groupValue}`)
|
|
747
769
|
}
|
|
748
770
|
|
|
749
771
|
return {
|
|
@@ -789,12 +811,12 @@ function normalizeColumnProjectionObject(value, path, parseString, label) {
|
|
|
789
811
|
|
|
790
812
|
if (Array.isArray(projectionEntry)) {
|
|
791
813
|
if (projectionEntry.length < 1) {
|
|
792
|
-
throw
|
|
814
|
+
throw frontendModelQueryError(`Invalid ${label} definition for "${projectionKey}": empty array`)
|
|
793
815
|
}
|
|
794
816
|
|
|
795
817
|
for (const nestedProjectionEntry of projectionEntry) {
|
|
796
818
|
if (typeof nestedProjectionEntry !== "string") {
|
|
797
|
-
throw
|
|
819
|
+
throw frontendModelQueryError(`Invalid ${label} definition for "${projectionKey}": expected string columns`)
|
|
798
820
|
}
|
|
799
821
|
|
|
800
822
|
normalized.push(parseString(nestedProjectionEntry, [...path, projectionKey]))
|
|
@@ -808,7 +830,7 @@ function normalizeColumnProjectionObject(value, path, parseString, label) {
|
|
|
808
830
|
continue
|
|
809
831
|
}
|
|
810
832
|
|
|
811
|
-
throw
|
|
833
|
+
throw frontendModelQueryError(`Invalid ${label} definition for "${projectionKey}": ${typeof projectionEntry}`)
|
|
812
834
|
}
|
|
813
835
|
|
|
814
836
|
return normalized
|
|
@@ -862,13 +884,13 @@ export function normalizeGroup(group) {
|
|
|
862
884
|
continue
|
|
863
885
|
}
|
|
864
886
|
|
|
865
|
-
throw
|
|
887
|
+
throw frontendModelQueryError(`Invalid group entry type: ${typeof groupEntry}`)
|
|
866
888
|
}
|
|
867
889
|
|
|
868
890
|
return normalized
|
|
869
891
|
}
|
|
870
892
|
|
|
871
|
-
throw
|
|
893
|
+
throw frontendModelQueryError(`Invalid group type: ${typeof group}`)
|
|
872
894
|
}
|
|
873
895
|
|
|
874
896
|
/**
|
|
@@ -881,7 +903,7 @@ function parsePluckString(pluckValue, path = []) {
|
|
|
881
903
|
const trimmed = pluckValue.trim()
|
|
882
904
|
|
|
883
905
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(trimmed)) {
|
|
884
|
-
throw
|
|
906
|
+
throw frontendModelQueryError(`Invalid pluck column: ${pluckValue}`)
|
|
885
907
|
}
|
|
886
908
|
|
|
887
909
|
return {
|
|
@@ -938,13 +960,13 @@ export function normalizePluck(pluck) {
|
|
|
938
960
|
continue
|
|
939
961
|
}
|
|
940
962
|
|
|
941
|
-
throw
|
|
963
|
+
throw frontendModelQueryError(`Invalid pluck entry type: ${typeof pluckEntry}`)
|
|
942
964
|
}
|
|
943
965
|
|
|
944
966
|
return normalized
|
|
945
967
|
}
|
|
946
968
|
|
|
947
|
-
throw
|
|
969
|
+
throw frontendModelQueryError(`Invalid pluck type: ${typeof pluck}`)
|
|
948
970
|
}
|
|
949
971
|
|
|
950
972
|
/**
|
|
@@ -997,13 +1019,13 @@ function frontendModelPluckTargetModelClass(modelClass, path) {
|
|
|
997
1019
|
}
|
|
998
1020
|
|
|
999
1021
|
/**
|
|
1000
|
-
* Runs
|
|
1001
|
-
* @param {object} args - Pluck
|
|
1022
|
+
* Runs assert pluck definitions allowed.
|
|
1023
|
+
* @param {object} args - Pluck assertion args.
|
|
1002
1024
|
* @param {import("./base.js").FrontendModelClass} args.modelClass - Root model class.
|
|
1003
1025
|
* @param {FrontendModelPluck[]} args.pluck - Pluck descriptors.
|
|
1004
|
-
* @returns {FrontendModelPluck[]} -
|
|
1026
|
+
* @returns {FrontendModelPluck[]} - Allowed pluck descriptors.
|
|
1005
1027
|
*/
|
|
1006
|
-
function
|
|
1028
|
+
function assertPluckDefinitionsAllowed({modelClass, pluck}) {
|
|
1007
1029
|
return pluck.map((pluckEntry) => {
|
|
1008
1030
|
const targetModelClass = frontendModelPluckTargetModelClass(modelClass, pluckEntry.path)
|
|
1009
1031
|
const targetAttributes = frontendModelResourceAttributes(targetModelClass)
|
|
@@ -1036,7 +1058,7 @@ function serializeFindConditions(conditions) {
|
|
|
1036
1058
|
* Runs normalize integer argument.
|
|
1037
1059
|
* @param {?} value - Candidate integer value.
|
|
1038
1060
|
* @param {string} argumentName - Argument name for errors.
|
|
1039
|
-
* @param {object} options -
|
|
1061
|
+
* @param {object} options - Integer options.
|
|
1040
1062
|
* @param {number} options.min - Minimum allowed value.
|
|
1041
1063
|
* @returns {number} - Normalized integer value.
|
|
1042
1064
|
*/
|
|
@@ -1961,7 +1983,7 @@ export default class FrontendModelQuery {
|
|
|
1961
1983
|
}
|
|
1962
1984
|
|
|
1963
1985
|
const normalizedPluck = normalizePluck(columns.length === 1 ? columns[0] : columns)
|
|
1964
|
-
const
|
|
1986
|
+
const allowedPluck = assertPluckDefinitionsAllowed({
|
|
1965
1987
|
modelClass: this.modelClass,
|
|
1966
1988
|
pluck: normalizedPluck
|
|
1967
1989
|
})
|
|
@@ -1973,7 +1995,7 @@ export default class FrontendModelQuery {
|
|
|
1973
1995
|
...this.sortPayload(),
|
|
1974
1996
|
...this.wherePayload(),
|
|
1975
1997
|
...this.paginationPayload(),
|
|
1976
|
-
pluck:
|
|
1998
|
+
pluck: allowedPluck
|
|
1977
1999
|
})
|
|
1978
2000
|
|
|
1979
2001
|
if (!response || typeof response !== "object") {
|
package/src/utils/ransack.js
CHANGED
|
@@ -4,6 +4,28 @@ import * as inflection from "inflection"
|
|
|
4
4
|
import {isPlainObject} from "is-plain-object"
|
|
5
5
|
import {resolveFrontendModelClass} from "../frontend-models/model-registry.js"
|
|
6
6
|
|
|
7
|
+
/** Error raised when a Ransack descriptor is malformed. */
|
|
8
|
+
export class RansackQueryError extends Error {
|
|
9
|
+
/**
|
|
10
|
+
* Creates a Ransack query error.
|
|
11
|
+
* @param {string} message - Error message.
|
|
12
|
+
*/
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message)
|
|
15
|
+
|
|
16
|
+
this.name = "RansackQueryError"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Builds a Ransack query error.
|
|
22
|
+
* @param {string} message - Error message.
|
|
23
|
+
* @returns {RansackQueryError} - Ransack query error.
|
|
24
|
+
*/
|
|
25
|
+
function ransackQueryError(message) {
|
|
26
|
+
return new RansackQueryError(message)
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
/**
|
|
8
30
|
* RansackPredicate type.
|
|
9
31
|
* @typedef {"cont" | "end" | "eq" | "gt" | "gteq" | "in" | "lt" | "lteq" | "not_eq" | "not_in" | "null" | "start"} RansackPredicate
|
|
@@ -76,7 +98,7 @@ export function normalizeRansackParams(modelClass, params) {
|
|
|
76
98
|
*/
|
|
77
99
|
export function normalizeRansackGroup(modelClass, params) {
|
|
78
100
|
if (!isPlainObject(params)) {
|
|
79
|
-
throw
|
|
101
|
+
throw ransackQueryError(`ransack params must be a plain object, got: ${typeof params}`)
|
|
80
102
|
}
|
|
81
103
|
|
|
82
104
|
/**
|
|
@@ -124,7 +146,7 @@ function normalizeSimpleRansackCondition({key, modelClass, rawValue}) {
|
|
|
124
146
|
const parsedKey = parseRansackKey(key)
|
|
125
147
|
|
|
126
148
|
if (!parsedKey) {
|
|
127
|
-
throw
|
|
149
|
+
throw ransackQueryError(`Unsupported ransack predicate in key: ${key}`)
|
|
128
150
|
}
|
|
129
151
|
|
|
130
152
|
const value = normalizeRansackValue({
|
|
@@ -159,17 +181,17 @@ function normalizeAdvancedRansackConditions({modelClass, value}) {
|
|
|
159
181
|
|
|
160
182
|
for (const entry of normalizeRansackCollection(value, "conditions")) {
|
|
161
183
|
if (!isPlainObject(entry)) {
|
|
162
|
-
throw
|
|
184
|
+
throw ransackQueryError(`Ransack condition entries must be plain objects, got: ${typeof entry}`)
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
const predicateValue = entry.p
|
|
166
188
|
|
|
167
189
|
if (typeof predicateValue !== "string") {
|
|
168
|
-
throw
|
|
190
|
+
throw ransackQueryError("Ransack condition predicate must be a string")
|
|
169
191
|
}
|
|
170
192
|
|
|
171
193
|
if (!supportedPredicates.includes(predicateValue)) {
|
|
172
|
-
throw
|
|
194
|
+
throw ransackQueryError(`Unsupported ransack predicate in condition: ${predicateValue}`)
|
|
173
195
|
}
|
|
174
196
|
|
|
175
197
|
const predicate = /** @type {RansackPredicate} */ (predicateValue)
|
|
@@ -206,7 +228,7 @@ function normalizeAdvancedRansackGroups({modelClass, value}) {
|
|
|
206
228
|
|
|
207
229
|
for (const entry of normalizeRansackCollection(value, "groupings")) {
|
|
208
230
|
if (!isPlainObject(entry)) {
|
|
209
|
-
throw
|
|
231
|
+
throw ransackQueryError(`Ransack grouping entries must be plain objects, got: ${typeof entry}`)
|
|
210
232
|
}
|
|
211
233
|
|
|
212
234
|
groupings.push(normalizeRansackGroup(modelClass, entry))
|
|
@@ -225,7 +247,7 @@ function normalizeRansackCombinator(value, defaultValue) {
|
|
|
225
247
|
if (value === undefined || value === null || value === "") return defaultValue
|
|
226
248
|
if (value === "and" || value === "or") return value
|
|
227
249
|
|
|
228
|
-
throw
|
|
250
|
+
throw ransackQueryError(`Invalid ransack combinator: ${String(value)}`)
|
|
229
251
|
}
|
|
230
252
|
|
|
231
253
|
/**
|
|
@@ -253,7 +275,7 @@ function normalizeRansackCollection(value, name) {
|
|
|
253
275
|
.map((key) => value[key])
|
|
254
276
|
}
|
|
255
277
|
|
|
256
|
-
throw
|
|
278
|
+
throw ransackQueryError(`Ransack ${name} must be an array or object, got: ${typeof value}`)
|
|
257
279
|
}
|
|
258
280
|
|
|
259
281
|
/**
|
|
@@ -292,7 +314,7 @@ function resolveRansackAttributesFromAdvancedValue({modelClass, value}) {
|
|
|
292
314
|
}
|
|
293
315
|
|
|
294
316
|
if (attributes.length < 1) {
|
|
295
|
-
throw
|
|
317
|
+
throw ransackQueryError("Ransack condition must include at least one attribute")
|
|
296
318
|
}
|
|
297
319
|
|
|
298
320
|
return attributes
|
|
@@ -314,7 +336,7 @@ function normalizeAdvancedAttributeValues(value) {
|
|
|
314
336
|
return normalizeRansackCollection(value, "attributes").map((entry) => normalizeAdvancedAttributeValue(entry))
|
|
315
337
|
}
|
|
316
338
|
|
|
317
|
-
throw
|
|
339
|
+
throw ransackQueryError(`Ransack condition attributes must be strings, arrays, or objects, got: ${typeof value}`)
|
|
318
340
|
}
|
|
319
341
|
|
|
320
342
|
/**
|
|
@@ -329,7 +351,7 @@ function normalizeAdvancedAttributeValue(value) {
|
|
|
329
351
|
return value.name
|
|
330
352
|
}
|
|
331
353
|
|
|
332
|
-
throw
|
|
354
|
+
throw ransackQueryError(`Ransack condition attribute entries must be strings or {name}, got: ${typeof value}`)
|
|
333
355
|
}
|
|
334
356
|
|
|
335
357
|
/**
|
|
@@ -346,7 +368,7 @@ function resolveRansackAttributes({modelClass, value}) {
|
|
|
346
368
|
const attributeName = resolveAttributeName({modelClass: targetModelClass, value: resolvedPath.attributeValue})
|
|
347
369
|
|
|
348
370
|
if (!attributeName) {
|
|
349
|
-
throw
|
|
371
|
+
throw ransackQueryError(`Unknown ransack attribute "${resolvedPath.attributeValue}" for ${targetModelClass.name}`)
|
|
350
372
|
}
|
|
351
373
|
|
|
352
374
|
return {
|
|
@@ -370,7 +392,7 @@ function modelClassAtPath({modelClass, path}) {
|
|
|
370
392
|
const relationship = relationshipEntries(currentModelClass)[relationshipName]
|
|
371
393
|
|
|
372
394
|
if (!relationship) {
|
|
373
|
-
throw
|
|
395
|
+
throw ransackQueryError(`Unknown ransack relationship "${relationshipName}" for ${currentModelClass.name}`)
|
|
374
396
|
}
|
|
375
397
|
|
|
376
398
|
currentModelClass = relationship.targetModelClass
|
|
@@ -412,7 +434,7 @@ function resolveRansackPath({modelClass, value}) {
|
|
|
412
434
|
}
|
|
413
435
|
|
|
414
436
|
if (remainingValue.length < 1) {
|
|
415
|
-
throw
|
|
437
|
+
throw ransackQueryError(`Invalid ransack key path: ${value}`)
|
|
416
438
|
}
|
|
417
439
|
|
|
418
440
|
return {
|
|
@@ -648,7 +670,7 @@ function parseRansackKey(key) {
|
|
|
648
670
|
const pathValue = key.slice(0, key.length - suffix.length)
|
|
649
671
|
|
|
650
672
|
if (pathValue.length < 1) {
|
|
651
|
-
throw
|
|
673
|
+
throw ransackQueryError(`Invalid ransack key: ${key}`)
|
|
652
674
|
}
|
|
653
675
|
|
|
654
676
|
return {
|
|
@@ -665,7 +687,7 @@ function parseRansackKey(key) {
|
|
|
665
687
|
const pathValue = key.slice(0, key.length - camelSuffix.length)
|
|
666
688
|
|
|
667
689
|
if (pathValue.length < 1) {
|
|
668
|
-
throw
|
|
690
|
+
throw ransackQueryError(`Invalid ransack key: ${key}`)
|
|
669
691
|
}
|
|
670
692
|
|
|
671
693
|
return {
|
|
@@ -750,7 +772,7 @@ function normalizeRansackBoolean(value) {
|
|
|
750
772
|
if (ransackFalseValues.has(value)) return false
|
|
751
773
|
if (ransackValueIsBlank(value)) return null
|
|
752
774
|
|
|
753
|
-
throw
|
|
775
|
+
throw ransackQueryError(`Invalid ransack boolean value: ${String(value)}`)
|
|
754
776
|
}
|
|
755
777
|
|
|
756
778
|
/**
|
|
@@ -789,10 +811,10 @@ function normalizeRansackArray(value) {
|
|
|
789
811
|
*/
|
|
790
812
|
|
|
791
813
|
/**
|
|
792
|
-
* Parses
|
|
793
|
-
* @param {RansackModelClass} modelClass - Model class for attribute
|
|
814
|
+
* Parses a ransack `s` sort string against model attributes.
|
|
815
|
+
* @param {RansackModelClass} modelClass - Model class for attribute lookup.
|
|
794
816
|
* @param {string} sortString - Ransack sort string (e.g., "name asc" or "name asc, createdAt desc").
|
|
795
|
-
* @returns {RansackSort[]} -
|
|
817
|
+
* @returns {RansackSort[]} - Parsed sort definitions.
|
|
796
818
|
*/
|
|
797
819
|
export function parseRansackSort(modelClass, sortString) {
|
|
798
820
|
const segments = sortString.split(",").map((segment) => segment.trim()).filter((segment) => segment.length > 0)
|
|
@@ -808,13 +830,13 @@ export function parseRansackSort(modelClass, sortString) {
|
|
|
808
830
|
const directionCandidate = parts.length > 1 ? parts[1].toLowerCase() : "asc"
|
|
809
831
|
|
|
810
832
|
if (directionCandidate !== "asc" && directionCandidate !== "desc") {
|
|
811
|
-
throw
|
|
833
|
+
throw ransackQueryError(`Invalid ransack sort direction "${directionCandidate}" in: ${segment}`)
|
|
812
834
|
}
|
|
813
835
|
|
|
814
836
|
const resolvedAttribute = resolveAttributeName({modelClass, value: columnCandidate})
|
|
815
837
|
|
|
816
838
|
if (!resolvedAttribute) {
|
|
817
|
-
throw
|
|
839
|
+
throw ransackQueryError(`Unknown ransack sort attribute "${columnCandidate}" for ${modelClass.name}`)
|
|
818
840
|
}
|
|
819
841
|
|
|
820
842
|
sorts.push({attribute: resolvedAttribute, direction: directionCandidate})
|