@uql/core 3.1.0 → 3.1.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 (170) hide show
  1. package/CHANGELOG.md +134 -176
  2. package/README.md +413 -0
  3. package/package.json +31 -26
  4. package/dist/package.json +0 -131
  5. package/src/@types/index.d.ts +0 -1
  6. package/src/@types/jest.d.ts +0 -6
  7. package/src/browser/http/bus.spec.ts +0 -22
  8. package/src/browser/http/bus.ts +0 -17
  9. package/src/browser/http/http.spec.ts +0 -70
  10. package/src/browser/http/http.ts +0 -55
  11. package/src/browser/http/index.ts +0 -2
  12. package/src/browser/index.ts +0 -4
  13. package/src/browser/options.spec.ts +0 -37
  14. package/src/browser/options.ts +0 -18
  15. package/src/browser/querier/genericClientRepository.spec.ts +0 -105
  16. package/src/browser/querier/genericClientRepository.ts +0 -49
  17. package/src/browser/querier/httpQuerier.ts +0 -82
  18. package/src/browser/querier/index.ts +0 -3
  19. package/src/browser/querier/querier.util.spec.ts +0 -35
  20. package/src/browser/querier/querier.util.ts +0 -18
  21. package/src/browser/type/clientQuerier.ts +0 -45
  22. package/src/browser/type/clientQuerierPool.ts +0 -5
  23. package/src/browser/type/clientRepository.ts +0 -22
  24. package/src/browser/type/index.ts +0 -4
  25. package/src/browser/type/request.ts +0 -25
  26. package/src/dialect/abstractDialect.ts +0 -28
  27. package/src/dialect/abstractSqlDialect-spec.ts +0 -1309
  28. package/src/dialect/abstractSqlDialect.ts +0 -805
  29. package/src/dialect/index.ts +0 -3
  30. package/src/dialect/namingStrategy.spec.ts +0 -52
  31. package/src/dialect/queryContext.ts +0 -69
  32. package/src/entity/decorator/definition.spec.ts +0 -736
  33. package/src/entity/decorator/definition.ts +0 -265
  34. package/src/entity/decorator/entity.ts +0 -8
  35. package/src/entity/decorator/field.ts +0 -9
  36. package/src/entity/decorator/id.ts +0 -9
  37. package/src/entity/decorator/index.ts +0 -5
  38. package/src/entity/decorator/relation.spec.ts +0 -41
  39. package/src/entity/decorator/relation.ts +0 -34
  40. package/src/entity/index.ts +0 -1
  41. package/src/express/@types/express.d.ts +0 -8
  42. package/src/express/@types/index.d.ts +0 -1
  43. package/src/express/index.ts +0 -2
  44. package/src/express/querierMiddleware.ts +0 -217
  45. package/src/express/query.util.spec.ts +0 -40
  46. package/src/express/query.util.ts +0 -21
  47. package/src/index.ts +0 -9
  48. package/src/maria/index.ts +0 -3
  49. package/src/maria/mariaDialect.spec.ts +0 -207
  50. package/src/maria/mariaDialect.ts +0 -42
  51. package/src/maria/mariaQuerierPool.test.ts +0 -23
  52. package/src/maria/mariadbQuerier.test.ts +0 -23
  53. package/src/maria/mariadbQuerier.ts +0 -45
  54. package/src/maria/mariadbQuerierPool.ts +0 -21
  55. package/src/migrate/cli.ts +0 -301
  56. package/src/migrate/generator/index.ts +0 -4
  57. package/src/migrate/generator/mongoSchemaGenerator.spec.ts +0 -112
  58. package/src/migrate/generator/mongoSchemaGenerator.ts +0 -115
  59. package/src/migrate/generator/mysqlSchemaGenerator.spec.ts +0 -34
  60. package/src/migrate/generator/mysqlSchemaGenerator.ts +0 -92
  61. package/src/migrate/generator/postgresSchemaGenerator.spec.ts +0 -44
  62. package/src/migrate/generator/postgresSchemaGenerator.ts +0 -127
  63. package/src/migrate/generator/sqliteSchemaGenerator.spec.ts +0 -33
  64. package/src/migrate/generator/sqliteSchemaGenerator.ts +0 -81
  65. package/src/migrate/index.ts +0 -41
  66. package/src/migrate/introspection/index.ts +0 -4
  67. package/src/migrate/introspection/mongoIntrospector.spec.ts +0 -75
  68. package/src/migrate/introspection/mongoIntrospector.ts +0 -47
  69. package/src/migrate/introspection/mysqlIntrospector.spec.ts +0 -113
  70. package/src/migrate/introspection/mysqlIntrospector.ts +0 -278
  71. package/src/migrate/introspection/postgresIntrospector.spec.ts +0 -112
  72. package/src/migrate/introspection/postgresIntrospector.ts +0 -329
  73. package/src/migrate/introspection/sqliteIntrospector.spec.ts +0 -112
  74. package/src/migrate/introspection/sqliteIntrospector.ts +0 -296
  75. package/src/migrate/migrator-mongo.test.ts +0 -54
  76. package/src/migrate/migrator.spec.ts +0 -255
  77. package/src/migrate/migrator.test.ts +0 -94
  78. package/src/migrate/migrator.ts +0 -719
  79. package/src/migrate/namingStrategy.spec.ts +0 -22
  80. package/src/migrate/schemaGenerator-advanced.spec.ts +0 -138
  81. package/src/migrate/schemaGenerator.spec.ts +0 -190
  82. package/src/migrate/schemaGenerator.ts +0 -478
  83. package/src/migrate/storage/databaseStorage.spec.ts +0 -69
  84. package/src/migrate/storage/databaseStorage.ts +0 -100
  85. package/src/migrate/storage/index.ts +0 -2
  86. package/src/migrate/storage/jsonStorage.ts +0 -58
  87. package/src/migrate/type.ts +0 -1
  88. package/src/mongo/index.ts +0 -3
  89. package/src/mongo/mongoDialect.spec.ts +0 -251
  90. package/src/mongo/mongoDialect.ts +0 -238
  91. package/src/mongo/mongodbQuerier.test.ts +0 -45
  92. package/src/mongo/mongodbQuerier.ts +0 -256
  93. package/src/mongo/mongodbQuerierPool.test.ts +0 -25
  94. package/src/mongo/mongodbQuerierPool.ts +0 -24
  95. package/src/mysql/index.ts +0 -3
  96. package/src/mysql/mysql2Querier.test.ts +0 -20
  97. package/src/mysql/mysql2Querier.ts +0 -49
  98. package/src/mysql/mysql2QuerierPool.test.ts +0 -20
  99. package/src/mysql/mysql2QuerierPool.ts +0 -21
  100. package/src/mysql/mysqlDialect.spec.ts +0 -20
  101. package/src/mysql/mysqlDialect.ts +0 -16
  102. package/src/namingStrategy/defaultNamingStrategy.ts +0 -18
  103. package/src/namingStrategy/index.spec.ts +0 -36
  104. package/src/namingStrategy/index.ts +0 -2
  105. package/src/namingStrategy/snakeCaseNamingStrategy.ts +0 -15
  106. package/src/options.spec.ts +0 -41
  107. package/src/options.ts +0 -18
  108. package/src/postgres/index.ts +0 -3
  109. package/src/postgres/manual-types.d.ts +0 -4
  110. package/src/postgres/pgQuerier.test.ts +0 -25
  111. package/src/postgres/pgQuerier.ts +0 -45
  112. package/src/postgres/pgQuerierPool.test.ts +0 -28
  113. package/src/postgres/pgQuerierPool.ts +0 -21
  114. package/src/postgres/postgresDialect.spec.ts +0 -428
  115. package/src/postgres/postgresDialect.ts +0 -144
  116. package/src/querier/abstractQuerier-test.ts +0 -584
  117. package/src/querier/abstractQuerier.ts +0 -353
  118. package/src/querier/abstractQuerierPool-test.ts +0 -20
  119. package/src/querier/abstractQuerierPool.ts +0 -18
  120. package/src/querier/abstractSqlQuerier-spec.ts +0 -979
  121. package/src/querier/abstractSqlQuerier-test.ts +0 -21
  122. package/src/querier/abstractSqlQuerier.ts +0 -138
  123. package/src/querier/decorator/index.ts +0 -3
  124. package/src/querier/decorator/injectQuerier.spec.ts +0 -74
  125. package/src/querier/decorator/injectQuerier.ts +0 -45
  126. package/src/querier/decorator/serialized.spec.ts +0 -98
  127. package/src/querier/decorator/serialized.ts +0 -13
  128. package/src/querier/decorator/transactional.spec.ts +0 -240
  129. package/src/querier/decorator/transactional.ts +0 -56
  130. package/src/querier/index.ts +0 -4
  131. package/src/repository/genericRepository.spec.ts +0 -111
  132. package/src/repository/genericRepository.ts +0 -74
  133. package/src/repository/index.ts +0 -1
  134. package/src/sqlite/index.ts +0 -3
  135. package/src/sqlite/manual-types.d.ts +0 -4
  136. package/src/sqlite/sqliteDialect.spec.ts +0 -155
  137. package/src/sqlite/sqliteDialect.ts +0 -76
  138. package/src/sqlite/sqliteQuerier.spec.ts +0 -36
  139. package/src/sqlite/sqliteQuerier.test.ts +0 -21
  140. package/src/sqlite/sqliteQuerier.ts +0 -37
  141. package/src/sqlite/sqliteQuerierPool.test.ts +0 -12
  142. package/src/sqlite/sqliteQuerierPool.ts +0 -38
  143. package/src/test/entityMock.ts +0 -375
  144. package/src/test/index.ts +0 -3
  145. package/src/test/it.util.ts +0 -69
  146. package/src/test/spec.util.ts +0 -57
  147. package/src/type/entity.ts +0 -218
  148. package/src/type/index.ts +0 -9
  149. package/src/type/migration.ts +0 -241
  150. package/src/type/namingStrategy.ts +0 -17
  151. package/src/type/querier.ts +0 -143
  152. package/src/type/querierPool.ts +0 -26
  153. package/src/type/query.ts +0 -506
  154. package/src/type/repository.ts +0 -142
  155. package/src/type/universalQuerier.ts +0 -133
  156. package/src/type/utility.ts +0 -21
  157. package/src/util/dialect.util-extra.spec.ts +0 -96
  158. package/src/util/dialect.util.spec.ts +0 -23
  159. package/src/util/dialect.util.ts +0 -134
  160. package/src/util/index.ts +0 -5
  161. package/src/util/object.util.spec.ts +0 -29
  162. package/src/util/object.util.ts +0 -27
  163. package/src/util/raw.ts +0 -11
  164. package/src/util/sql.util-extra.spec.ts +0 -17
  165. package/src/util/sql.util.spec.ts +0 -208
  166. package/src/util/sql.util.ts +0 -104
  167. package/src/util/string.util.spec.ts +0 -46
  168. package/src/util/string.util.ts +0 -35
  169. package/tsconfig.build.json +0 -5
  170. package/tsconfig.json +0 -8
