@slonik/sql-tag 48.12.2 → 48.13.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/README.md +0 -1
- package/dist/Logger.js +2 -2
- package/dist/factories/createPrimitiveValueExpressions.d.ts +1 -1
- package/dist/factories/createPrimitiveValueExpressions.js +10 -10
- package/dist/factories/createSqlTag.d.ts +2 -2
- package/dist/factories/createSqlTag.d.ts.map +1 -1
- package/dist/factories/createSqlTag.js +16 -16
- package/dist/factories/createSqlTag.js.map +1 -1
- package/dist/factories/createSqlTag.test/array.test.js +44 -44
- package/dist/factories/createSqlTag.test/array.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/date.test.js +9 -9
- package/dist/factories/createSqlTag.test/date.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/identifier.test.js +11 -14
- package/dist/factories/createSqlTag.test/identifier.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/interval.test.js +10 -10
- package/dist/factories/createSqlTag.test/join.test.js +24 -24
- package/dist/factories/createSqlTag.test/join.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/json.test.js +27 -27
- package/dist/factories/createSqlTag.test/json.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/jsonb.test.js +27 -27
- package/dist/factories/createSqlTag.test/jsonb.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/literalValue.test.js +5 -5
- package/dist/factories/createSqlTag.test/literalValue.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/sql.test.js +37 -37
- package/dist/factories/createSqlTag.test/sql.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/timestamp.test.js +9 -9
- package/dist/factories/createSqlTag.test/timestamp.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/type.test.js +4 -4
- package/dist/factories/createSqlTag.test/typeAlias.test.js +8 -8
- package/dist/factories/createSqlTag.test/unnest.test.js +25 -25
- package/dist/factories/createSqlTag.test/unnest.test.js.map +1 -1
- package/dist/factories/createSqlTag.test/uuid.test.js +10 -10
- package/dist/factories/createSqlTag.test/uuid.test.js.map +1 -1
- package/dist/factories/createSqlTokenSqlFragment.d.ts +1 -1
- package/dist/factories/createSqlTokenSqlFragment.d.ts.map +1 -1
- package/dist/factories/createSqlTokenSqlFragment.js +28 -67
- package/dist/factories/createSqlTokenSqlFragment.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/sqlFragmentFactories/createArraySqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createArraySqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createArraySqlFragment.js +15 -15
- package/dist/sqlFragmentFactories/createArraySqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createBinarySqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createBinarySqlFragment.js +4 -4
- package/dist/sqlFragmentFactories/createDateSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createDateSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createDateSqlFragment.js +5 -5
- package/dist/sqlFragmentFactories/createDateSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.js +7 -7
- package/dist/sqlFragmentFactories/createFragmentSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.js +6 -6
- package/dist/sqlFragmentFactories/createIdentifierSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.js +10 -20
- package/dist/sqlFragmentFactories/createIntervalSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createJsonSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createJsonSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createJsonSqlFragment.js +16 -18
- package/dist/sqlFragmentFactories/createJsonSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createListSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createListSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createListSqlFragment.js +9 -9
- package/dist/sqlFragmentFactories/createListSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createQuerySqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createQuerySqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createQuerySqlFragment.js +7 -7
- package/dist/sqlFragmentFactories/createQuerySqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.js +5 -7
- package/dist/sqlFragmentFactories/createTimestampSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.d.ts.map +1 -1
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.js +19 -20
- package/dist/sqlFragmentFactories/createUnnestSqlFragment.js.map +1 -1
- package/dist/sqlFragmentFactories/createUuidSqlFragment.d.ts +1 -1
- package/dist/sqlFragmentFactories/createUuidSqlFragment.js +5 -5
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +14 -14
- package/dist/tokens.js.map +1 -1
- package/dist/types.d.ts +5 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/utilities/countArrayDimensions.js +1 -1
- package/dist/utilities/countArrayDimensions.test.js +6 -6
- package/dist/utilities/escapeIdentifier.test.js +5 -5
- package/dist/utilities/escapeLiteralValue.js +2 -2
- package/dist/utilities/escapeLiteralValue.test.js +7 -7
- package/dist/utilities/formatSlonikPlaceholder.js +1 -1
- package/dist/utilities/isPlainObject.js +1 -1
- package/dist/utilities/isPrimitiveValueExpression.js +4 -4
- package/dist/utilities/isSqlToken.d.ts +1 -1
- package/dist/utilities/isSqlToken.d.ts.map +1 -1
- package/dist/utilities/isSqlToken.js +9 -9
- package/dist/utilities/isSqlToken.js.map +1 -1
- package/dist/utilities/safeStringify.js +3 -3
- package/dist/utilities/stripArrayNotation.js +1 -1
- package/dist/utilities/stripArrayNotation.test.js +6 -6
- package/package.json +35 -39
- package/src/Logger.ts +2 -2
- package/src/declarations.d.ts +2 -2
- package/src/factories/createPrimitiveValueExpressions.ts +11 -11
- package/src/factories/createSqlTag.test/array.test.ts +54 -66
- package/src/factories/createSqlTag.test/date.test.ts +9 -11
- package/src/factories/createSqlTag.test/identifier.test.ts +11 -14
- package/src/factories/createSqlTag.test/interval.test.ts +10 -10
- package/src/factories/createSqlTag.test/join.test.ts +25 -31
- package/src/factories/createSqlTag.test/json.test.ts +27 -30
- package/src/factories/createSqlTag.test/jsonb.test.ts +27 -30
- package/src/factories/createSqlTag.test/literalValue.test.ts +5 -7
- package/src/factories/createSqlTag.test/sql.test.ts +38 -41
- package/src/factories/createSqlTag.test/timestamp.test.ts +9 -14
- package/src/factories/createSqlTag.test/type.test.ts +4 -4
- package/src/factories/createSqlTag.test/typeAlias.test.ts +9 -9
- package/src/factories/createSqlTag.test/unnest.test.ts +25 -34
- package/src/factories/createSqlTag.test/uuid.test.ts +10 -12
- package/src/factories/createSqlTag.ts +26 -47
- package/src/factories/createSqlTokenSqlFragment.ts +30 -74
- package/src/index.ts +5 -5
- package/src/sqlFragmentFactories/createArraySqlFragment.ts +17 -22
- package/src/sqlFragmentFactories/createBinarySqlFragment.ts +5 -5
- package/src/sqlFragmentFactories/createDateSqlFragment.ts +6 -8
- package/src/sqlFragmentFactories/createFragmentSqlFragment.ts +9 -11
- package/src/sqlFragmentFactories/createIdentifierSqlFragment.ts +8 -12
- package/src/sqlFragmentFactories/createIntervalSqlFragment.ts +11 -23
- package/src/sqlFragmentFactories/createJsonSqlFragment.ts +17 -25
- package/src/sqlFragmentFactories/createListSqlFragment.ts +10 -14
- package/src/sqlFragmentFactories/createQuerySqlFragment.ts +9 -11
- package/src/sqlFragmentFactories/createTimestampSqlFragment.ts +6 -11
- package/src/sqlFragmentFactories/createUnnestSqlFragment.ts +20 -29
- package/src/sqlFragmentFactories/createUuidSqlFragment.ts +6 -6
- package/src/tokens.ts +14 -16
- package/src/types.ts +65 -87
- package/src/utilities/countArrayDimensions.test.ts +6 -6
- package/src/utilities/countArrayDimensions.ts +1 -1
- package/src/utilities/escapeIdentifier.test.ts +5 -5
- package/src/utilities/escapeLiteralValue.test.ts +7 -7
- package/src/utilities/escapeLiteralValue.ts +2 -2
- package/src/utilities/formatSlonikPlaceholder.ts +1 -1
- package/src/utilities/isPlainObject.ts +1 -1
- package/src/utilities/isPrimitiveValueExpression.ts +4 -4
- package/src/utilities/isSqlToken.ts +10 -12
- package/src/utilities/safeStringify.ts +3 -3
- package/src/utilities/stripArrayNotation.test.ts +6 -6
- package/src/utilities/stripArrayNotation.ts +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { FragmentToken } from
|
|
2
|
-
import { createSqlTag } from
|
|
3
|
-
import { InvalidInputError } from
|
|
4
|
-
import anyTest from
|
|
5
|
-
import type { TestFn } from
|
|
6
|
-
import { ROARR } from
|
|
1
|
+
import { FragmentToken } from "../../tokens.js";
|
|
2
|
+
import { createSqlTag } from "../createSqlTag.js";
|
|
3
|
+
import { InvalidInputError } from "@slonik/errors";
|
|
4
|
+
import anyTest from "ava";
|
|
5
|
+
import type { TestFn } from "ava";
|
|
6
|
+
import { ROARR } from "roarr";
|
|
7
7
|
|
|
8
8
|
const test = anyTest as TestFn<{
|
|
9
9
|
logs: unknown[];
|
|
@@ -19,7 +19,7 @@ test.beforeEach((t) => {
|
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
test(
|
|
22
|
+
test("throws error if called as a function", (t) => {
|
|
23
23
|
const error = t.throws(() => {
|
|
24
24
|
// @ts-expect-error - intentional
|
|
25
25
|
sql.fragment([`SELECT 1`]);
|
|
@@ -28,97 +28,94 @@ test('throws error if called as a function', (t) => {
|
|
|
28
28
|
t.true(error instanceof InvalidInputError);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
test(
|
|
31
|
+
test("creates an object describing a query", (t) => {
|
|
32
32
|
const query = sql.fragment`SELECT 1`;
|
|
33
33
|
|
|
34
34
|
t.deepEqual(query, {
|
|
35
|
-
sql:
|
|
35
|
+
sql: "SELECT 1",
|
|
36
36
|
type: FragmentToken,
|
|
37
37
|
values: [],
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
test(
|
|
42
|
-
const query = sql.fragment`SELECT ${
|
|
41
|
+
test("creates an object describing query value bindings", (t) => {
|
|
42
|
+
const query = sql.fragment`SELECT ${"foo"}`;
|
|
43
43
|
|
|
44
44
|
t.deepEqual(query, {
|
|
45
|
-
sql:
|
|
45
|
+
sql: "SELECT $slonik_1",
|
|
46
46
|
type: FragmentToken,
|
|
47
|
-
values: [
|
|
47
|
+
values: ["foo"],
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
test(
|
|
52
|
-
const query = sql.fragment`SELECT ${
|
|
51
|
+
test("creates an object describing query value bindings (multiple)", (t) => {
|
|
52
|
+
const query = sql.fragment`SELECT ${"foo"}, ${"bar"}`;
|
|
53
53
|
|
|
54
54
|
t.deepEqual(query, {
|
|
55
|
-
sql:
|
|
55
|
+
sql: "SELECT $slonik_1, $slonik_2",
|
|
56
56
|
type: FragmentToken,
|
|
57
|
-
values: [
|
|
57
|
+
values: ["foo", "bar"],
|
|
58
58
|
});
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
test(
|
|
62
|
-
const query0 = sql.fragment`SELECT ${
|
|
63
|
-
const query1 = sql.fragment`SELECT ${
|
|
61
|
+
test("nests sql templates", (t) => {
|
|
62
|
+
const query0 = sql.fragment`SELECT ${"foo"} FROM bar`;
|
|
63
|
+
const query1 = sql.fragment`SELECT ${"baz"} FROM (${query0})`;
|
|
64
64
|
|
|
65
65
|
t.deepEqual(query1, {
|
|
66
|
-
sql:
|
|
66
|
+
sql: "SELECT $slonik_1 FROM (SELECT $slonik_2 FROM bar)",
|
|
67
67
|
type: FragmentToken,
|
|
68
|
-
values: [
|
|
68
|
+
values: ["baz", "foo"],
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
test(
|
|
72
|
+
test("throws if bound an undefined value", (t) => {
|
|
73
73
|
const error = t.throws(() => {
|
|
74
74
|
// @ts-expect-error - intentional
|
|
75
75
|
sql.fragment`SELECT ${undefined}`;
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
t.is(
|
|
79
|
-
error?.message,
|
|
80
|
-
'SQL tag cannot be bound to undefined value at index 1.',
|
|
81
|
-
);
|
|
78
|
+
t.is(error?.message, "SQL tag cannot be bound to undefined value at index 1.");
|
|
82
79
|
});
|
|
83
80
|
|
|
84
81
|
// eslint-disable-next-line n/no-process-env
|
|
85
|
-
if (process.env.ROARR_LOG ===
|
|
82
|
+
if (process.env.ROARR_LOG === "1") {
|
|
86
83
|
// This test is only valid when ROARR_LOG=1.
|
|
87
84
|
// TODO find a way to test this without relying on environment variables.
|
|
88
|
-
test.serial(
|
|
85
|
+
test.serial("logs all bound values if one is undefined", (t) => {
|
|
89
86
|
t.throws(() => {
|
|
90
87
|
// @ts-expect-error - intentional
|
|
91
88
|
sql.fragment`SELECT ${undefined}`;
|
|
92
89
|
});
|
|
93
90
|
|
|
94
91
|
const targetMessage = t.context.logs.find((message: any) => {
|
|
95
|
-
return message.message ===
|
|
92
|
+
return message.message === "bound values";
|
|
96
93
|
}) as any;
|
|
97
94
|
|
|
98
95
|
t.truthy(targetMessage);
|
|
99
96
|
|
|
100
|
-
t.deepEqual(targetMessage.context.parts, [
|
|
97
|
+
t.deepEqual(targetMessage.context.parts, ["SELECT ", ""]);
|
|
101
98
|
});
|
|
102
99
|
}
|
|
103
100
|
|
|
104
|
-
test(
|
|
101
|
+
test("the sql property is immutable", (t) => {
|
|
105
102
|
const query = sql.fragment`SELECT 1`;
|
|
106
103
|
|
|
107
104
|
t.throws(() => {
|
|
108
105
|
// @ts-expect-error This is intentional.
|
|
109
|
-
query.sql =
|
|
106
|
+
query.sql = "SELECT 2";
|
|
110
107
|
});
|
|
111
108
|
});
|
|
112
109
|
|
|
113
110
|
/**
|
|
114
111
|
* https://github.com/gajus/slonik/pull/552
|
|
115
112
|
*/
|
|
116
|
-
test(
|
|
113
|
+
test("copes with dollar-number in table name", (t) => {
|
|
117
114
|
const query0 = sql.fragment`discounted_to_$1 (offer_id INTEGER)`;
|
|
118
115
|
const query1 = sql.fragment`CREATE TABLE ${query0}`;
|
|
119
116
|
|
|
120
117
|
t.deepEqual(query1, {
|
|
121
|
-
sql:
|
|
118
|
+
sql: "CREATE TABLE discounted_to_$1 (offer_id INTEGER)",
|
|
122
119
|
type: FragmentToken,
|
|
123
120
|
values: [],
|
|
124
121
|
});
|
|
@@ -127,12 +124,12 @@ test('copes with dollar-number in table name', (t) => {
|
|
|
127
124
|
/**
|
|
128
125
|
* https://github.com/gajus/slonik/pull/552
|
|
129
126
|
*/
|
|
130
|
-
test(
|
|
127
|
+
test("copes with dollar-number in column name (CREATE TABLE)", (t) => {
|
|
131
128
|
const query0 = sql.fragment`offers (discounted_to_$1 BOOLEAN)`;
|
|
132
129
|
const query1 = sql.fragment`CREATE TABLE ${query0}`;
|
|
133
130
|
|
|
134
131
|
t.deepEqual(query1, {
|
|
135
|
-
sql:
|
|
132
|
+
sql: "CREATE TABLE offers (discounted_to_$1 BOOLEAN)",
|
|
136
133
|
type: FragmentToken,
|
|
137
134
|
values: [],
|
|
138
135
|
});
|
|
@@ -141,7 +138,7 @@ test('copes with dollar-number in column name (CREATE TABLE)', (t) => {
|
|
|
141
138
|
/**
|
|
142
139
|
* https://github.com/gajus/slonik/pull/552
|
|
143
140
|
*/
|
|
144
|
-
test(
|
|
141
|
+
test("copes with dollar-number in column name (SELECT)", (t) => {
|
|
145
142
|
const query0 = sql.fragment`"discounted_to_$1" IS TRUE`;
|
|
146
143
|
const query1 = sql.fragment`SELECT * FROM offers WHERE ${query0}`;
|
|
147
144
|
|
|
@@ -155,7 +152,7 @@ test('copes with dollar-number in column name (SELECT)', (t) => {
|
|
|
155
152
|
/**
|
|
156
153
|
* https://github.com/gajus/slonik/pull/552
|
|
157
154
|
*/
|
|
158
|
-
test(
|
|
155
|
+
test("copes with dollar-number in function definitions", (t) => {
|
|
159
156
|
// example function from https://www.postgresql.org/docs/current/sql-createfunction.html
|
|
160
157
|
const query0 = sql.fragment`add(integer, integer) RETURNS integer
|
|
161
158
|
AS 'select $1 + $2;'
|
|
@@ -175,11 +172,11 @@ test('copes with dollar-number in function definitions', (t) => {
|
|
|
175
172
|
});
|
|
176
173
|
});
|
|
177
174
|
|
|
178
|
-
test(
|
|
175
|
+
test("interpolates literal boolean values", (t) => {
|
|
179
176
|
const query = sql.fragment`SELECT ${true}, ${false}`;
|
|
180
177
|
|
|
181
178
|
t.deepEqual(query, {
|
|
182
|
-
sql:
|
|
179
|
+
sql: "SELECT $slonik_1, $slonik_2",
|
|
183
180
|
type: FragmentToken,
|
|
184
181
|
values: [true, false],
|
|
185
182
|
});
|
|
@@ -1,29 +1,24 @@
|
|
|
1
|
-
import { FragmentToken } from
|
|
2
|
-
import { createSqlTag } from
|
|
3
|
-
import test from
|
|
1
|
+
import { FragmentToken } from "../../tokens.js";
|
|
2
|
+
import { createSqlTag } from "../createSqlTag.js";
|
|
3
|
+
import test from "ava";
|
|
4
4
|
|
|
5
5
|
const sql = createSqlTag();
|
|
6
6
|
|
|
7
|
-
test(
|
|
8
|
-
const query = sql.fragment`SELECT ${sql.timestamp(
|
|
9
|
-
new Date('2022-08-19T03:27:24.951Z'),
|
|
10
|
-
)}`;
|
|
7
|
+
test("binds a timestamp", (t) => {
|
|
8
|
+
const query = sql.fragment`SELECT ${sql.timestamp(new Date("2022-08-19T03:27:24.951Z"))}`;
|
|
11
9
|
|
|
12
10
|
t.deepEqual(query, {
|
|
13
|
-
sql:
|
|
11
|
+
sql: "SELECT to_timestamp($slonik_1)",
|
|
14
12
|
type: FragmentToken,
|
|
15
|
-
values: [
|
|
13
|
+
values: ["1660879644.951"],
|
|
16
14
|
});
|
|
17
15
|
});
|
|
18
16
|
|
|
19
|
-
test(
|
|
17
|
+
test("throws if not instance of Date", (t) => {
|
|
20
18
|
const error = t.throws(() => {
|
|
21
19
|
// @ts-expect-error - intentional
|
|
22
20
|
sql.fragment`SELECT ${sql.timestamp(1)}`;
|
|
23
21
|
});
|
|
24
22
|
|
|
25
|
-
t.is(
|
|
26
|
-
error?.message,
|
|
27
|
-
'Timestamp parameter value must be an instance of Date.',
|
|
28
|
-
);
|
|
23
|
+
t.is(error?.message, "Timestamp parameter value must be an instance of Date.");
|
|
29
24
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { createSqlTag } from
|
|
2
|
-
import test from
|
|
3
|
-
import { z } from
|
|
1
|
+
import { createSqlTag } from "../createSqlTag.js";
|
|
2
|
+
import test from "ava";
|
|
3
|
+
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
const sql = createSqlTag();
|
|
6
6
|
|
|
7
|
-
test(
|
|
7
|
+
test("describes zod object associated with the query", (t) => {
|
|
8
8
|
const zodObject = z.object({
|
|
9
9
|
id: z.number(),
|
|
10
10
|
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createSqlTag } from
|
|
2
|
-
import anyTest from
|
|
3
|
-
import type { TestFn } from
|
|
4
|
-
import { ROARR } from
|
|
5
|
-
import { z } from
|
|
1
|
+
import { createSqlTag } from "../createSqlTag.js";
|
|
2
|
+
import anyTest from "ava";
|
|
3
|
+
import type { TestFn } from "ava";
|
|
4
|
+
import { ROARR } from "roarr";
|
|
5
|
+
import { z } from "zod";
|
|
6
6
|
|
|
7
7
|
const test = anyTest as TestFn<{
|
|
8
8
|
logs: unknown[];
|
|
@@ -16,7 +16,7 @@ test.beforeEach((t) => {
|
|
|
16
16
|
};
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
test(
|
|
19
|
+
test("describes zod object associated with the query", (t) => {
|
|
20
20
|
const typeAliases = {
|
|
21
21
|
id: z.object({
|
|
22
22
|
id: z.number(),
|
|
@@ -27,14 +27,14 @@ test('describes zod object associated with the query', (t) => {
|
|
|
27
27
|
typeAliases,
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
const query = sql.typeAlias(
|
|
30
|
+
const query = sql.typeAlias("id")`
|
|
31
31
|
SELECT 1 id
|
|
32
32
|
`;
|
|
33
33
|
|
|
34
34
|
t.is(query.parser, typeAliases.id);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
test(
|
|
37
|
+
test("cannot alias unknown fields", (t) => {
|
|
38
38
|
const typeAliases = {
|
|
39
39
|
id: z.object({
|
|
40
40
|
id: z.number(),
|
|
@@ -47,7 +47,7 @@ test('cannot alias unknown fields', (t) => {
|
|
|
47
47
|
|
|
48
48
|
t.throws(() => {
|
|
49
49
|
// @ts-expect-error - intentional
|
|
50
|
-
sql.typeAlias(
|
|
50
|
+
sql.typeAlias("void")`
|
|
51
51
|
SELECT 1 id
|
|
52
52
|
`;
|
|
53
53
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { FragmentToken } from
|
|
2
|
-
import { createSqlTag } from
|
|
3
|
-
import test from
|
|
1
|
+
import { FragmentToken } from "../../tokens.js";
|
|
2
|
+
import { createSqlTag } from "../createSqlTag.js";
|
|
3
|
+
import test from "ava";
|
|
4
4
|
|
|
5
5
|
const sql = createSqlTag();
|
|
6
6
|
|
|
7
|
-
test(
|
|
7
|
+
test("creates an unnest expression using primitive values (type name identifier)", (t) => {
|
|
8
8
|
const query = sql.fragment`SELECT * FROM ${sql.unnest(
|
|
9
9
|
[
|
|
10
10
|
[1, 2, 3],
|
|
11
11
|
[4, 5, 6],
|
|
12
12
|
],
|
|
13
|
-
[
|
|
13
|
+
["int4", "int4", "int4"],
|
|
14
14
|
)}`;
|
|
15
15
|
|
|
16
16
|
t.deepEqual(query, {
|
|
@@ -24,7 +24,7 @@ test('creates an unnest expression using primitive values (type name identifier)
|
|
|
24
24
|
});
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
test(
|
|
27
|
+
test("creates an unnest expression using primitive values (sql token)", (t) => {
|
|
28
28
|
const query = sql.fragment`SELECT * FROM ${sql.unnest(
|
|
29
29
|
[
|
|
30
30
|
[1, 2, 3],
|
|
@@ -34,7 +34,7 @@ test('creates an unnest expression using primitive values (sql token)', (t) => {
|
|
|
34
34
|
)}`;
|
|
35
35
|
|
|
36
36
|
t.deepEqual(query, {
|
|
37
|
-
sql:
|
|
37
|
+
sql: "SELECT * FROM unnest($slonik_1::integer[], $slonik_2::integer[], $slonik_3::integer[])",
|
|
38
38
|
type: FragmentToken,
|
|
39
39
|
values: [
|
|
40
40
|
[1, 4],
|
|
@@ -44,15 +44,15 @@ test('creates an unnest expression using primitive values (sql token)', (t) => {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
test(
|
|
47
|
+
test("treats type as sql.identifier", (t) => {
|
|
48
48
|
const query = sql.fragment`SELECT bar, baz FROM ${sql.unnest(
|
|
49
49
|
[
|
|
50
50
|
[1, 3],
|
|
51
51
|
[2, 4],
|
|
52
52
|
],
|
|
53
53
|
[
|
|
54
|
-
[
|
|
55
|
-
[
|
|
54
|
+
["foo", "int4"],
|
|
55
|
+
["foo", "int4"],
|
|
56
56
|
],
|
|
57
57
|
)} AS foo(bar, baz)`;
|
|
58
58
|
|
|
@@ -66,13 +66,13 @@ test('treats type as sql.identifier', (t) => {
|
|
|
66
66
|
});
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
test(
|
|
69
|
+
test("creates an unnest expression using arrays", (t) => {
|
|
70
70
|
const query = sql.fragment`SELECT * FROM ${sql.unnest(
|
|
71
71
|
[
|
|
72
72
|
[1, 2, 3],
|
|
73
73
|
[4, 5, 6],
|
|
74
74
|
],
|
|
75
|
-
[
|
|
75
|
+
["int4", "int4", "int4"],
|
|
76
76
|
)}`;
|
|
77
77
|
|
|
78
78
|
t.deepEqual(query, {
|
|
@@ -86,13 +86,13 @@ test('creates an unnest expression using arrays', (t) => {
|
|
|
86
86
|
});
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
test(
|
|
89
|
+
test("creates incremental alias names if no alias names are provided", (t) => {
|
|
90
90
|
const query = sql.fragment`SELECT * FROM ${sql.unnest(
|
|
91
91
|
[
|
|
92
92
|
[1, 2, 3],
|
|
93
93
|
[4, 5, 6],
|
|
94
94
|
],
|
|
95
|
-
[
|
|
95
|
+
["int4", "int4", "int4"],
|
|
96
96
|
)}`;
|
|
97
97
|
|
|
98
98
|
t.deepEqual(query, {
|
|
@@ -106,11 +106,8 @@ test('creates incremental alias names if no alias names are provided', (t) => {
|
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
test(
|
|
110
|
-
const query = sql.fragment`SELECT * FROM ${sql.unnest(
|
|
111
|
-
[[[[1], [2], [3]]]],
|
|
112
|
-
['int4[]'],
|
|
113
|
-
)}`;
|
|
109
|
+
test("recognizes an array of arrays array", (t) => {
|
|
110
|
+
const query = sql.fragment`SELECT * FROM ${sql.unnest([[[[1], [2], [3]]]], ["int4[]"])}`;
|
|
114
111
|
|
|
115
112
|
t.deepEqual(query, {
|
|
116
113
|
sql: 'SELECT * FROM unnest($slonik_1::"int4"[][])',
|
|
@@ -119,50 +116,44 @@ test('recognizes an array of arrays array', (t) => {
|
|
|
119
116
|
});
|
|
120
117
|
});
|
|
121
118
|
|
|
122
|
-
test(
|
|
119
|
+
test("throws if tuple member is not a primitive value expression", (t) => {
|
|
123
120
|
const error = t.throws(() => {
|
|
124
121
|
sql.fragment`SELECT * FROM ${sql.unnest(
|
|
125
122
|
[
|
|
126
123
|
[() => {}, 2, 3],
|
|
127
124
|
[4, 5],
|
|
128
125
|
],
|
|
129
|
-
[
|
|
126
|
+
["int4", "int4", "int4"],
|
|
130
127
|
)}`;
|
|
131
128
|
});
|
|
132
129
|
|
|
133
|
-
t.is(
|
|
134
|
-
error?.message,
|
|
135
|
-
'Invalid unnest tuple member type. Must be a primitive value expression.',
|
|
136
|
-
);
|
|
130
|
+
t.is(error?.message, "Invalid unnest tuple member type. Must be a primitive value expression.");
|
|
137
131
|
});
|
|
138
132
|
|
|
139
|
-
test(
|
|
133
|
+
test("throws if tuple member length varies in a list of tuples", (t) => {
|
|
140
134
|
const error = t.throws(() => {
|
|
141
135
|
sql.fragment`SELECT * FROM ${sql.unnest(
|
|
142
136
|
[
|
|
143
137
|
[1, 2, 3],
|
|
144
138
|
[4, 5],
|
|
145
139
|
],
|
|
146
|
-
[
|
|
140
|
+
["int4", "int4", "int4"],
|
|
147
141
|
)}`;
|
|
148
142
|
});
|
|
149
143
|
|
|
150
|
-
t.is(
|
|
151
|
-
error?.message,
|
|
152
|
-
'Each tuple in a list of tuples must have an equal number of members.',
|
|
153
|
-
);
|
|
144
|
+
t.is(error?.message, "Each tuple in a list of tuples must have an equal number of members.");
|
|
154
145
|
});
|
|
155
146
|
|
|
156
|
-
test(
|
|
147
|
+
test("throws if tuple member length does not match column types length", (t) => {
|
|
157
148
|
const error = t.throws(() => {
|
|
158
149
|
sql.fragment`SELECT * FROM ${sql.unnest(
|
|
159
150
|
[
|
|
160
151
|
[1, 2, 3],
|
|
161
152
|
[4, 5, 6],
|
|
162
153
|
],
|
|
163
|
-
[
|
|
154
|
+
["int4", "int4"],
|
|
164
155
|
)}`;
|
|
165
156
|
});
|
|
166
157
|
|
|
167
|
-
t.is(error?.message,
|
|
158
|
+
t.is(error?.message, "Column types length must match tuple member length.");
|
|
168
159
|
});
|
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
import { FragmentToken } from
|
|
2
|
-
import { createSqlTag } from
|
|
3
|
-
import test from
|
|
1
|
+
import { FragmentToken } from "../../tokens.js";
|
|
2
|
+
import { createSqlTag } from "../createSqlTag.js";
|
|
3
|
+
import test from "ava";
|
|
4
4
|
|
|
5
5
|
const sql = createSqlTag();
|
|
6
6
|
|
|
7
|
-
test(
|
|
8
|
-
const query = sql.fragment`SELECT ${sql.uuid(
|
|
9
|
-
'00000000-0000-0000-0000-000000000000',
|
|
10
|
-
)}`;
|
|
7
|
+
test("binds a uuid", (t) => {
|
|
8
|
+
const query = sql.fragment`SELECT ${sql.uuid("00000000-0000-0000-0000-000000000000")}`;
|
|
11
9
|
|
|
12
10
|
t.deepEqual(query, {
|
|
13
|
-
sql:
|
|
11
|
+
sql: "SELECT $slonik_1::uuid",
|
|
14
12
|
type: FragmentToken,
|
|
15
|
-
values: [
|
|
13
|
+
values: ["00000000-0000-0000-0000-000000000000"],
|
|
16
14
|
});
|
|
17
15
|
});
|
|
18
16
|
|
|
19
|
-
test(
|
|
17
|
+
test("throws if not valid uuid", (t) => {
|
|
20
18
|
const error = t.throws(() => {
|
|
21
|
-
sql.fragment`SELECT ${sql.uuid(
|
|
19
|
+
sql.fragment`SELECT ${sql.uuid("1")}`;
|
|
22
20
|
});
|
|
23
21
|
|
|
24
|
-
t.is(error?.message,
|
|
22
|
+
t.is(error?.message, "UUID parameter value must be a valid UUID.");
|
|
25
23
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Logger } from
|
|
2
|
-
import type { UUID } from
|
|
1
|
+
import { Logger } from "../Logger.js";
|
|
2
|
+
import type { UUID } from "../sqlFragmentFactories/createUuidSqlFragment.js";
|
|
3
3
|
import {
|
|
4
4
|
ArrayToken,
|
|
5
5
|
BinaryToken,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
TimestampToken,
|
|
15
15
|
UnnestToken,
|
|
16
16
|
UuidToken,
|
|
17
|
-
} from
|
|
17
|
+
} from "../tokens.js";
|
|
18
18
|
import type {
|
|
19
19
|
ArraySqlToken,
|
|
20
20
|
PrimitiveValueExpression,
|
|
@@ -22,32 +22,27 @@ import type {
|
|
|
22
22
|
SqlTag,
|
|
23
23
|
TypeNameIdentifier,
|
|
24
24
|
ValueExpression,
|
|
25
|
-
} from
|
|
26
|
-
import { escapeLiteralValue } from
|
|
27
|
-
import { formatSlonikPlaceholder } from
|
|
28
|
-
import { isPrimitiveValueExpression } from
|
|
29
|
-
import { isSqlToken } from
|
|
30
|
-
import { safeStringify } from
|
|
31
|
-
import { createSqlTokenSqlFragment } from
|
|
32
|
-
import { InvalidInputError } from
|
|
33
|
-
import type { StandardSchemaV1 } from
|
|
34
|
-
import { z } from
|
|
25
|
+
} from "../types.js";
|
|
26
|
+
import { escapeLiteralValue } from "../utilities/escapeLiteralValue.js";
|
|
27
|
+
import { formatSlonikPlaceholder } from "../utilities/formatSlonikPlaceholder.js";
|
|
28
|
+
import { isPrimitiveValueExpression } from "../utilities/isPrimitiveValueExpression.js";
|
|
29
|
+
import { isSqlToken } from "../utilities/isSqlToken.js";
|
|
30
|
+
import { safeStringify } from "../utilities/safeStringify.js";
|
|
31
|
+
import { createSqlTokenSqlFragment } from "./createSqlTokenSqlFragment.js";
|
|
32
|
+
import { InvalidInputError } from "@slonik/errors";
|
|
33
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
34
|
+
import { z } from "zod";
|
|
35
35
|
|
|
36
36
|
const log = Logger.child({
|
|
37
|
-
namespace:
|
|
37
|
+
namespace: "sql",
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
const createFragment = (
|
|
41
|
-
parts: TemplateStringsArray,
|
|
42
|
-
values: readonly ValueExpression[],
|
|
43
|
-
) => {
|
|
40
|
+
const createFragment = (parts: TemplateStringsArray, values: readonly ValueExpression[]) => {
|
|
44
41
|
if (!Array.isArray(parts.raw) || !Object.isFrozen(parts.raw)) {
|
|
45
|
-
throw new InvalidInputError(
|
|
46
|
-
'Function must be called as a template literal.',
|
|
47
|
-
);
|
|
42
|
+
throw new InvalidInputError("Function must be called as a template literal.");
|
|
48
43
|
}
|
|
49
44
|
|
|
50
|
-
let rawSql =
|
|
45
|
+
let rawSql = "";
|
|
51
46
|
|
|
52
47
|
const parameterValues: PrimitiveValueExpression[] = [];
|
|
53
48
|
|
|
@@ -69,21 +64,16 @@ const createFragment = (
|
|
|
69
64
|
parts: JSON.parse(safeStringify(parts)),
|
|
70
65
|
values: JSON.parse(safeStringify(values)),
|
|
71
66
|
},
|
|
72
|
-
|
|
67
|
+
"bound values",
|
|
73
68
|
);
|
|
74
69
|
|
|
75
|
-
throw new InvalidInputError(
|
|
76
|
-
`SQL tag cannot be bound to undefined value at index ${index}.`,
|
|
77
|
-
);
|
|
70
|
+
throw new InvalidInputError(`SQL tag cannot be bound to undefined value at index ${index}.`);
|
|
78
71
|
} else if (isPrimitiveValueExpression(token)) {
|
|
79
72
|
rawSql += formatSlonikPlaceholder(parameterValues.length + 1);
|
|
80
73
|
|
|
81
74
|
parameterValues.push(token);
|
|
82
75
|
} else if (isSqlToken(token)) {
|
|
83
|
-
const sqlFragment = createSqlTokenSqlFragment(
|
|
84
|
-
token,
|
|
85
|
-
parameterValues.length,
|
|
86
|
-
);
|
|
76
|
+
const sqlFragment = createSqlTokenSqlFragment(token, parameterValues.length);
|
|
87
77
|
|
|
88
78
|
rawSql += sqlFragment.sql;
|
|
89
79
|
|
|
@@ -97,10 +87,10 @@ const createFragment = (
|
|
|
97
87
|
index,
|
|
98
88
|
offendingToken: JSON.parse(safeStringify(token)),
|
|
99
89
|
},
|
|
100
|
-
|
|
90
|
+
"unexpected value expression",
|
|
101
91
|
);
|
|
102
92
|
|
|
103
|
-
throw new TypeError(
|
|
93
|
+
throw new TypeError("Unexpected value expression.");
|
|
104
94
|
}
|
|
105
95
|
}
|
|
106
96
|
|
|
@@ -189,10 +179,7 @@ export const createSqlTag = <
|
|
|
189
179
|
});
|
|
190
180
|
},
|
|
191
181
|
prepared: (statementName, parser) => {
|
|
192
|
-
return (
|
|
193
|
-
parts: TemplateStringsArray,
|
|
194
|
-
...args: readonly ValueExpression[]
|
|
195
|
-
) => {
|
|
182
|
+
return (parts: TemplateStringsArray, ...args: readonly ValueExpression[]) => {
|
|
196
183
|
return Object.freeze({
|
|
197
184
|
...createFragment(parts, args),
|
|
198
185
|
name: statementName,
|
|
@@ -208,10 +195,7 @@ export const createSqlTag = <
|
|
|
208
195
|
});
|
|
209
196
|
},
|
|
210
197
|
type: (parser) => {
|
|
211
|
-
return (
|
|
212
|
-
parts: TemplateStringsArray,
|
|
213
|
-
...args: readonly ValueExpression[]
|
|
214
|
-
) => {
|
|
198
|
+
return (parts: TemplateStringsArray, ...args: readonly ValueExpression[]) => {
|
|
215
199
|
return Object.freeze({
|
|
216
200
|
...createFragment(parts, args),
|
|
217
201
|
parser,
|
|
@@ -221,15 +205,10 @@ export const createSqlTag = <
|
|
|
221
205
|
},
|
|
222
206
|
typeAlias: (parserAlias) => {
|
|
223
207
|
if (!typeAliases?.[parserAlias]) {
|
|
224
|
-
throw new Error(
|
|
225
|
-
'Type alias "' + String(parserAlias) + '" does not exist.',
|
|
226
|
-
);
|
|
208
|
+
throw new Error('Type alias "' + String(parserAlias) + '" does not exist.');
|
|
227
209
|
}
|
|
228
210
|
|
|
229
|
-
return (
|
|
230
|
-
parts: TemplateStringsArray,
|
|
231
|
-
...args: readonly ValueExpression[]
|
|
232
|
-
) => {
|
|
211
|
+
return (parts: TemplateStringsArray, ...args: readonly ValueExpression[]) => {
|
|
233
212
|
return Object.freeze({
|
|
234
213
|
...createFragment(parts, args),
|
|
235
214
|
parser: typeAliases[parserAlias],
|