@expo/entity-database-adapter-knex 0.59.0 → 0.60.0
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/build/src/SQLOperator.d.ts +101 -2
- package/build/src/SQLOperator.js +248 -42
- package/build/src/SQLOperator.js.map +1 -1
- package/build/src/internal/EntityKnexDataManager.js +2 -2
- package/build/src/internal/EntityKnexDataManager.js.map +1 -1
- package/package.json +4 -4
- package/src/SQLOperator.ts +307 -44
- package/src/__integration-tests__/PostgresEntityIntegration-test.ts +27 -0
- package/src/__tests__/SQLOperator-test.ts +388 -5
- package/src/internal/EntityKnexDataManager.ts +2 -2
|
@@ -8,9 +8,11 @@ import {
|
|
|
8
8
|
unsafeRaw,
|
|
9
9
|
sql,
|
|
10
10
|
SQLEntityField,
|
|
11
|
+
SQLExpression,
|
|
11
12
|
SQLFragment,
|
|
12
13
|
SQLFragmentHelpers,
|
|
13
14
|
SQLIdentifier,
|
|
15
|
+
expression,
|
|
14
16
|
} from '../SQLOperator';
|
|
15
17
|
import { TestFields, testEntityConfiguration } from './fixtures/TestEntity';
|
|
16
18
|
|
|
@@ -497,7 +499,7 @@ describe('SQLOperator', () => {
|
|
|
497
499
|
it('handles empty array', () => {
|
|
498
500
|
const fragment = SQLFragmentHelpers.inArray('stringField', []);
|
|
499
501
|
|
|
500
|
-
expect(fragment.sql).toBe('
|
|
502
|
+
expect(fragment.sql).toBe('FALSE'); // Always false
|
|
501
503
|
expect(fragment.getKnexBindings(getColumnForField)).toEqual([]);
|
|
502
504
|
});
|
|
503
505
|
});
|
|
@@ -517,7 +519,7 @@ describe('SQLOperator', () => {
|
|
|
517
519
|
it('handles empty array', () => {
|
|
518
520
|
const fragment = SQLFragmentHelpers.notInArray('stringField', []);
|
|
519
521
|
|
|
520
|
-
expect(fragment.sql).toBe('
|
|
522
|
+
expect(fragment.sql).toBe('TRUE'); // Always true
|
|
521
523
|
expect(fragment.getKnexBindings(getColumnForField)).toEqual([]);
|
|
522
524
|
});
|
|
523
525
|
});
|
|
@@ -536,7 +538,7 @@ describe('SQLOperator', () => {
|
|
|
536
538
|
it('handles empty array', () => {
|
|
537
539
|
const fragment = SQLFragmentHelpers.anyArray('stringField', []);
|
|
538
540
|
|
|
539
|
-
expect(fragment.sql).toBe('
|
|
541
|
+
expect(fragment.sql).toBe('FALSE'); // Always false
|
|
540
542
|
expect(fragment.getKnexBindings(getColumnForField)).toEqual([]);
|
|
541
543
|
});
|
|
542
544
|
});
|
|
@@ -829,7 +831,7 @@ describe('SQLOperator', () => {
|
|
|
829
831
|
it('handles empty conditions in AND', () => {
|
|
830
832
|
const fragment = SQLFragmentHelpers.and();
|
|
831
833
|
|
|
832
|
-
expect(fragment.sql).toBe('
|
|
834
|
+
expect(fragment.sql).toBe('TRUE');
|
|
833
835
|
expect(fragment.getKnexBindings(getColumnForField)).toEqual([]);
|
|
834
836
|
});
|
|
835
837
|
});
|
|
@@ -855,7 +857,7 @@ describe('SQLOperator', () => {
|
|
|
855
857
|
it('handles empty conditions in OR', () => {
|
|
856
858
|
const fragment = SQLFragmentHelpers.or();
|
|
857
859
|
|
|
858
|
-
expect(fragment.sql).toBe('
|
|
860
|
+
expect(fragment.sql).toBe('FALSE');
|
|
859
861
|
expect(fragment.getKnexBindings(getColumnForField)).toEqual([]);
|
|
860
862
|
});
|
|
861
863
|
});
|
|
@@ -908,5 +910,386 @@ describe('SQLOperator', () => {
|
|
|
908
910
|
]);
|
|
909
911
|
});
|
|
910
912
|
});
|
|
913
|
+
|
|
914
|
+
describe(expression, () => {
|
|
915
|
+
it('wraps a field name into an SQLExpression', () => {
|
|
916
|
+
const fragment = expression<TestFields>('stringField').eq('active');
|
|
917
|
+
|
|
918
|
+
expect(fragment.sql).toBe('?? = ?');
|
|
919
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'active']);
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
it('wraps a SQLFragment into an SQLExpression', () => {
|
|
923
|
+
const raw = sql<TestFields>`LOWER(${entityField<TestFields>('stringField')})`;
|
|
924
|
+
const fragment = expression(raw).eq('test');
|
|
925
|
+
|
|
926
|
+
expect(fragment.sql).toBe('LOWER(??) = ?');
|
|
927
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'test']);
|
|
928
|
+
});
|
|
929
|
+
});
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
describe(SQLExpression, () => {
|
|
933
|
+
// Use a simple expression for testing all fluent methods.
|
|
934
|
+
// Since fluent methods live on SQLExpression and behave identically regardless of
|
|
935
|
+
// how the expression was constructed, we only need to test them once.
|
|
936
|
+
const makeStringFieldExpr = (): SQLExpression<TestFields> =>
|
|
937
|
+
expression<TestFields>('stringField');
|
|
938
|
+
|
|
939
|
+
describe('comparison methods', () => {
|
|
940
|
+
it('eq(value)', () => {
|
|
941
|
+
const fragment = makeStringFieldExpr().eq('active');
|
|
942
|
+
expect(fragment.sql).toBe('?? = ?');
|
|
943
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'active']);
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
it('eq(null) uses IS NULL', () => {
|
|
947
|
+
const fragment = makeStringFieldExpr().eq(null);
|
|
948
|
+
expect(fragment.sql).toBe('?? IS NULL');
|
|
949
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
it('eq(undefined) uses IS NULL', () => {
|
|
953
|
+
const fragment = makeStringFieldExpr().eq(undefined);
|
|
954
|
+
expect(fragment.sql).toBe('?? IS NULL');
|
|
955
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
it('neq(value)', () => {
|
|
959
|
+
const fragment = makeStringFieldExpr().neq('deleted');
|
|
960
|
+
expect(fragment.sql).toBe('?? != ?');
|
|
961
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'deleted']);
|
|
962
|
+
});
|
|
963
|
+
|
|
964
|
+
it('neq(null) uses IS NOT NULL', () => {
|
|
965
|
+
const fragment = makeStringFieldExpr().neq(null);
|
|
966
|
+
expect(fragment.sql).toBe('?? IS NOT NULL');
|
|
967
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
it('neq(undefined) uses IS NOT NULL', () => {
|
|
971
|
+
const fragment = makeStringFieldExpr().neq(undefined);
|
|
972
|
+
expect(fragment.sql).toBe('?? IS NOT NULL');
|
|
973
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
it('gt(value)', () => {
|
|
977
|
+
const fragment = makeStringFieldExpr().gt(10);
|
|
978
|
+
expect(fragment.sql).toBe('?? > ?');
|
|
979
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 10]);
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
it('gte(value)', () => {
|
|
983
|
+
const fragment = makeStringFieldExpr().gte(10);
|
|
984
|
+
expect(fragment.sql).toBe('?? >= ?');
|
|
985
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 10]);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
it('lt(value)', () => {
|
|
989
|
+
const fragment = makeStringFieldExpr().lt(100);
|
|
990
|
+
expect(fragment.sql).toBe('?? < ?');
|
|
991
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 100]);
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
it('lte(value)', () => {
|
|
995
|
+
const fragment = makeStringFieldExpr().lte(100);
|
|
996
|
+
expect(fragment.sql).toBe('?? <= ?');
|
|
997
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 100]);
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
it('isNull()', () => {
|
|
1001
|
+
const fragment = makeStringFieldExpr().isNull();
|
|
1002
|
+
expect(fragment.sql).toBe('?? IS NULL');
|
|
1003
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
it('isNotNull()', () => {
|
|
1007
|
+
const fragment = makeStringFieldExpr().isNotNull();
|
|
1008
|
+
expect(fragment.sql).toBe('?? IS NOT NULL');
|
|
1009
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
1010
|
+
});
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
describe('pattern matching methods', () => {
|
|
1014
|
+
it('like(pattern)', () => {
|
|
1015
|
+
const fragment = makeStringFieldExpr().like('%test%');
|
|
1016
|
+
expect(fragment.sql).toBe('?? LIKE ?');
|
|
1017
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', '%test%']);
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
it('notLike(pattern)', () => {
|
|
1021
|
+
const fragment = makeStringFieldExpr().notLike('%test%');
|
|
1022
|
+
expect(fragment.sql).toBe('?? NOT LIKE ?');
|
|
1023
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', '%test%']);
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
it('ilike(pattern)', () => {
|
|
1027
|
+
const fragment = makeStringFieldExpr().ilike('%test%');
|
|
1028
|
+
expect(fragment.sql).toBe('?? ILIKE ?');
|
|
1029
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', '%test%']);
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
it('notIlike(pattern)', () => {
|
|
1033
|
+
const fragment = makeStringFieldExpr().notIlike('%test%');
|
|
1034
|
+
expect(fragment.sql).toBe('?? NOT ILIKE ?');
|
|
1035
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', '%test%']);
|
|
1036
|
+
});
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
describe('collection methods', () => {
|
|
1040
|
+
it('inArray(values)', () => {
|
|
1041
|
+
const fragment = makeStringFieldExpr().inArray(['a', 'b']);
|
|
1042
|
+
expect(fragment.sql).toBe('?? IN (?, ?)');
|
|
1043
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'a', 'b']);
|
|
1044
|
+
});
|
|
1045
|
+
|
|
1046
|
+
it('inArray([]) returns always-false', () => {
|
|
1047
|
+
const fragment = makeStringFieldExpr().inArray([]);
|
|
1048
|
+
expect(fragment.sql).toBe('FALSE');
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
it('notInArray(values)', () => {
|
|
1052
|
+
const fragment = makeStringFieldExpr().notInArray(['x']);
|
|
1053
|
+
expect(fragment.sql).toBe('?? NOT IN (?)');
|
|
1054
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'x']);
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
it('notInArray([]) returns always-true', () => {
|
|
1058
|
+
const fragment = makeStringFieldExpr().notInArray([]);
|
|
1059
|
+
expect(fragment.sql).toBe('TRUE');
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
it('anyArray(values)', () => {
|
|
1063
|
+
const fragment = makeStringFieldExpr().anyArray(['a', 'b']);
|
|
1064
|
+
expect(fragment.sql).toBe('?? = ANY(?)');
|
|
1065
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', ['a', 'b']]);
|
|
1066
|
+
});
|
|
1067
|
+
|
|
1068
|
+
it('anyArray([]) returns always-false', () => {
|
|
1069
|
+
const fragment = makeStringFieldExpr().anyArray([]);
|
|
1070
|
+
expect(fragment.sql).toBe('FALSE');
|
|
1071
|
+
});
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
describe('range methods', () => {
|
|
1075
|
+
it('between(min, max)', () => {
|
|
1076
|
+
const fragment = makeStringFieldExpr().between(1, 100);
|
|
1077
|
+
expect(fragment.sql).toBe('?? BETWEEN ? AND ?');
|
|
1078
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 1, 100]);
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
it('notBetween(min, max)', () => {
|
|
1082
|
+
const fragment = makeStringFieldExpr().notBetween(1, 100);
|
|
1083
|
+
expect(fragment.sql).toBe('?? NOT BETWEEN ? AND ?');
|
|
1084
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 1, 100]);
|
|
1085
|
+
});
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
describe('helpers that return SQLExpression', () => {
|
|
1089
|
+
it('jsonPath returns an SQLExpression with correct base SQL', () => {
|
|
1090
|
+
const expr = SQLFragmentHelpers.jsonPath<TestFields>('stringField', 'key');
|
|
1091
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1092
|
+
expect(expr.sql).toBe('??->?');
|
|
1093
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual(['string_field', 'key']);
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
it('jsonPathText returns an SQLExpression with correct base SQL', () => {
|
|
1097
|
+
const expr = SQLFragmentHelpers.jsonPathText<TestFields>('stringField', 'email');
|
|
1098
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1099
|
+
expect(expr.sql).toBe('??->>?');
|
|
1100
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual(['string_field', 'email']);
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
it('jsonDeepPath returns an SQLExpression with correct base SQL', () => {
|
|
1104
|
+
const expr = SQLFragmentHelpers.jsonDeepPath<TestFields>('stringField', [
|
|
1105
|
+
'user',
|
|
1106
|
+
'address',
|
|
1107
|
+
'city',
|
|
1108
|
+
]);
|
|
1109
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1110
|
+
expect(expr.sql).toBe('?? #> ?');
|
|
1111
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual([
|
|
1112
|
+
'string_field',
|
|
1113
|
+
'{user,address,city}',
|
|
1114
|
+
]);
|
|
1115
|
+
});
|
|
1116
|
+
|
|
1117
|
+
it('jsonDeepPath properly quotes path elements with special characters', () => {
|
|
1118
|
+
const fragment = SQLFragmentHelpers.jsonDeepPath<TestFields>('stringField', [
|
|
1119
|
+
'user',
|
|
1120
|
+
'first,last',
|
|
1121
|
+
'na}me',
|
|
1122
|
+
]);
|
|
1123
|
+
|
|
1124
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual([
|
|
1125
|
+
'string_field',
|
|
1126
|
+
'{user,"first,last","na}me"}',
|
|
1127
|
+
]);
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
it('jsonDeepPath properly quotes empty path elements', () => {
|
|
1131
|
+
const fragment = SQLFragmentHelpers.jsonDeepPath<TestFields>('stringField', ['user', '']);
|
|
1132
|
+
|
|
1133
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', '{user,""}']);
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
it('jsonDeepPath properly escapes quotes and backslashes in path elements', () => {
|
|
1137
|
+
const fragment = SQLFragmentHelpers.jsonDeepPath<TestFields>('stringField', [
|
|
1138
|
+
'key"with"quotes',
|
|
1139
|
+
'back\\slash',
|
|
1140
|
+
]);
|
|
1141
|
+
|
|
1142
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual([
|
|
1143
|
+
'string_field',
|
|
1144
|
+
'{"key\\"with\\"quotes","back\\\\slash"}',
|
|
1145
|
+
]);
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
it('jsonDeepPathText returns an SQLExpression with correct base SQL', () => {
|
|
1149
|
+
const expr = SQLFragmentHelpers.jsonDeepPathText<TestFields>('stringField', [
|
|
1150
|
+
'user',
|
|
1151
|
+
'address',
|
|
1152
|
+
'city',
|
|
1153
|
+
]);
|
|
1154
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1155
|
+
expect(expr.sql).toBe('?? #>> ?');
|
|
1156
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual([
|
|
1157
|
+
'string_field',
|
|
1158
|
+
'{user,address,city}',
|
|
1159
|
+
]);
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
it('cast returns an SQLExpression with correct base SQL', () => {
|
|
1163
|
+
const jsonExpr = SQLFragmentHelpers.jsonPath<TestFields>('stringField', 'count');
|
|
1164
|
+
const expr = SQLFragmentHelpers.cast(jsonExpr, 'int');
|
|
1165
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1166
|
+
expect(expr.sql).toBe('(??->?)::int');
|
|
1167
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual(['string_field', 'count']);
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
it('cast rejects unsupported type names', () => {
|
|
1171
|
+
const expr = SQLFragmentHelpers.jsonPath<TestFields>('stringField', 'count');
|
|
1172
|
+
expect(() => SQLFragmentHelpers.cast(expr, 'int; DROP TABLE users' as any)).toThrow(
|
|
1173
|
+
'cast: unsupported type name',
|
|
1174
|
+
);
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
it('coalesce returns an SQLExpression with correct base SQL', () => {
|
|
1178
|
+
const expr = SQLFragmentHelpers.coalesce<TestFields>(
|
|
1179
|
+
sql`${entityField<TestFields>('nullableField')}`,
|
|
1180
|
+
'default',
|
|
1181
|
+
);
|
|
1182
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1183
|
+
expect(expr.sql).toBe('COALESCE(??, ?)');
|
|
1184
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual(['nullable_field', 'default']);
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
it('coalesce with multiple expressions', () => {
|
|
1188
|
+
const fragment = SQLFragmentHelpers.coalesce<TestFields>(
|
|
1189
|
+
sql`${entityField<TestFields>('nullableField')}`,
|
|
1190
|
+
sql`${entityField<TestFields>('stringField')}`,
|
|
1191
|
+
'fallback',
|
|
1192
|
+
);
|
|
1193
|
+
expect(fragment.sql).toBe('COALESCE(??, ??, ?)');
|
|
1194
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual([
|
|
1195
|
+
'nullable_field',
|
|
1196
|
+
'string_field',
|
|
1197
|
+
'fallback',
|
|
1198
|
+
]);
|
|
1199
|
+
});
|
|
1200
|
+
|
|
1201
|
+
it('lower returns an SQLExpression with correct base SQL', () => {
|
|
1202
|
+
const expr = SQLFragmentHelpers.lower<TestFields>('stringField');
|
|
1203
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1204
|
+
expect(expr.sql).toBe('LOWER(??)');
|
|
1205
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
it('lower accepts a SQLFragment', () => {
|
|
1209
|
+
const fragment = SQLFragmentHelpers.lower(
|
|
1210
|
+
SQLFragmentHelpers.jsonPathText<TestFields>('stringField', 'email'),
|
|
1211
|
+
);
|
|
1212
|
+
expect(fragment.sql).toBe('LOWER(??->>?)');
|
|
1213
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'email']);
|
|
1214
|
+
});
|
|
1215
|
+
|
|
1216
|
+
it('upper returns an SQLExpression with correct base SQL', () => {
|
|
1217
|
+
const expr = SQLFragmentHelpers.upper<TestFields>('stringField');
|
|
1218
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1219
|
+
expect(expr.sql).toBe('UPPER(??)');
|
|
1220
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
1221
|
+
});
|
|
1222
|
+
|
|
1223
|
+
it('upper accepts a SQLFragment', () => {
|
|
1224
|
+
const fragment = SQLFragmentHelpers.upper(
|
|
1225
|
+
SQLFragmentHelpers.jsonPathText<TestFields>('stringField', 'email'),
|
|
1226
|
+
);
|
|
1227
|
+
expect(fragment.sql).toBe('UPPER(??->>?)');
|
|
1228
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'email']);
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
it('trim returns an SQLExpression with correct base SQL', () => {
|
|
1232
|
+
const expr = SQLFragmentHelpers.trim<TestFields>('stringField');
|
|
1233
|
+
expect(expr).toBeInstanceOf(SQLExpression);
|
|
1234
|
+
expect(expr.sql).toBe('TRIM(??)');
|
|
1235
|
+
expect(expr.getKnexBindings(getColumnForField)).toEqual(['string_field']);
|
|
1236
|
+
});
|
|
1237
|
+
|
|
1238
|
+
it('trim accepts a SQLFragment', () => {
|
|
1239
|
+
const fragment = SQLFragmentHelpers.trim(
|
|
1240
|
+
SQLFragmentHelpers.jsonPathText<TestFields>('stringField', 'name'),
|
|
1241
|
+
);
|
|
1242
|
+
expect(fragment.sql).toBe('TRIM(??->>?)');
|
|
1243
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'name']);
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
it('SQLExpression still works as a SQLFragment in sql template', () => {
|
|
1247
|
+
const path = SQLFragmentHelpers.jsonPath<TestFields>('stringField', 'key');
|
|
1248
|
+
const fragment = sql`${path} IS NOT NULL`;
|
|
1249
|
+
|
|
1250
|
+
expect(fragment.sql).toBe('??->? IS NOT NULL');
|
|
1251
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'key']);
|
|
1252
|
+
});
|
|
1253
|
+
});
|
|
1254
|
+
|
|
1255
|
+
describe('composing multiple expression helpers', () => {
|
|
1256
|
+
it('lower(trim(field)).eq(value)', () => {
|
|
1257
|
+
const fragment = SQLFragmentHelpers.lower(
|
|
1258
|
+
SQLFragmentHelpers.trim<TestFields>('stringField'),
|
|
1259
|
+
).eq('hello');
|
|
1260
|
+
|
|
1261
|
+
expect(fragment.sql).toBe('LOWER(TRIM(??)) = ?');
|
|
1262
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual(['string_field', 'hello']);
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
it('cast(jsonDeepPath(...), type).gt(value)', () => {
|
|
1266
|
+
const fragment = SQLFragmentHelpers.cast(
|
|
1267
|
+
SQLFragmentHelpers.jsonDeepPath<TestFields>('stringField', ['stats', 'count']),
|
|
1268
|
+
'int',
|
|
1269
|
+
).gt(10);
|
|
1270
|
+
|
|
1271
|
+
expect(fragment.sql).toBe('(?? #> ?)::int > ?');
|
|
1272
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual([
|
|
1273
|
+
'string_field',
|
|
1274
|
+
'{stats,count}',
|
|
1275
|
+
10,
|
|
1276
|
+
]);
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
it('coalesce(jsonPathText(...), default).ilike(pattern)', () => {
|
|
1280
|
+
const fragment = SQLFragmentHelpers.coalesce(
|
|
1281
|
+
SQLFragmentHelpers.jsonPathText<TestFields>('stringField', 'name'),
|
|
1282
|
+
'',
|
|
1283
|
+
).ilike('%test%');
|
|
1284
|
+
|
|
1285
|
+
expect(fragment.sql).toBe('COALESCE(??->>?, ?) ILIKE ?');
|
|
1286
|
+
expect(fragment.getKnexBindings(getColumnForField)).toEqual([
|
|
1287
|
+
'string_field',
|
|
1288
|
+
'name',
|
|
1289
|
+
'',
|
|
1290
|
+
'%test%',
|
|
1291
|
+
]);
|
|
1292
|
+
});
|
|
1293
|
+
});
|
|
911
1294
|
});
|
|
912
1295
|
});
|
|
@@ -487,7 +487,7 @@ export class EntityKnexDataManager<
|
|
|
487
487
|
): SQLFragment<TFields> {
|
|
488
488
|
const conditions = [baseWhere, cursorCondition].filter((it) => !!it);
|
|
489
489
|
if (conditions.length === 0) {
|
|
490
|
-
return sql`
|
|
490
|
+
return sql`TRUE`;
|
|
491
491
|
}
|
|
492
492
|
if (conditions.length === 1) {
|
|
493
493
|
return conditions[0]!;
|
|
@@ -775,7 +775,7 @@ export class EntityKnexDataManager<
|
|
|
775
775
|
];
|
|
776
776
|
|
|
777
777
|
return {
|
|
778
|
-
searchWhere: conditions.length > 0 ? SQLFragmentHelpers.or(...conditions) : sql`
|
|
778
|
+
searchWhere: conditions.length > 0 ? SQLFragmentHelpers.or(...conditions) : sql`FALSE`,
|
|
779
779
|
searchOrderByClauses,
|
|
780
780
|
};
|
|
781
781
|
}
|