@@ -1,28 +0,0 @@
1
- import { types } from 'pg';
2
- import { AbstractQuerierPoolIt } from '../querier/abstractQuerierPool-test.js';
3
- import { createSpec } from '../test/index.js';
4
- import type { PgQuerier } from './pgQuerier.js';
5
- import { PgQuerierPool } from './pgQuerierPool.js';
6
-
7
- types.setTypeParser(types.builtins.INT8, (value: string) => Number.parseInt(value, 10));
8
- types.setTypeParser(types.builtins.FLOAT8, (value: string) => Number.parseFloat(value));
9
- types.setTypeParser(types.builtins.NUMERIC, (value: string) => Number.parseFloat(value));
10
- types.setTypeParser(types.builtins.INT8, (value: string) => Number.parseInt(value, 10));
11
- types.setTypeParser(types.builtins.FLOAT8, (value: string) => Number.parseFloat(value));
12
- types.setTypeParser(types.builtins.NUMERIC, (value: string) => Number.parseFloat(value));
13
-
14
- export class PostgresQuerierPoolIt extends AbstractQuerierPoolIt<PgQuerier> {
15
- constructor() {
16
- super(
17
- new PgQuerierPool({
18
- host: '0.0.0.0',
19
- port: 5442,
20
- user: 'test',
21
- password: 'test',
22
- database: 'test',
23
- }),
24
- );
25
- }
26
- }
27
-
28
- createSpec(new PostgresQuerierPoolIt());
@@ -1,21 +0,0 @@
1
- import pg from 'pg';
2
- import { AbstractQuerierPool } from '../querier/index.js';
3
- import type { ExtraOptions } from '../type/index.js';
4
- import { PgQuerier } from './pgQuerier.js';
5
-
6
- export class PgQuerierPool extends AbstractQuerierPool<PgQuerier> {
7
- readonly pool: pg.Pool;
8
-
9
- constructor(opts: pg.PoolConfig, extra?: ExtraOptions) {
10
- super('postgres', extra);
11
- this.pool = new pg.Pool(opts);
12
- }
13
-
14
- async getQuerier() {
15
- return new PgQuerier(() => this.pool.connect(), this.extra);
16
- }
17
-
18
- async end() {
19
- await this.pool.end();
20
- }
21
- }
@@ -1,428 +0,0 @@
1
- import { expect } from 'bun:test';
2
- import {
3
- Company,
4
- createSpec,
5
- Item,
6
- ItemTag,
7
- Profile,
8
- TaxCategory,
9
- User,
10
- UserWithNonUpdatableId,
11
- } from '../test/index.js';
12
- import { raw } from '../util/index.js';
13
- import { PostgresDialect } from './postgresDialect.js';
14
-
15
- class PostgresDialectSpec {
16
- readonly dialect = new PostgresDialect();
17
-
18
- protected exec(fn: (ctx: any) => void): { sql: string; values: unknown[] } {
19
- const ctx = this.dialect.createContext();
20
- fn(ctx);
21
- return { sql: ctx.sql, values: ctx.values };
22
- }
23
-
24
- shouldBeValidEscapeCharacter() {
25
- expect(this.dialect.escapeIdChar).toBe('"');
26
- }
27
-
28
- shouldBeginTransaction() {
29
- expect(this.dialect.beginTransactionCommand).toBe('BEGIN TRANSACTION');
30
- }
31
-
32
- shouldInsertMany() {
33
- const { sql, values } = this.exec((ctx) =>
34
- this.dialect.insert(ctx, User, [
35
- {
36
- name: 'Some name 1',
37
- email: 'someemail1@example.com',
38
- createdAt: 123,
39
- },
40
- {
41
- name: 'Some name 2',
42
- email: 'someemail2@example.com',
43
- createdAt: 456,
44
- },
45
- {
46
- name: 'Some name 3',
47
- email: 'someemail3@example.com',
48
- createdAt: 789,
49
- },
50
- ]),
51
- );
52
- expect(sql).toBe(
53
- 'INSERT INTO "User" ("name", "email", "createdAt") VALUES' +
54
- ' ($1, $2, $3), ($4, $5, $6), ($7, $8, $9)' +
55
- ' RETURNING "id" "id"',
56
- );
57
- expect(values).toEqual([
58
- 'Some name 1',
59
- 'someemail1@example.com',
60
- 123,
61
- 'Some name 2',
62
- 'someemail2@example.com',
63
- 456,
64
- 'Some name 3',
65
- 'someemail3@example.com',
66
- 789,
67
- ]);
68
- }
69
-
70
- shouldInsertOne() {
71
- const { sql, values } = this.exec((ctx) =>
72
- this.dialect.insert(ctx, User, {
73
- name: 'Some Name',
74
- email: 'someemail@example.com',
75
- createdAt: 123,
76
- }),
77
- );
78
- expect(sql).toBe('INSERT INTO "User" ("name", "email", "createdAt") VALUES ($1, $2, $3) RETURNING "id" "id"');
79
- expect(values).toEqual(['Some Name', 'someemail@example.com', 123]);
80
- }
81
-
82
- shouldInsertWithOnInsertId() {
83
- const { sql, values } = this.exec((ctx) =>
84
- this.dialect.insert(ctx, TaxCategory, {
85
- name: 'Some Name',
86
- createdAt: 123,
87
- }),
88
- );
89
- expect(sql).toMatch(
90
- /^INSERT INTO "TaxCategory" \("name", "createdAt", "pk"\) VALUES \(\$1, \$2, \$3\) RETURNING "pk" "id"$/,
91
- );
92
- expect(values[0]).toBe('Some Name');
93
- expect(values[1]).toBe(123);
94
- expect(values[2]).toMatch(/.+/);
95
- }
96
-
97
- shouldUpsert() {
98
- const { sql, values } = this.exec((ctx) =>
99
- this.dialect.upsert(
100
- ctx,
101
- User,
102
- { id: true },
103
- {
104
- id: 1,
105
- name: 'Some Name',
106
- createdAt: 123,
107
- },
108
- ),
109
- );
110
- expect(sql).toMatch(
111
- /^INSERT INTO "User" \("id", "name", "createdAt", "updatedAt"\) VALUES \(\$1, \$2, \$3, \$4\) ON CONFLICT \("id"\) DO UPDATE SET "name" = EXCLUDED."name", "createdAt" = EXCLUDED."createdAt", "updatedAt" = EXCLUDED."updatedAt" RETURNING "id" "id"$/,
112
- );
113
- expect(values).toEqual([1, 'Some Name', 123, expect.any(Number)]);
114
- }
115
-
116
- shouldUpsertWithDifferentColumnNames() {
117
- const { sql, values } = this.exec((ctx) =>
118
- this.dialect.upsert(
119
- ctx,
120
- Profile,
121
- { pk: true },
122
- {
123
- pk: 1,
124
- picture: 'image.jpg',
125
- },
126
- ),
127
- );
128
- expect(sql).toMatch(
129
- /^INSERT INTO "user_profile" \("pk", "image", "updatedAt", "createdAt"\) VALUES \(\$1, \$2, \$3, \$4\) ON CONFLICT \("pk"\) DO UPDATE SET "image" = EXCLUDED."image", "updatedAt" = EXCLUDED."updatedAt" RETURNING "pk" "id"$/,
130
- );
131
- expect(values).toEqual([1, 'image.jpg', expect.any(Number), expect.any(Number)]);
132
- }
133
-
134
- shouldUpsertWithNonUpdatableFields() {
135
- const { sql, values } = this.exec((ctx) =>
136
- this.dialect.upsert(
137
- ctx,
138
- User,
139
- { id: true },
140
- {
141
- id: 1,
142
- email: 'a@b.com',
143
- },
144
- ),
145
- );
146
- expect(sql).toMatch(
147
- /^INSERT INTO "User" \("id", "email", "updatedAt", "createdAt"\) VALUES \(\$1, \$2, \$3, \$4\) ON CONFLICT \("id"\) DO UPDATE SET "updatedAt" = EXCLUDED."updatedAt" RETURNING "id" "id"$/,
148
- );
149
- expect(values).toEqual([1, 'a@b.com', expect.any(Number), expect.any(Number)]);
150
- }
151
-
152
- shouldUpsertWithNonUpdatableId() {
153
- const { sql, values } = this.exec((ctx) =>
154
- this.dialect.upsert(
155
- ctx,
156
- UserWithNonUpdatableId,
157
- { id: true },
158
- {
159
- id: 1,
160
- name: 'Some Name',
161
- },
162
- ),
163
- );
164
- expect(sql).toBe(
165
- 'INSERT INTO "UserWithNonUpdatableId" ("id", "name") VALUES ($1, $2) ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name" RETURNING "id" "id"',
166
- );
167
- expect(values).toEqual([1, 'Some Name']);
168
- }
169
-
170
- shouldUpsertWithDoNothing() {
171
- const { sql, values } = this.exec((ctx) =>
172
- this.dialect.upsert(
173
- ctx,
174
- ItemTag,
175
- { id: true },
176
- {
177
- id: 1,
178
- },
179
- ),
180
- );
181
- expect(sql).toBe('INSERT INTO "ItemTag" ("id") VALUES ($1) ON CONFLICT ("id") DO NOTHING RETURNING "id" "id"');
182
- expect(values).toEqual([1]);
183
- }
184
-
185
- shouldUpsertWithCompositeKeys() {
186
- const { sql, values } = this.exec((ctx) =>
187
- this.dialect.upsert(
188
- ctx,
189
- ItemTag,
190
- { itemId: true, tagId: true },
191
- {
192
- itemId: 1,
193
- tagId: 2,
194
- },
195
- ),
196
- );
197
- expect(sql).toBe(
198
- 'INSERT INTO "ItemTag" ("itemId", "tagId") VALUES ($1, $2) ON CONFLICT ("itemId", "tagId") DO NOTHING RETURNING "id" "id"',
199
- );
200
- expect(values).toEqual([1, 2]);
201
- }
202
-
203
- shouldUpsertWithOnUpdateField() {
204
- const { sql, values } = this.exec((ctx) =>
205
- this.dialect.upsert(
206
- ctx,
207
- User,
208
- { id: true },
209
- {
210
- id: 1,
211
- name: 'Some Name',
212
- },
213
- ),
214
- );
215
- expect(sql).toMatch(
216
- /^INSERT INTO "User" \(.*"id".*"name".*"updatedAt".*"createdAt".*\) VALUES \(.*\$1, \$2, \$3, \$4.*\) ON CONFLICT \("id"\) DO UPDATE SET .*"name" = EXCLUDED."name".*"updatedAt" = EXCLUDED."updatedAt".*$/,
217
- );
218
- expect(values).toEqual([1, 'Some Name', expect.any(Number), expect.any(Number)]);
219
- }
220
-
221
- shouldUpsertWithVirtualField() {
222
- const { sql, values } = this.exec((ctx) =>
223
- this.dialect.upsert(
224
- ctx,
225
- Item,
226
- { id: true },
227
- {
228
- id: 1,
229
- name: 'Some Item',
230
- tagsCount: 5,
231
- },
232
- ),
233
- );
234
- expect(sql).toMatch(
235
- /^INSERT INTO "Item" \("id", "name", "updatedAt", "createdAt"\) VALUES \(\$1, \$2, \$3, \$4\) ON CONFLICT \("id"\) DO UPDATE SET "name" = EXCLUDED."name", "updatedAt" = EXCLUDED."updatedAt" RETURNING "id" "id"$/,
236
- );
237
- expect(values).toEqual([1, 'Some Item', expect.any(Number), expect.any(Number)]);
238
- }
239
-
240
- shouldFind$istartsWith() {
241
- let res = this.exec((ctx) =>
242
- this.dialect.find(ctx, User, {
243
- $select: ['id'],
244
- $where: { name: { $istartsWith: 'Some' } },
245
- $sort: { name: 1, id: -1 },
246
- $skip: 0,
247
- $limit: 50,
248
- }),
249
- );
250
- expect(res.sql).toBe('SELECT "id" FROM "User" WHERE "name" ILIKE $1 ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0');
251
- expect(res.values).toEqual(['Some%']);
252
-
253
- res = this.exec((ctx) =>
254
- this.dialect.find(ctx, User, {
255
- $select: { id: true },
256
- $where: { name: { $istartsWith: 'Some', $ne: 'Something' } },
257
- $sort: { name: 1, id: -1 },
258
- $skip: 0,
259
- $limit: 50,
260
- }),
261
- );
262
- expect(res.sql).toBe(
263
- 'SELECT "id" FROM "User" WHERE ("name" ILIKE $1 AND "name" <> $2) ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0',
264
- );
265
- expect(res.values).toEqual(['Some%', 'Something']);
266
- }
267
-
268
- shouldFind$iendsWith() {
269
- let res = this.exec((ctx) =>
270
- this.dialect.find(ctx, User, {
271
- $select: ['id'],
272
- $where: { name: { $iendsWith: 'Some' } },
273
- $sort: { name: 1, id: -1 },
274
- $skip: 0,
275
- $limit: 50,
276
- }),
277
- );
278
- expect(res.sql).toBe('SELECT "id" FROM "User" WHERE "name" ILIKE $1 ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0');
279
- expect(res.values).toEqual(['%Some']);
280
-
281
- res = this.exec((ctx) =>
282
- this.dialect.find(ctx, User, {
283
- $select: { id: true },
284
- $where: { name: { $iendsWith: 'Some', $ne: 'Something' } },
285
- $sort: { name: 1, id: -1 },
286
- $skip: 0,
287
- $limit: 50,
288
- }),
289
- );
290
- expect(res.sql).toBe(
291
- 'SELECT "id" FROM "User" WHERE ("name" ILIKE $1 AND "name" <> $2) ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0',
292
- );
293
- expect(res.values).toEqual(['%Some', 'Something']);
294
- }
295
-
296
- shouldFind$iincludes() {
297
- let res = this.exec((ctx) =>
298
- this.dialect.find(ctx, User, {
299
- $select: ['id'],
300
- $where: { name: { $iincludes: 'Some' } },
301
- $sort: { name: 1, id: -1 },
302
- $skip: 0,
303
- $limit: 50,
304
- }),
305
- );
306
- expect(res.sql).toBe('SELECT "id" FROM "User" WHERE "name" ILIKE $1 ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0');
307
- expect(res.values).toEqual(['%Some%']);
308
-
309
- res = this.exec((ctx) =>
310
- this.dialect.find(ctx, User, {
311
- $select: { id: true },
312
- $where: { name: { $iincludes: 'Some', $ne: 'Something' } },
313
- $sort: { name: 1, id: -1 },
314
- $skip: 0,
315
- $limit: 50,
316
- }),
317
- );
318
- expect(res.sql).toBe(
319
- 'SELECT "id" FROM "User" WHERE ("name" ILIKE $1 AND "name" <> $2) ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0',
320
- );
321
- expect(res.values).toEqual(['%Some%', 'Something']);
322
- }
323
-
324
- shouldFind$ilike() {
325
- let res = this.exec((ctx) =>
326
- this.dialect.find(ctx, User, {
327
- $select: ['id'],
328
- $where: { name: { $ilike: 'Some' } },
329
- $sort: { name: 1, id: -1 },
330
- $skip: 0,
331
- $limit: 50,
332
- }),
333
- );
334
- expect(res.sql).toBe('SELECT "id" FROM "User" WHERE "name" ILIKE $1 ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0');
335
- expect(res.values).toEqual(['Some']);
336
-
337
- res = this.exec((ctx) =>
338
- this.dialect.find(ctx, User, {
339
- $select: { id: true },
340
- $where: { name: { $ilike: 'Some', $ne: 'Something' } },
341
- $sort: { name: 1, id: -1 },
342
- $skip: 0,
343
- $limit: 50,
344
- }),
345
- );
346
- expect(res.sql).toBe(
347
- 'SELECT "id" FROM "User" WHERE ("name" ILIKE $1 AND "name" <> $2) ORDER BY "name", "id" DESC LIMIT 50 OFFSET 0',
348
- );
349
- expect(res.values).toEqual(['Some', 'Something']);
350
- }
351
-
352
- shouldFind$regex() {
353
- const { sql, values } = this.exec((ctx) =>
354
- this.dialect.find(ctx, User, {
355
- $select: { id: true },
356
- $where: { name: { $regex: '^some' } },
357
- }),
358
- );
359
- expect(sql).toBe('SELECT "id" FROM "User" WHERE "name" ~ $1');
360
- expect(values).toEqual(['^some']);
361
- }
362
-
363
- shouldFind$text() {
364
- let res = this.exec((ctx) =>
365
- this.dialect.find(ctx, Item, {
366
- $select: { id: true },
367
- $where: { $text: { $fields: ['name', 'description'], $value: 'some text' }, code: '1' },
368
- $limit: 30,
369
- }),
370
- );
371
- expect(res.sql).toBe(
372
- 'SELECT "id" FROM "Item" WHERE to_tsvector("name" || \' \' || "description") @@ to_tsquery($1) AND "code" = $2 LIMIT 30',
373
- );
374
- expect(res.values).toEqual(['some text', '1']);
375
-
376
- res = this.exec((ctx) =>
377
- this.dialect.find(ctx, User, {
378
- $select: { id: true },
379
- $where: {
380
- $text: { $fields: ['name'], $value: 'something' },
381
- name: { $ne: 'other unwanted' },
382
- creatorId: 1,
383
- },
384
- $limit: 10,
385
- }),
386
- );
387
- expect(res.sql).toBe(
388
- 'SELECT "id" FROM "User" WHERE to_tsvector("name") @@ to_tsquery($1) AND "name" <> $2 AND "creatorId" = $3 LIMIT 10',
389
- );
390
- expect(res.values).toEqual(['something', 'other unwanted', 1]);
391
- }
392
-
393
- shouldUpdateWithRawString() {
394
- const { sql, values } = this.exec((ctx) =>
395
- this.dialect.update(
396
- ctx,
397
- Company,
398
- { $where: { id: 1 } },
399
- {
400
- kind: raw("jsonb_set(kind, '{open}', to_jsonb(1))"),
401
- updatedAt: 123,
402
- },
403
- ),
404
- );
405
- expect(sql).toBe(
406
- 'UPDATE "Company" SET "kind" = jsonb_set(kind, \'{open}\', to_jsonb(1)), "updatedAt" = $1 WHERE "id" = $2',
407
- );
408
- expect(values).toEqual([123, 1]);
409
- }
410
-
411
- shouldUpdateWithJsonbField() {
412
- const { sql, values } = this.exec((ctx) =>
413
- this.dialect.update(
414
- ctx,
415
- Company,
416
- { $where: { id: 1 } },
417
- {
418
- kind: { private: 1 },
419
- updatedAt: 123,
420
- },
421
- ),
422
- );
423
- expect(sql).toBe('UPDATE "Company" SET "kind" = $1::jsonb, "updatedAt" = $2 WHERE "id" = $3');
424
- expect(values).toEqual(['{"private":1}', 123, 1]);
425
- }
426
- }
427
-
428
- createSpec(new PostgresDialectSpec());
@@ -1,144 +0,0 @@
1
- import sqlstring from 'sqlstring-sqlite';
2
- import { AbstractSqlDialect } from '../dialect/index.js';
3
- import { getMeta } from '../entity/index.js';
4
- import {
5
- type FieldKey,
6
- type FieldOptions,
7
- type NamingStrategy,
8
- type QueryComparisonOptions,
9
- type QueryConflictPaths,
10
- type QueryContext,
11
- type QueryOptions,
12
- QueryRaw,
13
- type QueryTextSearchOptions,
14
- type QueryWhereFieldOperatorMap,
15
- type QueryWhereMap,
16
- type Type,
17
- } from '../type/index.js';
18
-
19
- export class PostgresDialect extends AbstractSqlDialect {
20
- constructor(namingStrategy?: NamingStrategy) {
21
- super(namingStrategy, '"', 'BEGIN TRANSACTION');
22
- }
23
-
24
- override addValue(values: unknown[], value: unknown): string {
25
- values.push(value);
26
- return this.placeholder(values.length);
27
- }
28
-
29
- override placeholder(index: number): string {
30
- return `$${index}`;
31
- }
32
-
33
- override insert<E>(ctx: QueryContext, entity: Type<E>, payload: E | E[], opts?: QueryOptions): void {
34
- super.insert(ctx, entity, payload, opts);
35
- ctx.append(' ' + this.returningId(entity));
36
- }
37
-
38
- override upsert<E>(ctx: QueryContext, entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: E): void {
39
- const meta = getMeta(entity);
40
- const update = this.getUpsertUpdateAssignments(ctx, meta, conflictPaths, payload, (name) => `EXCLUDED.${name}`);
41
- const keysStr = this.getUpsertConflictPathsStr(meta, conflictPaths);
42
- const onConflict = update ? `DO UPDATE SET ${update}` : 'DO NOTHING';
43
- super.insert(ctx, entity, payload);
44
- ctx.append(` ON CONFLICT (${keysStr}) ${onConflict} ${this.returningId(entity)}`);
45
- }
46
-
47
- override compare<E, K extends keyof QueryWhereMap<E>>(
48
- ctx: QueryContext,
49
- entity: Type<E>,
50
- key: K,
51
- val: QueryWhereMap<E>[K],
52
- opts: QueryComparisonOptions = {},
53
- ): void {
54
- if (key === '$text') {
55
- const meta = getMeta(entity);
56
- const search = val as QueryTextSearchOptions<E>;
57
- const fields = search.$fields
58
- .map((fKey) => {
59
- const field = meta.fields[fKey];
60
- const columnName = this.resolveColumnName(fKey as string, field);
61
- return this.escapeId(columnName);
62
- })
63
- .join(` || ' ' || `);
64
- ctx.append(`to_tsvector(${fields}) @@ to_tsquery(`);
65
- ctx.addValue(search.$value);
66
- ctx.append(')');
67
- return;
68
- }
69
- super.compare(ctx, entity, key, val, opts);
70
- }
71
-
72
- override compareFieldOperator<E, K extends keyof QueryWhereFieldOperatorMap<E>>(
73
- ctx: QueryContext,
74
- entity: Type<E>,
75
- key: FieldKey<E>,
76
- op: K,
77
- val: QueryWhereFieldOperatorMap<E>[K],
78
- opts: QueryOptions = {},
79
- ): void {
80
- switch (op) {
81
- case '$istartsWith':
82
- this.getComparisonKey(ctx, entity, key, opts);
83
- ctx.append(' ILIKE ');
84
- ctx.addValue(`${val}%`);
85
- break;
86
- case '$iendsWith':
87
- this.getComparisonKey(ctx, entity, key, opts);
88
- ctx.append(' ILIKE ');
89
- ctx.addValue(`%${val}`);
90
- break;
91
- case '$iincludes':
92
- this.getComparisonKey(ctx, entity, key, opts);
93
- ctx.append(' ILIKE ');
94
- ctx.addValue(`%${val}%`);
95
- break;
96
- case '$ilike':
97
- this.getComparisonKey(ctx, entity, key, opts);
98
- ctx.append(' ILIKE ');
99
- ctx.addValue(val);
100
- break;
101
- case '$in':
102
- this.getComparisonKey(ctx, entity, key, opts);
103
- ctx.append(' = ANY(');
104
- ctx.addValue(val);
105
- ctx.append(')');
106
- break;
107
- case '$nin':
108
- this.getComparisonKey(ctx, entity, key, opts);
109
- ctx.append(' <> ALL(');
110
- ctx.addValue(val);
111
- ctx.append(')');
112
- break;
113
- case '$regex':
114
- this.getComparisonKey(ctx, entity, key, opts);
115
- ctx.append(' ~ ');
116
- ctx.addValue(val);
117
- break;
118
- default:
119
- super.compareFieldOperator(ctx, entity, key, op, val, opts);
120
- }
121
- }
122
-
123
- protected override formatPersistableValue<E>(ctx: QueryContext, field: FieldOptions, value: unknown): void {
124
- if (value instanceof QueryRaw) {
125
- super.formatPersistableValue(ctx, field, value);
126
- return;
127
- }
128
- if (field.type === 'json' || field.type === 'jsonb') {
129
- ctx.addValue(value ? JSON.stringify(value) : null);
130
- ctx.append(`::${field.type}`);
131
- return;
132
- }
133
- if (field.type === 'vector' && Array.isArray(value)) {
134
- ctx.addValue(`[${value.join(',')}]`);
135
- ctx.append('::vector');
136
- return;
137
- }
138
- super.formatPersistableValue(ctx, field, value);
139
- }
140
-
141
- override escape(value: unknown): string {
142
- return sqlstring.escape(value);
143
- }
144
- }