@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.
Files changed (233) hide show
  1. package/README.md +2 -0
  2. package/dist/Logger.d.ts +2 -0
  3. package/dist/Logger.d.ts.map +1 -0
  4. package/dist/Logger.js +8 -0
  5. package/dist/Logger.js.map +1 -0
  6. package/dist/factories/createPrimitiveValueExpressions.d.ts +3 -0
  7. package/dist/factories/createPrimitiveValueExpressions.d.ts.map +1 -0
  8. package/dist/factories/createPrimitiveValueExpressions.js +33 -0
  9. package/dist/factories/createPrimitiveValueExpressions.js.map +1 -0
  10. package/dist/factories/createSqlTag.d.ts +38 -0
  11. package/dist/factories/createSqlTag.d.ts.map +1 -0
  12. package/dist/factories/createSqlTag.js +170 -0
  13. package/dist/factories/createSqlTag.js.map +1 -0
  14. package/dist/factories/createSqlTag.test/array.test.d.ts +2 -0
  15. package/dist/factories/createSqlTag.test/array.test.d.ts.map +1 -0
  16. package/dist/factories/createSqlTag.test/array.test.js +76 -0
  17. package/dist/factories/createSqlTag.test/array.test.js.map +1 -0
  18. package/dist/factories/createSqlTag.test/date.test.d.ts +2 -0
  19. package/dist/factories/createSqlTag.test/date.test.d.ts.map +1 -0
  20. package/dist/factories/createSqlTag.test/date.test.js +25 -0
  21. package/dist/factories/createSqlTag.test/date.test.js.map +1 -0
  22. package/dist/factories/createSqlTag.test/identifier.test.d.ts +2 -0
  23. package/dist/factories/createSqlTag.test/identifier.test.d.ts.map +1 -0
  24. package/dist/factories/createSqlTag.test/identifier.test.js +38 -0
  25. package/dist/factories/createSqlTag.test/identifier.test.js.map +1 -0
  26. package/dist/factories/createSqlTag.test/interval.test.d.ts +2 -0
  27. package/dist/factories/createSqlTag.test/interval.test.d.ts.map +1 -0
  28. package/dist/factories/createSqlTag.test/interval.test.js +43 -0
  29. package/dist/factories/createSqlTag.test/interval.test.js.map +1 -0
  30. package/dist/factories/createSqlTag.test/join.test.d.ts +2 -0
  31. package/dist/factories/createSqlTag.test/join.test.d.ts.map +1 -0
  32. package/dist/factories/createSqlTag.test/join.test.js +87 -0
  33. package/dist/factories/createSqlTag.test/join.test.js.map +1 -0
  34. package/dist/factories/createSqlTag.test/json.test.d.ts +2 -0
  35. package/dist/factories/createSqlTag.test/json.test.d.ts.map +1 -0
  36. package/dist/factories/createSqlTag.test/json.test.js +88 -0
  37. package/dist/factories/createSqlTag.test/json.test.js.map +1 -0
  38. package/dist/factories/createSqlTag.test/jsonb.test.d.ts +2 -0
  39. package/dist/factories/createSqlTag.test/jsonb.test.d.ts.map +1 -0
  40. package/dist/factories/createSqlTag.test/jsonb.test.js +88 -0
  41. package/dist/factories/createSqlTag.test/jsonb.test.js.map +1 -0
  42. package/dist/factories/createSqlTag.test/literalValue.test.d.ts +2 -0
  43. package/dist/factories/createSqlTag.test/literalValue.test.d.ts.map +1 -0
  44. package/dist/factories/createSqlTag.test/literalValue.test.js +18 -0
  45. package/dist/factories/createSqlTag.test/literalValue.test.js.map +1 -0
  46. package/dist/factories/createSqlTag.test/sql.test.d.ts +2 -0
  47. package/dist/factories/createSqlTag.test/sql.test.d.ts.map +1 -0
  48. package/dist/factories/createSqlTag.test/sql.test.js +138 -0
  49. package/dist/factories/createSqlTag.test/sql.test.js.map +1 -0
  50. package/dist/factories/createSqlTag.test/timestamp.test.d.ts +2 -0
  51. package/dist/factories/createSqlTag.test/timestamp.test.d.ts.map +1 -0
  52. package/dist/factories/createSqlTag.test/timestamp.test.js +25 -0
  53. package/dist/factories/createSqlTag.test/timestamp.test.js.map +1 -0
  54. package/dist/factories/createSqlTag.test/type.test.d.ts +2 -0
  55. package/dist/factories/createSqlTag.test/type.test.d.ts.map +1 -0
  56. package/dist/factories/createSqlTag.test/type.test.js +19 -0
  57. package/dist/factories/createSqlTag.test/type.test.js.map +1 -0
  58. package/dist/factories/createSqlTag.test/typeAlias.test.d.ts +2 -0
  59. package/dist/factories/createSqlTag.test/typeAlias.test.d.ts.map +1 -0
  60. package/dist/factories/createSqlTag.test/typeAlias.test.js +47 -0
  61. package/dist/factories/createSqlTag.test/typeAlias.test.js.map +1 -0
  62. package/dist/factories/createSqlTag.test/unnest.test.d.ts +2 -0
  63. package/dist/factories/createSqlTag.test/unnest.test.d.ts.map +1 -0
  64. package/dist/factories/createSqlTag.test/unnest.test.js +127 -0
  65. package/dist/factories/createSqlTag.test/unnest.test.js.map +1 -0
  66. package/dist/factories/createSqlTokenSqlFragment.d.ts +3 -0
  67. package/dist/factories/createSqlTokenSqlFragment.d.ts.map +1 -0
  68. package/dist/factories/createSqlTokenSqlFragment.js +57 -0
  69. package/dist/factories/createSqlTokenSqlFragment.js.map +1 -0
  70. package/dist/index.d.ts +3 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +6 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/regexRules/slonikPlaceholderRegexRule.d.ts +2 -0
  75. package/dist/regexRules/slonikPlaceholderRegexRule.d.ts.map +1 -0
  76. package/dist/regexRules/slonikPlaceholderRegexRule.js +5 -0
  77. package/dist/regexRules/slonikPlaceholderRegexRule.js.map +1 -0
  78. package/dist/sqlFragmentFactories/createArraySqlFragment.d.ts +3 -0
  79. package/dist/sqlFragmentFactories/createArraySqlFragment.d.ts.map +1 -0
  80. package/dist/sqlFragmentFactories/createArraySqlFragment.js +48 -0
  81. package/dist/sqlFragmentFactories/createArraySqlFragment.js.map +1 -0
  82. package/dist/sqlFragmentFactories/createBinarySqlFragment.d.ts +3 -0
  83. package/dist/sqlFragmentFactories/createBinarySqlFragment.d.ts.map +1 -0
  84. package/dist/sqlFragmentFactories/createBinarySqlFragment.js +16 -0
  85. package/dist/sqlFragmentFactories/createBinarySqlFragment.js.map +1 -0
  86. package/dist/sqlFragmentFactories/createDateSqlFragment.d.ts +3 -0
  87. package/dist/sqlFragmentFactories/createDateSqlFragment.d.ts.map +1 -0
  88. package/dist/sqlFragmentFactories/createDateSqlFragment.js +16 -0
  89. package/dist/sqlFragmentFactories/createDateSqlFragment.js.map +1 -0
  90. package/dist/sqlFragmentFactories/createFragmentSqlFragment.d.ts +3 -0
  91. package/dist/sqlFragmentFactories/createFragmentSqlFragment.d.ts.map +1 -0
  92. package/dist/sqlFragmentFactories/createFragmentSqlFragment.js +34 -0
  93. package/dist/sqlFragmentFactories/createFragmentSqlFragment.js.map +1 -0
  94. package/dist/sqlFragmentFactories/createIdentifierSqlFragment.d.ts +3 -0
  95. package/dist/sqlFragmentFactories/createIdentifierSqlFragment.d.ts.map +1 -0
  96. package/dist/sqlFragmentFactories/createIdentifierSqlFragment.js +21 -0
  97. package/dist/sqlFragmentFactories/createIdentifierSqlFragment.js.map +1 -0
  98. package/dist/sqlFragmentFactories/createIntervalSqlFragment.d.ts +3 -0
  99. package/dist/sqlFragmentFactories/createIntervalSqlFragment.d.ts.map +1 -0
  100. package/dist/sqlFragmentFactories/createIntervalSqlFragment.js +57 -0
  101. package/dist/sqlFragmentFactories/createIntervalSqlFragment.js.map +1 -0
  102. package/dist/sqlFragmentFactories/createJsonSqlFragment.d.ts +3 -0
  103. package/dist/sqlFragmentFactories/createJsonSqlFragment.d.ts.map +1 -0
  104. package/dist/sqlFragmentFactories/createJsonSqlFragment.js +49 -0
  105. package/dist/sqlFragmentFactories/createJsonSqlFragment.js.map +1 -0
  106. package/dist/sqlFragmentFactories/createListSqlFragment.d.ts +3 -0
  107. package/dist/sqlFragmentFactories/createListSqlFragment.d.ts.map +1 -0
  108. package/dist/sqlFragmentFactories/createListSqlFragment.js +38 -0
  109. package/dist/sqlFragmentFactories/createListSqlFragment.js.map +1 -0
  110. package/dist/sqlFragmentFactories/createQuerySqlFragment.d.ts +3 -0
  111. package/dist/sqlFragmentFactories/createQuerySqlFragment.d.ts.map +1 -0
  112. package/dist/sqlFragmentFactories/createQuerySqlFragment.js +34 -0
  113. package/dist/sqlFragmentFactories/createQuerySqlFragment.js.map +1 -0
  114. package/dist/sqlFragmentFactories/createTimestampSqlFragment.d.ts +3 -0
  115. package/dist/sqlFragmentFactories/createTimestampSqlFragment.d.ts.map +1 -0
  116. package/dist/sqlFragmentFactories/createTimestampSqlFragment.js +18 -0
  117. package/dist/sqlFragmentFactories/createTimestampSqlFragment.js.map +1 -0
  118. package/dist/sqlFragmentFactories/createUnnestSqlFragment.d.ts +3 -0
  119. package/dist/sqlFragmentFactories/createUnnestSqlFragment.d.ts.map +1 -0
  120. package/dist/sqlFragmentFactories/createUnnestSqlFragment.js +81 -0
  121. package/dist/sqlFragmentFactories/createUnnestSqlFragment.js.map +1 -0
  122. package/dist/tokens.d.ts +14 -0
  123. package/dist/tokens.d.ts.map +1 -0
  124. package/dist/tokens.js +17 -0
  125. package/dist/tokens.js.map +1 -0
  126. package/dist/types.d.ts +99 -0
  127. package/dist/types.d.ts.map +1 -0
  128. package/dist/types.js +3 -0
  129. package/dist/types.js.map +1 -0
  130. package/dist/utilities/countArrayDimensions.d.ts +2 -0
  131. package/dist/utilities/countArrayDimensions.d.ts.map +1 -0
  132. package/dist/utilities/countArrayDimensions.js +14 -0
  133. package/dist/utilities/countArrayDimensions.js.map +1 -0
  134. package/dist/utilities/countArrayDimensions.test.d.ts +2 -0
  135. package/dist/utilities/countArrayDimensions.test.d.ts.map +1 -0
  136. package/dist/utilities/countArrayDimensions.test.js +13 -0
  137. package/dist/utilities/countArrayDimensions.test.js.map +1 -0
  138. package/dist/utilities/escapeIdentifier.d.ts +5 -0
  139. package/dist/utilities/escapeIdentifier.d.ts.map +1 -0
  140. package/dist/utilities/escapeIdentifier.js +12 -0
  141. package/dist/utilities/escapeIdentifier.js.map +1 -0
  142. package/dist/utilities/escapeIdentifier.test.d.ts +2 -0
  143. package/dist/utilities/escapeIdentifier.test.d.ts.map +1 -0
  144. package/dist/utilities/escapeIdentifier.test.js +13 -0
  145. package/dist/utilities/escapeIdentifier.test.js.map +1 -0
  146. package/dist/utilities/escapeLiteralValue.d.ts +5 -0
  147. package/dist/utilities/escapeLiteralValue.d.ts.map +1 -0
  148. package/dist/utilities/escapeLiteralValue.js +29 -0
  149. package/dist/utilities/escapeLiteralValue.js.map +1 -0
  150. package/dist/utilities/escapeLiteralValue.test.d.ts +2 -0
  151. package/dist/utilities/escapeLiteralValue.test.d.ts.map +1 -0
  152. package/dist/utilities/escapeLiteralValue.test.js +14 -0
  153. package/dist/utilities/escapeLiteralValue.test.js.map +1 -0
  154. package/dist/utilities/formatSlonikPlaceholder.d.ts +14 -0
  155. package/dist/utilities/formatSlonikPlaceholder.d.ts.map +1 -0
  156. package/dist/utilities/formatSlonikPlaceholder.js +20 -0
  157. package/dist/utilities/formatSlonikPlaceholder.js.map +1 -0
  158. package/dist/utilities/hasOwnProperty.d.ts +6 -0
  159. package/dist/utilities/hasOwnProperty.d.ts.map +1 -0
  160. package/dist/utilities/hasOwnProperty.js +12 -0
  161. package/dist/utilities/hasOwnProperty.js.map +1 -0
  162. package/dist/utilities/isPlainObject.d.ts +2 -0
  163. package/dist/utilities/isPlainObject.d.ts.map +1 -0
  164. package/dist/utilities/isPlainObject.js +16 -0
  165. package/dist/utilities/isPlainObject.js.map +1 -0
  166. package/dist/utilities/isPrimitiveValueExpression.d.ts +2 -0
  167. package/dist/utilities/isPrimitiveValueExpression.d.ts.map +1 -0
  168. package/dist/utilities/isPrimitiveValueExpression.js +12 -0
  169. package/dist/utilities/isPrimitiveValueExpression.js.map +1 -0
  170. package/dist/utilities/isSqlToken.d.ts +3 -0
  171. package/dist/utilities/isSqlToken.d.ts.map +1 -0
  172. package/dist/utilities/isSqlToken.js +35 -0
  173. package/dist/utilities/isSqlToken.js.map +1 -0
  174. package/dist/utilities/safeStringify.d.ts +2 -0
  175. package/dist/utilities/safeStringify.d.ts.map +1 -0
  176. package/dist/utilities/safeStringify.js +18 -0
  177. package/dist/utilities/safeStringify.js.map +1 -0
  178. package/dist/utilities/stripArrayNotation.d.ts +2 -0
  179. package/dist/utilities/stripArrayNotation.d.ts.map +1 -0
  180. package/dist/utilities/stripArrayNotation.js +12 -0
  181. package/dist/utilities/stripArrayNotation.js.map +1 -0
  182. package/dist/utilities/stripArrayNotation.test.d.ts +2 -0
  183. package/dist/utilities/stripArrayNotation.test.d.ts.map +1 -0
  184. package/dist/utilities/stripArrayNotation.test.js +13 -0
  185. package/dist/utilities/stripArrayNotation.test.js.map +1 -0
  186. package/package.json +88 -0
  187. package/src/Logger.ts +5 -0
  188. package/src/declarations.d.ts +8 -0
  189. package/src/factories/createPrimitiveValueExpressions.ts +43 -0
  190. package/src/factories/createSqlTag.test/array.test.ts +107 -0
  191. package/src/factories/createSqlTag.test/date.test.ts +26 -0
  192. package/src/factories/createSqlTag.test/identifier.test.ts +39 -0
  193. package/src/factories/createSqlTag.test/interval.test.ts +44 -0
  194. package/src/factories/createSqlTag.test/join.test.ts +127 -0
  195. package/src/factories/createSqlTag.test/json.test.ts +106 -0
  196. package/src/factories/createSqlTag.test/jsonb.test.ts +106 -0
  197. package/src/factories/createSqlTag.test/literalValue.test.ts +17 -0
  198. package/src/factories/createSqlTag.test/sql.test.ts +165 -0
  199. package/src/factories/createSqlTag.test/timestamp.test.ts +29 -0
  200. package/src/factories/createSqlTag.test/type.test.ts +17 -0
  201. package/src/factories/createSqlTag.test/typeAlias.test.ts +53 -0
  202. package/src/factories/createSqlTag.test/unnest.test.ts +173 -0
  203. package/src/factories/createSqlTag.ts +256 -0
  204. package/src/factories/createSqlTokenSqlFragment.ts +60 -0
  205. package/src/index.ts +2 -0
  206. package/src/regexRules/slonikPlaceholderRegexRule.ts +1 -0
  207. package/src/sqlFragmentFactories/createArraySqlFragment.ts +67 -0
  208. package/src/sqlFragmentFactories/createBinarySqlFragment.ts +17 -0
  209. package/src/sqlFragmentFactories/createDateSqlFragment.ts +19 -0
  210. package/src/sqlFragmentFactories/createFragmentSqlFragment.ts +48 -0
  211. package/src/sqlFragmentFactories/createIdentifierSqlFragment.ts +24 -0
  212. package/src/sqlFragmentFactories/createIntervalSqlFragment.ts +71 -0
  213. package/src/sqlFragmentFactories/createJsonSqlFragment.ts +66 -0
  214. package/src/sqlFragmentFactories/createListSqlFragment.ts +48 -0
  215. package/src/sqlFragmentFactories/createQuerySqlFragment.ts +48 -0
  216. package/src/sqlFragmentFactories/createTimestampSqlFragment.ts +22 -0
  217. package/src/sqlFragmentFactories/createUnnestSqlFragment.ts +118 -0
  218. package/src/tokens.ts +14 -0
  219. package/src/types.ts +189 -0
  220. package/src/utilities/countArrayDimensions.test.ts +8 -0
  221. package/src/utilities/countArrayDimensions.ts +12 -0
  222. package/src/utilities/escapeIdentifier.test.ts +8 -0
  223. package/src/utilities/escapeIdentifier.ts +8 -0
  224. package/src/utilities/escapeLiteralValue.test.ts +9 -0
  225. package/src/utilities/escapeLiteralValue.ts +26 -0
  226. package/src/utilities/formatSlonikPlaceholder.ts +15 -0
  227. package/src/utilities/hasOwnProperty.ts +10 -0
  228. package/src/utilities/isPlainObject.ts +14 -0
  229. package/src/utilities/isPrimitiveValueExpression.ts +11 -0
  230. package/src/utilities/isSqlToken.ts +52 -0
  231. package/src/utilities/safeStringify.ts +25 -0
  232. package/src/utilities/stripArrayNotation.test.ts +8 -0
  233. 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
+ });