@slonik/sql-tag 40.2.2
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 -0
- package/dist/Logger.d.ts +2 -0
- package/dist/Logger.d.ts.map +1 -0
- package/dist/Logger.js +8 -0
- package/dist/Logger.js.map +1 -0
- package/dist/factories/createPrimitiveValueExpressions.d.ts +3 -0
- package/dist/factories/createPrimitiveValueExpressions.d.ts.map +1 -0
- package/dist/factories/createPrimitiveValueExpressions.js +33 -0
- package/dist/factories/createPrimitiveValueExpressions.js.map +1 -0
- package/dist/factories/createSqlTag.d.ts +38 -0
- package/dist/factories/createSqlTag.d.ts.map +1 -0
- package/dist/factories/createSqlTag.js +170 -0
- package/dist/factories/createSqlTag.js.map +1 -0
- package/dist/factories/createSqlTag.test/array.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/array.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/array.test.js +76 -0
- package/dist/factories/createSqlTag.test/array.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/date.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/date.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/date.test.js +25 -0
- package/dist/factories/createSqlTag.test/date.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/identifier.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/identifier.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/identifier.test.js +38 -0
- package/dist/factories/createSqlTag.test/identifier.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/interval.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/interval.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/interval.test.js +43 -0
- package/dist/factories/createSqlTag.test/interval.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/join.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/join.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/join.test.js +87 -0
- package/dist/factories/createSqlTag.test/join.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/json.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/json.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/json.test.js +88 -0
- package/dist/factories/createSqlTag.test/json.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/jsonb.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/jsonb.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/jsonb.test.js +88 -0
- package/dist/factories/createSqlTag.test/jsonb.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/literalValue.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/literalValue.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/literalValue.test.js +18 -0
- package/dist/factories/createSqlTag.test/literalValue.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/sql.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/sql.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/sql.test.js +138 -0
- package/dist/factories/createSqlTag.test/sql.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/timestamp.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/timestamp.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/timestamp.test.js +25 -0
- package/dist/factories/createSqlTag.test/timestamp.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/type.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/type.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/type.test.js +19 -0
- package/dist/factories/createSqlTag.test/type.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/typeAlias.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/typeAlias.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/typeAlias.test.js +47 -0
- package/dist/factories/createSqlTag.test/typeAlias.test.js.map +1 -0
- package/dist/factories/createSqlTag.test/unnest.test.d.ts +2 -0
- package/dist/factories/createSqlTag.test/unnest.test.d.ts.map +1 -0
- package/dist/factories/createSqlTag.test/unnest.test.js +127 -0
- package/dist/factories/createSqlTag.test/unnest.test.js.map +1 -0
- package/dist/factories/createSqlTokenSqlFragment.d.ts +3 -0
- package/dist/factories/createSqlTokenSqlFragment.d.ts.map +1 -0
- package/dist/factories/createSqlTokenSqlFragment.js +57 -0
- package/dist/factories/createSqlTokenSqlFragment.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/regexRules/slonikPlaceholderRegexRule.d.ts +2 -0
- package/dist/regexRules/slonikPlaceholderRegexRule.d.ts.map +1 -0
- package/dist/regexRules/slonikPlaceholderRegexRule.js +5 -0
- package/dist/regexRules/slonikPlaceholderRegexRule.js.map +1 -0
- package/dist/sqlFragmentFactories/createArraySqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createArraySqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createArraySqlFragment.js +48 -0
- package/dist/sqlFragmentFactories/createArraySqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createBinarySqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createBinarySqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createBinarySqlFragment.js +16 -0
- package/dist/sqlFragmentFactories/createBinarySqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createDateSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createDateSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createDateSqlFragment.js +16 -0
- package/dist/sqlFragmentFactories/createDateSqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.js +34 -0
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.js +21 -0
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.js +57 -0
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createJsonSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createJsonSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createJsonSqlFragment.js +49 -0
- package/dist/sqlFragmentFactories/createJsonSqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createListSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createListSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createListSqlFragment.js +38 -0
- package/dist/sqlFragmentFactories/createListSqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createQuerySqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createQuerySqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createQuerySqlFragment.js +34 -0
- package/dist/sqlFragmentFactories/createQuerySqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.js +18 -0
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.js.map +1 -0
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.d.ts +3 -0
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.d.ts.map +1 -0
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.js +81 -0
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.js.map +1 -0
- package/dist/tokens.d.ts +14 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +17 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +99 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utilities/countArrayDimensions.d.ts +2 -0
- package/dist/utilities/countArrayDimensions.d.ts.map +1 -0
- package/dist/utilities/countArrayDimensions.js +14 -0
- package/dist/utilities/countArrayDimensions.js.map +1 -0
- package/dist/utilities/countArrayDimensions.test.d.ts +2 -0
- package/dist/utilities/countArrayDimensions.test.d.ts.map +1 -0
- package/dist/utilities/countArrayDimensions.test.js +13 -0
- package/dist/utilities/countArrayDimensions.test.js.map +1 -0
- package/dist/utilities/escapeIdentifier.d.ts +5 -0
- package/dist/utilities/escapeIdentifier.d.ts.map +1 -0
- package/dist/utilities/escapeIdentifier.js +12 -0
- package/dist/utilities/escapeIdentifier.js.map +1 -0
- package/dist/utilities/escapeIdentifier.test.d.ts +2 -0
- package/dist/utilities/escapeIdentifier.test.d.ts.map +1 -0
- package/dist/utilities/escapeIdentifier.test.js +13 -0
- package/dist/utilities/escapeIdentifier.test.js.map +1 -0
- package/dist/utilities/escapeLiteralValue.d.ts +5 -0
- package/dist/utilities/escapeLiteralValue.d.ts.map +1 -0
- package/dist/utilities/escapeLiteralValue.js +29 -0
- package/dist/utilities/escapeLiteralValue.js.map +1 -0
- package/dist/utilities/escapeLiteralValue.test.d.ts +2 -0
- package/dist/utilities/escapeLiteralValue.test.d.ts.map +1 -0
- package/dist/utilities/escapeLiteralValue.test.js +14 -0
- package/dist/utilities/escapeLiteralValue.test.js.map +1 -0
- package/dist/utilities/formatSlonikPlaceholder.d.ts +14 -0
- package/dist/utilities/formatSlonikPlaceholder.d.ts.map +1 -0
- package/dist/utilities/formatSlonikPlaceholder.js +20 -0
- package/dist/utilities/formatSlonikPlaceholder.js.map +1 -0
- package/dist/utilities/hasOwnProperty.d.ts +6 -0
- package/dist/utilities/hasOwnProperty.d.ts.map +1 -0
- package/dist/utilities/hasOwnProperty.js +12 -0
- package/dist/utilities/hasOwnProperty.js.map +1 -0
- package/dist/utilities/isPlainObject.d.ts +2 -0
- package/dist/utilities/isPlainObject.d.ts.map +1 -0
- package/dist/utilities/isPlainObject.js +16 -0
- package/dist/utilities/isPlainObject.js.map +1 -0
- package/dist/utilities/isPrimitiveValueExpression.d.ts +2 -0
- package/dist/utilities/isPrimitiveValueExpression.d.ts.map +1 -0
- package/dist/utilities/isPrimitiveValueExpression.js +12 -0
- package/dist/utilities/isPrimitiveValueExpression.js.map +1 -0
- package/dist/utilities/isSqlToken.d.ts +3 -0
- package/dist/utilities/isSqlToken.d.ts.map +1 -0
- package/dist/utilities/isSqlToken.js +35 -0
- package/dist/utilities/isSqlToken.js.map +1 -0
- package/dist/utilities/safeStringify.d.ts +2 -0
- package/dist/utilities/safeStringify.d.ts.map +1 -0
- package/dist/utilities/safeStringify.js +18 -0
- package/dist/utilities/safeStringify.js.map +1 -0
- package/dist/utilities/stripArrayNotation.d.ts +2 -0
- package/dist/utilities/stripArrayNotation.d.ts.map +1 -0
- package/dist/utilities/stripArrayNotation.js +12 -0
- package/dist/utilities/stripArrayNotation.js.map +1 -0
- package/dist/utilities/stripArrayNotation.test.d.ts +2 -0
- package/dist/utilities/stripArrayNotation.test.d.ts.map +1 -0
- package/dist/utilities/stripArrayNotation.test.js +13 -0
- package/dist/utilities/stripArrayNotation.test.js.map +1 -0
- package/package.json +88 -0
- package/src/Logger.ts +5 -0
- package/src/declarations.d.ts +8 -0
- package/src/factories/createPrimitiveValueExpressions.ts +43 -0
- package/src/factories/createSqlTag.test/array.test.ts +107 -0
- package/src/factories/createSqlTag.test/date.test.ts +26 -0
- package/src/factories/createSqlTag.test/identifier.test.ts +39 -0
- package/src/factories/createSqlTag.test/interval.test.ts +44 -0
- package/src/factories/createSqlTag.test/join.test.ts +127 -0
- package/src/factories/createSqlTag.test/json.test.ts +106 -0
- package/src/factories/createSqlTag.test/jsonb.test.ts +106 -0
- package/src/factories/createSqlTag.test/literalValue.test.ts +17 -0
- package/src/factories/createSqlTag.test/sql.test.ts +165 -0
- package/src/factories/createSqlTag.test/timestamp.test.ts +29 -0
- package/src/factories/createSqlTag.test/type.test.ts +17 -0
- package/src/factories/createSqlTag.test/typeAlias.test.ts +53 -0
- package/src/factories/createSqlTag.test/unnest.test.ts +173 -0
- package/src/factories/createSqlTag.ts +256 -0
- package/src/factories/createSqlTokenSqlFragment.ts +60 -0
- package/src/index.ts +2 -0
- package/src/regexRules/slonikPlaceholderRegexRule.ts +1 -0
- package/src/sqlFragmentFactories/createArraySqlFragment.ts +67 -0
- package/src/sqlFragmentFactories/createBinarySqlFragment.ts +17 -0
- package/src/sqlFragmentFactories/createDateSqlFragment.ts +19 -0
- package/src/sqlFragmentFactories/createFragmentSqlFragment.ts +48 -0
- package/src/sqlFragmentFactories/createIdentifierSqlFragment.ts +24 -0
- package/src/sqlFragmentFactories/createIntervalSqlFragment.ts +71 -0
- package/src/sqlFragmentFactories/createJsonSqlFragment.ts +66 -0
- package/src/sqlFragmentFactories/createListSqlFragment.ts +48 -0
- package/src/sqlFragmentFactories/createQuerySqlFragment.ts +48 -0
- package/src/sqlFragmentFactories/createTimestampSqlFragment.ts +22 -0
- package/src/sqlFragmentFactories/createUnnestSqlFragment.ts +118 -0
- package/src/tokens.ts +14 -0
- package/src/types.ts +189 -0
- package/src/utilities/countArrayDimensions.test.ts +8 -0
- package/src/utilities/countArrayDimensions.ts +12 -0
- package/src/utilities/escapeIdentifier.test.ts +8 -0
- package/src/utilities/escapeIdentifier.ts +8 -0
- package/src/utilities/escapeLiteralValue.test.ts +9 -0
- package/src/utilities/escapeLiteralValue.ts +26 -0
- package/src/utilities/formatSlonikPlaceholder.ts +15 -0
- package/src/utilities/hasOwnProperty.ts +10 -0
- package/src/utilities/isPlainObject.ts +14 -0
- package/src/utilities/isPrimitiveValueExpression.ts +11 -0
- package/src/utilities/isSqlToken.ts +52 -0
- package/src/utilities/safeStringify.ts +25 -0
- package/src/utilities/stripArrayNotation.test.ts +8 -0
- package/src/utilities/stripArrayNotation.ts +9 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { FragmentToken } from '../../tokens';
|
|
2
|
+
import { createSqlTag } from '../createSqlTag';
|
|
3
|
+
import test from 'ava';
|
|
4
|
+
|
|
5
|
+
const sql = createSqlTag();
|
|
6
|
+
|
|
7
|
+
test('creates a list of values', (t) => {
|
|
8
|
+
const query = sql.fragment`SELECT (${sql.join([1, 2, 3], sql.fragment`, `)})`;
|
|
9
|
+
|
|
10
|
+
t.deepEqual(query, {
|
|
11
|
+
sql: 'SELECT ($slonik_1, $slonik_2, $slonik_3)',
|
|
12
|
+
type: FragmentToken,
|
|
13
|
+
values: [1, 2, 3],
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('creates a list of values using glue', (t) => {
|
|
18
|
+
const query = sql.fragment`SELECT ${sql.join(
|
|
19
|
+
[sql.fragment`TRUE`, sql.fragment`TRUE`],
|
|
20
|
+
sql.fragment` AND `,
|
|
21
|
+
)}`;
|
|
22
|
+
|
|
23
|
+
t.deepEqual(query, {
|
|
24
|
+
sql: 'SELECT TRUE AND TRUE',
|
|
25
|
+
type: FragmentToken,
|
|
26
|
+
values: [],
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('interpolates SQL tokens', (t) => {
|
|
31
|
+
const query = sql.fragment`SELECT (${sql.join(
|
|
32
|
+
[1, sql.fragment`foo`, 3],
|
|
33
|
+
sql.fragment`, `,
|
|
34
|
+
)})`;
|
|
35
|
+
|
|
36
|
+
t.deepEqual(query, {
|
|
37
|
+
sql: 'SELECT ($slonik_1, foo, $slonik_2)',
|
|
38
|
+
type: FragmentToken,
|
|
39
|
+
values: [1, 3],
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('interpolates SQL tokens with bound values', (t) => {
|
|
44
|
+
const query = sql.fragment`SELECT ${sql.join(
|
|
45
|
+
[1, sql.fragment`to_timestamp(${2}), ${3}`, 4],
|
|
46
|
+
sql.fragment`, `,
|
|
47
|
+
)}`;
|
|
48
|
+
|
|
49
|
+
t.deepEqual(query, {
|
|
50
|
+
sql: 'SELECT $slonik_1, to_timestamp($slonik_2), $slonik_3, $slonik_4',
|
|
51
|
+
type: FragmentToken,
|
|
52
|
+
values: [1, 2, 3, 4],
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('offsets positional parameter indexes', (t) => {
|
|
57
|
+
const query = sql.fragment`SELECT ${1}, ${sql.join(
|
|
58
|
+
[1, sql.fragment`to_timestamp(${2}), ${3}`, 4],
|
|
59
|
+
sql.fragment`, `,
|
|
60
|
+
)}, ${3}`;
|
|
61
|
+
|
|
62
|
+
t.deepEqual(query, {
|
|
63
|
+
sql: 'SELECT $slonik_1, $slonik_2, to_timestamp($slonik_3), $slonik_4, $slonik_5, $slonik_6',
|
|
64
|
+
type: FragmentToken,
|
|
65
|
+
values: [1, 1, 2, 3, 4, 3],
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('supports bigint', (t) => {
|
|
70
|
+
const query = sql.fragment`SELECT ${1n}, ${sql.join(
|
|
71
|
+
[sql.fragment`to_timestamp(${2n})`, 3n],
|
|
72
|
+
sql.fragment`, `,
|
|
73
|
+
)}, ${4n}`;
|
|
74
|
+
|
|
75
|
+
t.deepEqual(query, {
|
|
76
|
+
sql: 'SELECT $slonik_1, to_timestamp($slonik_2), $slonik_3, $slonik_4',
|
|
77
|
+
type: FragmentToken,
|
|
78
|
+
values: [1n, 2n, 3n, 4n],
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test('nests expressions', (t) => {
|
|
83
|
+
const query = sql.fragment`SELECT ${sql.join(
|
|
84
|
+
[
|
|
85
|
+
sql.fragment`(${sql.join([1, 2], sql.fragment`, `)})`,
|
|
86
|
+
sql.fragment`(${sql.join([3, 4], sql.fragment`, `)})`,
|
|
87
|
+
],
|
|
88
|
+
sql.fragment`, `,
|
|
89
|
+
)}`;
|
|
90
|
+
|
|
91
|
+
t.deepEqual(query, {
|
|
92
|
+
sql: 'SELECT ($slonik_1, $slonik_2), ($slonik_3, $slonik_4)',
|
|
93
|
+
type: FragmentToken,
|
|
94
|
+
values: [1, 2, 3, 4],
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('binary join expressions', (t) => {
|
|
99
|
+
const data = Buffer.from('1f', 'hex');
|
|
100
|
+
const query = sql.fragment`SELECT (${sql.join(
|
|
101
|
+
['a', sql.binary(data)],
|
|
102
|
+
sql.fragment`, `,
|
|
103
|
+
)})`;
|
|
104
|
+
|
|
105
|
+
t.deepEqual(query, {
|
|
106
|
+
sql: 'SELECT ($slonik_1, $slonik_2)',
|
|
107
|
+
type: FragmentToken,
|
|
108
|
+
values: ['a', data],
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test('throws is member is not a SQL token or a primitive value expression', (t) => {
|
|
113
|
+
const error = t.throws(() => {
|
|
114
|
+
sql.fragment`${sql.join(
|
|
115
|
+
[
|
|
116
|
+
// @ts-expect-error - intentional
|
|
117
|
+
() => {},
|
|
118
|
+
],
|
|
119
|
+
sql.fragment`, `,
|
|
120
|
+
)}`;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
t.is(
|
|
124
|
+
error?.message,
|
|
125
|
+
'Invalid list member type. Must be a SQL token or a primitive value expression.',
|
|
126
|
+
);
|
|
127
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { FragmentToken } from '../../tokens';
|
|
2
|
+
import { createSqlTag } from '../createSqlTag';
|
|
3
|
+
import test from 'ava';
|
|
4
|
+
|
|
5
|
+
const sql = createSqlTag();
|
|
6
|
+
|
|
7
|
+
test('creates a value list (object)', (t) => {
|
|
8
|
+
const query = sql.fragment`SELECT ${sql.json({
|
|
9
|
+
foo: 'bar',
|
|
10
|
+
})}`;
|
|
11
|
+
|
|
12
|
+
t.deepEqual(query, {
|
|
13
|
+
sql: 'SELECT $slonik_1::json',
|
|
14
|
+
type: FragmentToken,
|
|
15
|
+
values: ['{"foo":"bar"}'],
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('creates a value list (array)', (t) => {
|
|
20
|
+
const query = sql.fragment`SELECT ${sql.json([
|
|
21
|
+
{
|
|
22
|
+
foo: 'bar',
|
|
23
|
+
},
|
|
24
|
+
])}`;
|
|
25
|
+
|
|
26
|
+
t.deepEqual(query, {
|
|
27
|
+
sql: 'SELECT $slonik_1::json',
|
|
28
|
+
type: FragmentToken,
|
|
29
|
+
values: ['[{"foo":"bar"}]'],
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("stringifies NULL to 'null'::json", (t) => {
|
|
34
|
+
const query = sql.fragment`SELECT ${sql.json(null)}`;
|
|
35
|
+
|
|
36
|
+
t.deepEqual(query, {
|
|
37
|
+
sql: 'SELECT $slonik_1::json',
|
|
38
|
+
type: FragmentToken,
|
|
39
|
+
values: ['null'],
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('JSON encodes string values', (t) => {
|
|
44
|
+
const query = sql.fragment`SELECT ${sql.json('example string')}`;
|
|
45
|
+
|
|
46
|
+
t.deepEqual(query, {
|
|
47
|
+
sql: 'SELECT $slonik_1::json',
|
|
48
|
+
type: FragmentToken,
|
|
49
|
+
values: ['"example string"'],
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('JSON encodes numeric values', (t) => {
|
|
54
|
+
const query = sql.fragment`SELECT ${sql.json(1_234)}`;
|
|
55
|
+
|
|
56
|
+
t.deepEqual(query, {
|
|
57
|
+
sql: 'SELECT $slonik_1::json',
|
|
58
|
+
type: FragmentToken,
|
|
59
|
+
values: ['1234'],
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('JSON encodes boolean values', (t) => {
|
|
64
|
+
const query = sql.fragment`SELECT ${sql.json(true)}`;
|
|
65
|
+
|
|
66
|
+
t.deepEqual(query, {
|
|
67
|
+
sql: 'SELECT $slonik_1::json',
|
|
68
|
+
type: FragmentToken,
|
|
69
|
+
values: ['true'],
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('throws if payload is undefined', (t) => {
|
|
74
|
+
const error = t.throws(() => {
|
|
75
|
+
sql.fragment`SELECT ${sql.json(undefined)}`;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
t.is(error?.message, 'JSON payload must not be undefined.');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('throws if payload cannot be stringified (non-primitive object)', (t) => {
|
|
82
|
+
const error = t.throws(() => {
|
|
83
|
+
// @ts-expect-error - intentional
|
|
84
|
+
sql.fragment`SELECT ${sql.json(() => {})}`;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
t.is(
|
|
88
|
+
error?.message,
|
|
89
|
+
'JSON payload must be a primitive value or a plain object.',
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('Object types with optional properties are allowed', (t) => {
|
|
94
|
+
type TypeWithOptionalProperty = { foo: string; opt?: string };
|
|
95
|
+
const testValue: TypeWithOptionalProperty = {
|
|
96
|
+
foo: 'bar',
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const query = sql.fragment`SELECT ${sql.json(testValue)}`;
|
|
100
|
+
|
|
101
|
+
t.deepEqual(query, {
|
|
102
|
+
sql: 'SELECT $slonik_1::json',
|
|
103
|
+
type: FragmentToken,
|
|
104
|
+
values: ['{"foo":"bar"}'],
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { FragmentToken } from '../../tokens';
|
|
2
|
+
import { createSqlTag } from '../createSqlTag';
|
|
3
|
+
import test from 'ava';
|
|
4
|
+
|
|
5
|
+
const sql = createSqlTag();
|
|
6
|
+
|
|
7
|
+
test('creates a value list (object)', (t) => {
|
|
8
|
+
const query = sql.fragment`SELECT ${sql.jsonb({
|
|
9
|
+
foo: 'bar',
|
|
10
|
+
})}`;
|
|
11
|
+
|
|
12
|
+
t.deepEqual(query, {
|
|
13
|
+
sql: 'SELECT $slonik_1::jsonb',
|
|
14
|
+
type: FragmentToken,
|
|
15
|
+
values: ['{"foo":"bar"}'],
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('creates a value list (array)', (t) => {
|
|
20
|
+
const query = sql.fragment`SELECT ${sql.jsonb([
|
|
21
|
+
{
|
|
22
|
+
foo: 'bar',
|
|
23
|
+
},
|
|
24
|
+
])}`;
|
|
25
|
+
|
|
26
|
+
t.deepEqual(query, {
|
|
27
|
+
sql: 'SELECT $slonik_1::jsonb',
|
|
28
|
+
type: FragmentToken,
|
|
29
|
+
values: ['[{"foo":"bar"}]'],
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("stringifies NULL to 'null'::jsonb", (t) => {
|
|
34
|
+
const query = sql.fragment`SELECT ${sql.jsonb(null)}`;
|
|
35
|
+
|
|
36
|
+
t.deepEqual(query, {
|
|
37
|
+
sql: 'SELECT $slonik_1::jsonb',
|
|
38
|
+
type: FragmentToken,
|
|
39
|
+
values: ['null'],
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('JSON encodes string values', (t) => {
|
|
44
|
+
const query = sql.fragment`SELECT ${sql.jsonb('example string')}`;
|
|
45
|
+
|
|
46
|
+
t.deepEqual(query, {
|
|
47
|
+
sql: 'SELECT $slonik_1::jsonb',
|
|
48
|
+
type: FragmentToken,
|
|
49
|
+
values: ['"example string"'],
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('JSON encodes numeric values', (t) => {
|
|
54
|
+
const query = sql.fragment`SELECT ${sql.jsonb(1_234)}`;
|
|
55
|
+
|
|
56
|
+
t.deepEqual(query, {
|
|
57
|
+
sql: 'SELECT $slonik_1::jsonb',
|
|
58
|
+
type: FragmentToken,
|
|
59
|
+
values: ['1234'],
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('JSON encodes boolean values', (t) => {
|
|
64
|
+
const query = sql.fragment`SELECT ${sql.jsonb(true)}`;
|
|
65
|
+
|
|
66
|
+
t.deepEqual(query, {
|
|
67
|
+
sql: 'SELECT $slonik_1::jsonb',
|
|
68
|
+
type: FragmentToken,
|
|
69
|
+
values: ['true'],
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('throws if payload is undefined', (t) => {
|
|
74
|
+
const error = t.throws(() => {
|
|
75
|
+
sql.fragment`SELECT ${sql.jsonb(undefined)}`;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
t.is(error?.message, 'JSON payload must not be undefined.');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('throws if payload cannot be stringified (non-primitive object)', (t) => {
|
|
82
|
+
const error = t.throws(() => {
|
|
83
|
+
// @ts-expect-error - intentional
|
|
84
|
+
sql.fragment`SELECT ${sql.jsonb(() => {})}`;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
t.is(
|
|
88
|
+
error?.message,
|
|
89
|
+
'JSON payload must be a primitive value or a plain object.',
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('Object types with optional properties are allowed', (t) => {
|
|
94
|
+
type TypeWithOptionalProperty = { foo: string; opt?: string };
|
|
95
|
+
const testValue: TypeWithOptionalProperty = {
|
|
96
|
+
foo: 'bar',
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const query = sql.fragment`SELECT ${sql.jsonb(testValue)}`;
|
|
100
|
+
|
|
101
|
+
t.deepEqual(query, {
|
|
102
|
+
sql: 'SELECT $slonik_1::jsonb',
|
|
103
|
+
type: FragmentToken,
|
|
104
|
+
values: ['{"foo":"bar"}'],
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FragmentToken } from '../../tokens';
|
|
2
|
+
import { createSqlTag } from '../createSqlTag';
|
|
3
|
+
import test from 'ava';
|
|
4
|
+
|
|
5
|
+
const sql = createSqlTag();
|
|
6
|
+
|
|
7
|
+
test('creates an object describing a query with an inlined literal value', (t) => {
|
|
8
|
+
const query = sql.fragment`CREATE USER foo WITH PASSWORD ${sql.literalValue(
|
|
9
|
+
'bar',
|
|
10
|
+
)}`;
|
|
11
|
+
|
|
12
|
+
t.deepEqual(query, {
|
|
13
|
+
sql: "CREATE USER foo WITH PASSWORD 'bar'",
|
|
14
|
+
type: FragmentToken,
|
|
15
|
+
values: [],
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { FragmentToken } from '../../tokens';
|
|
2
|
+
import { createSqlTag } from '../createSqlTag';
|
|
3
|
+
import anyTest, { type TestFn } from 'ava';
|
|
4
|
+
import { ROARR } from 'roarr';
|
|
5
|
+
|
|
6
|
+
const test = anyTest as TestFn<{
|
|
7
|
+
logs: unknown[];
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
const sql = createSqlTag();
|
|
11
|
+
|
|
12
|
+
test.beforeEach((t) => {
|
|
13
|
+
t.context.logs = [];
|
|
14
|
+
|
|
15
|
+
ROARR.write = (message) => {
|
|
16
|
+
t.context.logs.push(JSON.parse(message));
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('creates an object describing a query', (t) => {
|
|
21
|
+
const query = sql.fragment`SELECT 1`;
|
|
22
|
+
|
|
23
|
+
t.deepEqual(query, {
|
|
24
|
+
sql: 'SELECT 1',
|
|
25
|
+
type: FragmentToken,
|
|
26
|
+
values: [],
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('creates an object describing query value bindings', (t) => {
|
|
31
|
+
const query = sql.fragment`SELECT ${'foo'}`;
|
|
32
|
+
|
|
33
|
+
t.deepEqual(query, {
|
|
34
|
+
sql: 'SELECT $slonik_1',
|
|
35
|
+
type: FragmentToken,
|
|
36
|
+
values: ['foo'],
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('creates an object describing query value bindings (multiple)', (t) => {
|
|
41
|
+
const query = sql.fragment`SELECT ${'foo'}, ${'bar'}`;
|
|
42
|
+
|
|
43
|
+
t.deepEqual(query, {
|
|
44
|
+
sql: 'SELECT $slonik_1, $slonik_2',
|
|
45
|
+
type: FragmentToken,
|
|
46
|
+
values: ['foo', 'bar'],
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('nests sql templates', (t) => {
|
|
51
|
+
const query0 = sql.fragment`SELECT ${'foo'} FROM bar`;
|
|
52
|
+
const query1 = sql.fragment`SELECT ${'baz'} FROM (${query0})`;
|
|
53
|
+
|
|
54
|
+
t.deepEqual(query1, {
|
|
55
|
+
sql: 'SELECT $slonik_1 FROM (SELECT $slonik_2 FROM bar)',
|
|
56
|
+
type: FragmentToken,
|
|
57
|
+
values: ['baz', 'foo'],
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('throws if bound an undefined value', (t) => {
|
|
62
|
+
const error = t.throws(() => {
|
|
63
|
+
// @ts-expect-error - intentional
|
|
64
|
+
sql.fragment`SELECT ${undefined}`;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
t.is(
|
|
68
|
+
error?.message,
|
|
69
|
+
'SQL tag cannot be bound to undefined value at index 1.',
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// eslint-disable-next-line n/no-process-env
|
|
74
|
+
if (process.env.ROARR_LOG === '1') {
|
|
75
|
+
// This test is only valid when ROARR_LOG=1.
|
|
76
|
+
// TODO find a way to test this without relying on environment variables.
|
|
77
|
+
test.serial('logs all bound values if one is undefined', (t) => {
|
|
78
|
+
t.throws(() => {
|
|
79
|
+
// @ts-expect-error - intentional
|
|
80
|
+
sql.fragment`SELECT ${undefined}`;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const targetMessage = t.context.logs.find((message: any) => {
|
|
84
|
+
return message.message === 'bound values';
|
|
85
|
+
}) as any;
|
|
86
|
+
|
|
87
|
+
t.truthy(targetMessage);
|
|
88
|
+
|
|
89
|
+
t.deepEqual(targetMessage.context.parts, ['SELECT ', '']);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
test('the sql property is immutable', (t) => {
|
|
94
|
+
const query = sql.fragment`SELECT 1`;
|
|
95
|
+
|
|
96
|
+
t.throws(() => {
|
|
97
|
+
// @ts-expect-error This is intentional.
|
|
98
|
+
query.sql = 'SELECT 2';
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* https://github.com/gajus/slonik/pull/552
|
|
104
|
+
*/
|
|
105
|
+
test('copes with dollar-number in table name', (t) => {
|
|
106
|
+
const query0 = sql.fragment`discounted_to_$1 (offer_id INTEGER)`;
|
|
107
|
+
const query1 = sql.fragment`CREATE TABLE ${query0}`;
|
|
108
|
+
|
|
109
|
+
t.deepEqual(query1, {
|
|
110
|
+
sql: 'CREATE TABLE discounted_to_$1 (offer_id INTEGER)',
|
|
111
|
+
type: FragmentToken,
|
|
112
|
+
values: [],
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* https://github.com/gajus/slonik/pull/552
|
|
118
|
+
*/
|
|
119
|
+
test('copes with dollar-number in column name (CREATE TABLE)', (t) => {
|
|
120
|
+
const query0 = sql.fragment`offers (discounted_to_$1 BOOLEAN)`;
|
|
121
|
+
const query1 = sql.fragment`CREATE TABLE ${query0}`;
|
|
122
|
+
|
|
123
|
+
t.deepEqual(query1, {
|
|
124
|
+
sql: 'CREATE TABLE offers (discounted_to_$1 BOOLEAN)',
|
|
125
|
+
type: FragmentToken,
|
|
126
|
+
values: [],
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* https://github.com/gajus/slonik/pull/552
|
|
132
|
+
*/
|
|
133
|
+
test('copes with dollar-number in column name (SELECT)', (t) => {
|
|
134
|
+
const query0 = sql.fragment`"discounted_to_$1" IS TRUE`;
|
|
135
|
+
const query1 = sql.fragment`SELECT * FROM offers WHERE ${query0}`;
|
|
136
|
+
|
|
137
|
+
t.deepEqual(query1, {
|
|
138
|
+
sql: 'SELECT * FROM offers WHERE "discounted_to_$1" IS TRUE',
|
|
139
|
+
type: FragmentToken,
|
|
140
|
+
values: [],
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* https://github.com/gajus/slonik/pull/552
|
|
146
|
+
*/
|
|
147
|
+
test('copes with dollar-number in function definitions', (t) => {
|
|
148
|
+
// example function from https://www.postgresql.org/docs/current/sql-createfunction.html
|
|
149
|
+
const query0 = sql.fragment`add(integer, integer) RETURNS integer
|
|
150
|
+
AS 'select $1 + $2;'
|
|
151
|
+
LANGUAGE SQL
|
|
152
|
+
IMMUTABLE
|
|
153
|
+
RETURNS NULL ON NULL INPUT`;
|
|
154
|
+
const query1 = sql.fragment`CREATE FUNCTION ${query0}`;
|
|
155
|
+
|
|
156
|
+
t.deepEqual(query1, {
|
|
157
|
+
sql: `CREATE FUNCTION add(integer, integer) RETURNS integer
|
|
158
|
+
AS 'select $1 + $2;'
|
|
159
|
+
LANGUAGE SQL
|
|
160
|
+
IMMUTABLE
|
|
161
|
+
RETURNS NULL ON NULL INPUT`,
|
|
162
|
+
type: FragmentToken,
|
|
163
|
+
values: [],
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FragmentToken } from '../../tokens';
|
|
2
|
+
import { createSqlTag } from '../createSqlTag';
|
|
3
|
+
import test from 'ava';
|
|
4
|
+
|
|
5
|
+
const sql = createSqlTag();
|
|
6
|
+
|
|
7
|
+
test('binds a timestamp', (t) => {
|
|
8
|
+
const query = sql.fragment`SELECT ${sql.timestamp(
|
|
9
|
+
new Date('2022-08-19T03:27:24.951Z'),
|
|
10
|
+
)}`;
|
|
11
|
+
|
|
12
|
+
t.deepEqual(query, {
|
|
13
|
+
sql: 'SELECT to_timestamp($slonik_1)',
|
|
14
|
+
type: FragmentToken,
|
|
15
|
+
values: ['1660879644.951'],
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('throws if not instance of Date', (t) => {
|
|
20
|
+
const error = t.throws(() => {
|
|
21
|
+
// @ts-expect-error - intentional
|
|
22
|
+
sql.fragment`SELECT ${sql.timestamp(1)}`;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
t.is(
|
|
26
|
+
error?.message,
|
|
27
|
+
'Timestamp parameter value must be an instance of Date.',
|
|
28
|
+
);
|
|
29
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createSqlTag } from '../createSqlTag';
|
|
2
|
+
import test from 'ava';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
const sql = createSqlTag();
|
|
6
|
+
|
|
7
|
+
test('describes zod object associated with the query', (t) => {
|
|
8
|
+
const zodObject = z.object({
|
|
9
|
+
id: z.number(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const query = sql.type(zodObject)`
|
|
13
|
+
SELECT 1 id
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
t.is(query.parser, zodObject);
|
|
17
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createSqlTag } from '../createSqlTag';
|
|
2
|
+
import anyTest, { type TestFn } from 'ava';
|
|
3
|
+
import { ROARR } from 'roarr';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
const test = anyTest as TestFn<{
|
|
7
|
+
logs: unknown[];
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
test.beforeEach((t) => {
|
|
11
|
+
t.context.logs = [];
|
|
12
|
+
|
|
13
|
+
ROARR.write = (message) => {
|
|
14
|
+
t.context.logs.push(JSON.parse(message));
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('describes zod object associated with the query', (t) => {
|
|
19
|
+
const typeAliases = {
|
|
20
|
+
id: z.object({
|
|
21
|
+
id: z.number(),
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const sql = createSqlTag({
|
|
26
|
+
typeAliases,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const query = sql.typeAlias('id')`
|
|
30
|
+
SELECT 1 id
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
t.is(query.parser, typeAliases.id);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('cannot alias unknown fields', (t) => {
|
|
37
|
+
const typeAliases = {
|
|
38
|
+
id: z.object({
|
|
39
|
+
id: z.number(),
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const sql = createSqlTag({
|
|
44
|
+
typeAliases,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
t.throws(() => {
|
|
48
|
+
// @ts-expect-error - intentional
|
|
49
|
+
sql.typeAlias('void')`
|
|
50
|
+
SELECT 1 id
|
|
51
|
+
`;
|
|
52
|
+
});
|
|
53
|
+
});
|