@storecraft/database-sql-base 1.0.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 +126 -0
- package/TODO.md +2 -0
- package/db-strategy.md +3 -0
- package/driver.js +190 -0
- package/index.js +3 -0
- package/migrate.js +66 -0
- package/migrations.mssql/00000_init_tables.js +268 -0
- package/migrations.mysql/00000_init_tables.js +372 -0
- package/migrations.mysql/00001_seed_email_templates.js +1 -0
- package/migrations.postgres/00000_init_tables.js +358 -0
- package/migrations.postgres/00001_seed_email_templates.js +1 -0
- package/migrations.shared/00001_seed_email_templates.js +260 -0
- package/migrations.sqlite/00000_init_tables.js +357 -0
- package/migrations.sqlite/00001_seed_email_templates.js +1 -0
- package/package.json +47 -0
- package/src/con.auth_users.js +159 -0
- package/src/con.collections.js +197 -0
- package/src/con.customers.js +202 -0
- package/src/con.discounts.js +225 -0
- package/src/con.discounts.utils.js +180 -0
- package/src/con.helpers.json.js +231 -0
- package/src/con.helpers.json.mssql.js +233 -0
- package/src/con.helpers.json.mysql.js +239 -0
- package/src/con.helpers.json.postgres.js +223 -0
- package/src/con.helpers.json.sqlite.js +263 -0
- package/src/con.images.js +230 -0
- package/src/con.notifications.js +149 -0
- package/src/con.orders.js +156 -0
- package/src/con.posts.js +147 -0
- package/src/con.products.js +497 -0
- package/src/con.search.js +148 -0
- package/src/con.shared.js +616 -0
- package/src/con.shipping.js +147 -0
- package/src/con.storefronts.js +301 -0
- package/src/con.tags.js +120 -0
- package/src/con.templates.js +133 -0
- package/src/kysely.sanitize.plugin.js +40 -0
- package/src/utils.funcs.js +77 -0
- package/src/utils.query.js +195 -0
- package/tests/query.cursor.test.js +389 -0
- package/tests/query.vql.test.js +71 -0
- package/tests/runner.mssql-local.test.js +118 -0
- package/tests/runner.mysql-local.test.js +101 -0
- package/tests/runner.postgres-local.test.js +99 -0
- package/tests/runner.sqlite-local.test.js +99 -0
- package/tests/sandbox.test.js +71 -0
- package/tsconfig.json +21 -0
- package/types.public.d.ts +19 -0
- package/types.sql.tables.d.ts +247 -0
@@ -0,0 +1,263 @@
|
|
1
|
+
import { SelectQueryNode, sql} from 'kysely'
|
2
|
+
import { extract_first_selection, getJsonObjectArgs } from './con.helpers.json.js';
|
3
|
+
|
4
|
+
/**
|
5
|
+
* A SQLite helper for aggregating a subquery into a JSON array.
|
6
|
+
*
|
7
|
+
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
8
|
+
* Otherwise the nested selections will be returned as JSON strings.
|
9
|
+
*
|
10
|
+
* The plugin can be installed like this:
|
11
|
+
*
|
12
|
+
* ```ts
|
13
|
+
* const db = new Kysely({
|
14
|
+
* dialect: new SqliteDialect(config),
|
15
|
+
* plugins: [new ParseJSONResultsPlugin()]
|
16
|
+
* })
|
17
|
+
* ```
|
18
|
+
*
|
19
|
+
* ### Examples
|
20
|
+
*
|
21
|
+
* ```ts
|
22
|
+
* const result = await db
|
23
|
+
* .selectFrom('person')
|
24
|
+
* .select((eb) => [
|
25
|
+
* 'id',
|
26
|
+
* jsonArrayFrom(
|
27
|
+
* eb.selectFrom('pet')
|
28
|
+
* .select(['pet.id as pet_id', 'pet.name'])
|
29
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
30
|
+
* .orderBy('pet.name')
|
31
|
+
* ).as('pets')
|
32
|
+
* ])
|
33
|
+
* .execute()
|
34
|
+
*
|
35
|
+
* result[0].id
|
36
|
+
* result[0].pets[0].pet_id
|
37
|
+
* result[0].pets[0].name
|
38
|
+
* ```
|
39
|
+
*
|
40
|
+
* The generated SQL (SQLite):
|
41
|
+
*
|
42
|
+
* ```sql
|
43
|
+
* select "id", (
|
44
|
+
* select coalesce(json_group_array(json_object(
|
45
|
+
* 'pet_id', "agg"."pet_id",
|
46
|
+
* 'name', "agg"."name"
|
47
|
+
* )), '[]') from (
|
48
|
+
* select "pet"."id" as "pet_id", "pet"."name"
|
49
|
+
* from "pet"
|
50
|
+
* where "pet"."owner_id" = "person"."id"
|
51
|
+
* order by "pet"."name"
|
52
|
+
* ) as "agg"
|
53
|
+
* ) as "pets"
|
54
|
+
* from "person"
|
55
|
+
* ```
|
56
|
+
* @template O
|
57
|
+
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
58
|
+
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O>[]>}
|
59
|
+
*/
|
60
|
+
export function sqlite_jsonArrayFrom(expr) {
|
61
|
+
|
62
|
+
return sql`(select coalesce(json_group_array(json_object(${sql.join(
|
63
|
+
getSqliteJsonObjectArgs(expr.toOperationNode(), 'agg')
|
64
|
+
)})), '[]') from ${expr} as agg)`
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
/**
|
69
|
+
* A SQLite helper for aggregating a subquery into a JSON array.
|
70
|
+
*
|
71
|
+
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
72
|
+
* Otherwise the nested selections will be returned as JSON strings.
|
73
|
+
*
|
74
|
+
* The plugin can be installed like this:
|
75
|
+
*
|
76
|
+
* ```ts
|
77
|
+
* const db = new Kysely({
|
78
|
+
* dialect: new SqliteDialect(config),
|
79
|
+
* plugins: [new ParseJSONResultsPlugin()]
|
80
|
+
* })
|
81
|
+
* ```
|
82
|
+
*
|
83
|
+
* ### Examples
|
84
|
+
*
|
85
|
+
* ```ts
|
86
|
+
* const result = await db
|
87
|
+
* .selectFrom('person')
|
88
|
+
* .select((eb) => [
|
89
|
+
* 'id',
|
90
|
+
* stringArrayFrom(
|
91
|
+
* eb.selectFrom('pet')
|
92
|
+
* .select('pet.name')
|
93
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
94
|
+
* .orderBy('pet.name')
|
95
|
+
* ).as('pets')
|
96
|
+
* ])
|
97
|
+
* .execute()
|
98
|
+
*
|
99
|
+
* result[0].pets = ['name1', 'name2', ....]
|
100
|
+
* ```
|
101
|
+
*
|
102
|
+
* The generated SQL (SQLite):
|
103
|
+
*
|
104
|
+
* ```sql
|
105
|
+
* select "id", (
|
106
|
+
* select coalesce(json_group_array("agg"."name"), '[]') from (
|
107
|
+
* select "pet"."name"
|
108
|
+
* from "pet"
|
109
|
+
* where "pet"."owner_id" = "person"."id"
|
110
|
+
* order by "pet"."name"
|
111
|
+
* ) as "agg"
|
112
|
+
* ) as "pets"
|
113
|
+
* from "person"
|
114
|
+
* ```
|
115
|
+
* @template O
|
116
|
+
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
117
|
+
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O>[]>}
|
118
|
+
*/
|
119
|
+
export function sqlite_stringArrayFrom(expr) {
|
120
|
+
const arg = extract_first_selection(expr, 'agg');
|
121
|
+
return sql`(select coalesce(json_group_array(${sql.join([arg])}), '[]') from ${expr} as agg)`
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* A SQLite helper for turning a subquery into a JSON object.
|
126
|
+
*
|
127
|
+
* The subquery must only return one row.
|
128
|
+
*
|
129
|
+
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
130
|
+
* Otherwise the nested selections will be returned as JSON strings.
|
131
|
+
*
|
132
|
+
* The plugin can be installed like this:
|
133
|
+
*
|
134
|
+
* ```ts
|
135
|
+
* const db = new Kysely({
|
136
|
+
* dialect: new SqliteDialect(config),
|
137
|
+
* plugins: [new ParseJSONResultsPlugin()]
|
138
|
+
* })
|
139
|
+
* ```
|
140
|
+
*
|
141
|
+
* ### Examples
|
142
|
+
*
|
143
|
+
* ```ts
|
144
|
+
* const result = await db
|
145
|
+
* .selectFrom('person')
|
146
|
+
* .select((eb) => [
|
147
|
+
* 'id',
|
148
|
+
* jsonObjectFrom(
|
149
|
+
* eb.selectFrom('pet')
|
150
|
+
* .select(['pet.id as pet_id', 'pet.name'])
|
151
|
+
* .whereRef('pet.owner_id', '=', 'person.id')
|
152
|
+
* .where('pet.is_favorite', '=', true)
|
153
|
+
* ).as('favorite_pet')
|
154
|
+
* ])
|
155
|
+
* .execute()
|
156
|
+
*
|
157
|
+
* result[0].id
|
158
|
+
* result[0].favorite_pet.pet_id
|
159
|
+
* result[0].favorite_pet.name
|
160
|
+
* ```
|
161
|
+
*
|
162
|
+
* The generated SQL (SQLite):
|
163
|
+
*
|
164
|
+
* ```sql
|
165
|
+
* select "id", (
|
166
|
+
* select json_object(
|
167
|
+
* 'pet_id', "obj"."pet_id",
|
168
|
+
* 'name', "obj"."name"
|
169
|
+
* ) from (
|
170
|
+
* select "pet"."id" as "pet_id", "pet"."name"
|
171
|
+
* from "pet"
|
172
|
+
* where "pet"."owner_id" = "person"."id"
|
173
|
+
* and "pet"."is_favorite" = ?
|
174
|
+
* ) as obj
|
175
|
+
* ) as "favorite_pet"
|
176
|
+
* from "person";
|
177
|
+
* ```
|
178
|
+
*
|
179
|
+
* @template O
|
180
|
+
* @param {import('./con.helpers.json.js').SelectQueryBuilderExpression<O>} expr
|
181
|
+
* @returns {import('kysely').RawBuilder<import('kysely').Simplify<O> | null>}
|
182
|
+
*/
|
183
|
+
export function sqlite_jsonObjectFrom(expr) {
|
184
|
+
return sql`(select json_object(${sql.join(
|
185
|
+
getSqliteJsonObjectArgs(expr.toOperationNode(), 'obj'),
|
186
|
+
)}) from ${expr} as obj)`
|
187
|
+
}
|
188
|
+
|
189
|
+
/**
|
190
|
+
* The SQLite `json_object` function.
|
191
|
+
*
|
192
|
+
* NOTE: This helper only works correctly if you've installed the `ParseJSONResultsPlugin`.
|
193
|
+
* Otherwise the nested selections will be returned as JSON strings.
|
194
|
+
*
|
195
|
+
* The plugin can be installed like this:
|
196
|
+
*
|
197
|
+
* ```ts
|
198
|
+
* const db = new Kysely({
|
199
|
+
* dialect: new SqliteDialect(config),
|
200
|
+
* plugins: [new ParseJSONResultsPlugin()]
|
201
|
+
* })
|
202
|
+
* ```
|
203
|
+
*
|
204
|
+
* ### Examples
|
205
|
+
*
|
206
|
+
* ```ts
|
207
|
+
* const result = await db
|
208
|
+
* .selectFrom('person')
|
209
|
+
* .select((eb) => [
|
210
|
+
* 'id',
|
211
|
+
* jsonBuildObject({
|
212
|
+
* first: eb.ref('first_name'),
|
213
|
+
* last: eb.ref('last_name'),
|
214
|
+
* full: sql<string>`first_name || ' ' || last_name`
|
215
|
+
* }).as('name')
|
216
|
+
* ])
|
217
|
+
* .execute()
|
218
|
+
*
|
219
|
+
* result[0].id
|
220
|
+
* result[0].name.first
|
221
|
+
* result[0].name.last
|
222
|
+
* result[0].name.full
|
223
|
+
* ```
|
224
|
+
*
|
225
|
+
* The generated SQL (SQLite):
|
226
|
+
*
|
227
|
+
* ```sql
|
228
|
+
* select "id", json_object(
|
229
|
+
* 'first', first_name,
|
230
|
+
* 'last', last_name,
|
231
|
+
* 'full', "first_name" || ' ' || "last_name"
|
232
|
+
* ) as "name"
|
233
|
+
* from "person"
|
234
|
+
* ```
|
235
|
+
*/
|
236
|
+
// export function jsonBuildObject<O extends Record<string, Expression<unknown>>>(
|
237
|
+
// obj: O,
|
238
|
+
// ): RawBuilder<
|
239
|
+
// Simplify<{
|
240
|
+
// [K in keyof O]: O[K] extends Expression<infer V> ? V : never
|
241
|
+
// }>
|
242
|
+
// > {
|
243
|
+
// return sql`json_object(${sql.join(
|
244
|
+
// Object.keys(obj).flatMap((k) => [sql.lit(k), obj[k]]),
|
245
|
+
// )})`
|
246
|
+
// }
|
247
|
+
|
248
|
+
|
249
|
+
/**
|
250
|
+
*
|
251
|
+
* @param {SelectQueryNode} node
|
252
|
+
* @param {string} table
|
253
|
+
* @returns {import('kysely').Expression<unknown>[]}
|
254
|
+
*/
|
255
|
+
function getSqliteJsonObjectArgs(node, table) {
|
256
|
+
try {
|
257
|
+
return getJsonObjectArgs(node, table)
|
258
|
+
} catch {
|
259
|
+
throw new Error(
|
260
|
+
'SQLite jsonArrayFrom and jsonObjectFrom functions can only handle explicit selections due to limitations of the json_object function. selectAll() is not allowed in the subquery.',
|
261
|
+
)
|
262
|
+
}
|
263
|
+
}
|
@@ -0,0 +1,230 @@
|
|
1
|
+
import { func } from '@storecraft/core/v-api'
|
2
|
+
import { SQL } from '../driver.js'
|
3
|
+
import { count_regular, delete_me, delete_search_of,
|
4
|
+
insert_search_of, regular_upsert_me, where_id_or_handle_table
|
5
|
+
} from './con.shared.js'
|
6
|
+
import { sanitize_array } from './utils.funcs.js'
|
7
|
+
import { query_to_eb, query_to_sort } from './utils.query.js'
|
8
|
+
import { Transaction } from 'kysely'
|
9
|
+
import { ID } from '@storecraft/core/v-api/utils.func.js'
|
10
|
+
import {
|
11
|
+
image_url_to_handle, image_url_to_name
|
12
|
+
} from '@storecraft/core/v-api/con.images.logic.js'
|
13
|
+
|
14
|
+
/**
|
15
|
+
* @typedef {import('@storecraft/core/v-database').db_images} db_col
|
16
|
+
*/
|
17
|
+
export const table_name = 'images'
|
18
|
+
|
19
|
+
/**
|
20
|
+
* @param {SQL} driver
|
21
|
+
* @returns {db_col["upsert"]}
|
22
|
+
*/
|
23
|
+
const upsert = (driver) => {
|
24
|
+
return async (item, search_terms) => {
|
25
|
+
const c = driver.client;
|
26
|
+
try {
|
27
|
+
const t = await c.transaction().execute(
|
28
|
+
async (trx) => {
|
29
|
+
await insert_search_of(
|
30
|
+
trx, search_terms, item.id, item.handle, table_name
|
31
|
+
);
|
32
|
+
await regular_upsert_me(trx, table_name, {
|
33
|
+
created_at: item.created_at,
|
34
|
+
updated_at: item.updated_at,
|
35
|
+
id: item.id,
|
36
|
+
handle: item.handle,
|
37
|
+
name: item.name,
|
38
|
+
url: item.url,
|
39
|
+
});
|
40
|
+
}
|
41
|
+
);
|
42
|
+
} catch(e) {
|
43
|
+
console.log(e);
|
44
|
+
return false;
|
45
|
+
}
|
46
|
+
return true;
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
/**
|
52
|
+
* @param {SQL} driver
|
53
|
+
* @returns {db_col["get"]}
|
54
|
+
*/
|
55
|
+
const get = (driver) => {
|
56
|
+
return (id_or_handle, options) => {
|
57
|
+
return driver.client
|
58
|
+
.selectFrom(table_name)
|
59
|
+
.selectAll()
|
60
|
+
.where(where_id_or_handle_table(id_or_handle))
|
61
|
+
.executeTakeFirst();
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
/**
|
67
|
+
* @param {SQL} driver
|
68
|
+
* @returns {db_col["remove"]}
|
69
|
+
*/
|
70
|
+
const remove = (driver) => {
|
71
|
+
return async (id_or_handle) => {
|
72
|
+
const img = await driver.client
|
73
|
+
.selectFrom(table_name)
|
74
|
+
.selectAll()
|
75
|
+
.where(where_id_or_handle_table(id_or_handle))
|
76
|
+
.executeTakeFirst();
|
77
|
+
|
78
|
+
try {
|
79
|
+
await driver.client.transaction().execute(
|
80
|
+
async (trx) => {
|
81
|
+
// remove images -> media
|
82
|
+
await trx
|
83
|
+
.deleteFrom('entity_to_media')
|
84
|
+
.where('value', '=', img.url)
|
85
|
+
.execute();
|
86
|
+
// entities
|
87
|
+
await delete_search_of(trx, id_or_handle);
|
88
|
+
// delete me
|
89
|
+
await delete_me(trx, table_name, id_or_handle);
|
90
|
+
}
|
91
|
+
);
|
92
|
+
|
93
|
+
} catch(e) {
|
94
|
+
console.log(e);
|
95
|
+
return false;
|
96
|
+
}
|
97
|
+
return true;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
/**
|
102
|
+
* report media usages
|
103
|
+
* @param {SQL} driver
|
104
|
+
* @returns {db_col["report_document_media"]}
|
105
|
+
*/
|
106
|
+
export const report_document_media = (driver) => {
|
107
|
+
/**
|
108
|
+
* @param {Transaction<import('../index.js').Database>} [transaction]
|
109
|
+
*/
|
110
|
+
return async (item, transaction) => {
|
111
|
+
if(!(item?.media?.length))
|
112
|
+
return;
|
113
|
+
|
114
|
+
/**
|
115
|
+
*
|
116
|
+
* @param {Transaction<import('../index.js').Database>} trx
|
117
|
+
*/
|
118
|
+
const doit = async (trx) => {
|
119
|
+
const dates = func.apply_dates({});
|
120
|
+
|
121
|
+
const ms = item.media.map(
|
122
|
+
m => (
|
123
|
+
{
|
124
|
+
handle: image_url_to_handle(m),
|
125
|
+
url: m,
|
126
|
+
name: image_url_to_name(m),
|
127
|
+
id: ID('img'),
|
128
|
+
created_at: dates.created_at,
|
129
|
+
updated_at: dates.updated_at,
|
130
|
+
}
|
131
|
+
)
|
132
|
+
);
|
133
|
+
const handles = ms.map(m => m.handle);
|
134
|
+
|
135
|
+
await trx.deleteFrom(table_name).where(
|
136
|
+
'handle', 'in', handles
|
137
|
+
).execute();
|
138
|
+
await trx.insertInto(table_name).values(
|
139
|
+
ms
|
140
|
+
).execute();
|
141
|
+
// search stuff
|
142
|
+
// remove by reporter
|
143
|
+
await trx.deleteFrom('entity_to_search_terms').where(
|
144
|
+
eb => eb.and([
|
145
|
+
eb('reporter', '=', item.id),
|
146
|
+
eb('context', '=', table_name),
|
147
|
+
]
|
148
|
+
)
|
149
|
+
).execute();
|
150
|
+
const search = func.union(
|
151
|
+
item['title'], func.to_tokens(item['title'])
|
152
|
+
);
|
153
|
+
if(search.length) {
|
154
|
+
const A = ms.map(m => ({
|
155
|
+
entity_id: m.id,
|
156
|
+
entity_handle: m.handle,
|
157
|
+
context: table_name,
|
158
|
+
reporter: item.id
|
159
|
+
})
|
160
|
+
);
|
161
|
+
|
162
|
+
const B = search.reduce(
|
163
|
+
(p, c) => {
|
164
|
+
p.push(...A.map(a => ({...a, value: c})));
|
165
|
+
return p;
|
166
|
+
}, []
|
167
|
+
);
|
168
|
+
|
169
|
+
await trx.insertInto('entity_to_search_terms').values(
|
170
|
+
B
|
171
|
+
).execute();
|
172
|
+
}
|
173
|
+
|
174
|
+
}
|
175
|
+
|
176
|
+
if(transaction) {
|
177
|
+
await doit(transaction);
|
178
|
+
} else {
|
179
|
+
try {
|
180
|
+
const t = await driver.client
|
181
|
+
.transaction()
|
182
|
+
.execute(doit);
|
183
|
+
} catch(e) {
|
184
|
+
console.log(e);
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
/**
|
191
|
+
* @param {SQL} driver
|
192
|
+
* @returns {db_col["list"]}
|
193
|
+
*/
|
194
|
+
const list = (driver) => {
|
195
|
+
return async (query) => {
|
196
|
+
|
197
|
+
const items = await driver.client
|
198
|
+
.selectFrom(table_name)
|
199
|
+
.selectAll()
|
200
|
+
.where(
|
201
|
+
(eb) => {
|
202
|
+
return query_to_eb(eb, query, table_name);
|
203
|
+
}
|
204
|
+
)
|
205
|
+
.orderBy(query_to_sort(query))
|
206
|
+
.limit(query.limitToLast ?? query.limit ?? 10)
|
207
|
+
.execute();
|
208
|
+
|
209
|
+
if(query.limitToLast) items.reverse();
|
210
|
+
|
211
|
+
return sanitize_array(items);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
|
216
|
+
/**
|
217
|
+
* @param {SQL} driver
|
218
|
+
* @return {db_col}}
|
219
|
+
* */
|
220
|
+
export const impl = (driver) => {
|
221
|
+
|
222
|
+
return {
|
223
|
+
get: get(driver),
|
224
|
+
upsert: upsert(driver),
|
225
|
+
remove: remove(driver),
|
226
|
+
list: list(driver),
|
227
|
+
report_document_media: report_document_media(driver),
|
228
|
+
count: count_regular(driver, table_name),
|
229
|
+
}
|
230
|
+
}
|
@@ -0,0 +1,149 @@
|
|
1
|
+
import { SQL } from '../driver.js'
|
2
|
+
import { count_regular, delete_me, delete_search_of,
|
3
|
+
insert_search_of, regular_upsert_me, where_id_or_handle_table,
|
4
|
+
with_search } from './con.shared.js'
|
5
|
+
import { sanitize_array } from './utils.funcs.js'
|
6
|
+
import { query_to_eb, query_to_sort } from './utils.query.js'
|
7
|
+
|
8
|
+
/**
|
9
|
+
* @typedef {import('@storecraft/core/v-database').db_notifications} db_col
|
10
|
+
*/
|
11
|
+
export const table_name = 'notifications'
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @param {SQL} driver
|
15
|
+
* @returns {db_col["upsert"]}
|
16
|
+
*/
|
17
|
+
const upsert = (driver) => {
|
18
|
+
return async (item, search_terms=[]) => {
|
19
|
+
const c = driver.client;
|
20
|
+
try {
|
21
|
+
const t = await c.transaction().execute(
|
22
|
+
async (trx) => {
|
23
|
+
await insert_search_of(
|
24
|
+
trx, [...item.search, ...search_terms],
|
25
|
+
item.id, item.id, table_name
|
26
|
+
);
|
27
|
+
await regular_upsert_me(trx, table_name, {
|
28
|
+
created_at: item.created_at,
|
29
|
+
updated_at: item.updated_at,
|
30
|
+
message: item.message,
|
31
|
+
author: item.author,
|
32
|
+
id: item.id,
|
33
|
+
actions: JSON.stringify(item.actions)
|
34
|
+
});
|
35
|
+
}
|
36
|
+
);
|
37
|
+
} catch(e) {
|
38
|
+
console.log(e);
|
39
|
+
return false;
|
40
|
+
}
|
41
|
+
return true;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* @param {SQL} driver
|
47
|
+
* @returns {db_col["upsertBulk"]}
|
48
|
+
*/
|
49
|
+
const upsertBulk = (driver) => {
|
50
|
+
return async (items, search_terms) => {
|
51
|
+
const results = [];
|
52
|
+
// for (const it of items)
|
53
|
+
for(let ix = 0; ix < items.length; ix++)
|
54
|
+
results.push(await upsert(driver)(
|
55
|
+
items[ix], search_terms?.[ix])
|
56
|
+
);
|
57
|
+
|
58
|
+
return results.every(b => b);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* @param {SQL} driver
|
64
|
+
* @returns {db_col["get"]}
|
65
|
+
*/
|
66
|
+
const get = (driver) => {
|
67
|
+
return (id_or_handle, options) => {
|
68
|
+
return driver.client
|
69
|
+
.selectFrom(table_name)
|
70
|
+
.selectAll()
|
71
|
+
.select(eb => [
|
72
|
+
with_search(eb, eb.ref('notifications.id'), driver.dialectType),
|
73
|
+
]
|
74
|
+
.filter(Boolean))
|
75
|
+
.where(where_id_or_handle_table(id_or_handle))
|
76
|
+
.executeTakeFirst();
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
/**
|
82
|
+
* @param {SQL} driver
|
83
|
+
* @returns {db_col["remove"]}
|
84
|
+
*/
|
85
|
+
const remove = (driver) => {
|
86
|
+
return async (id_or_handle) => {
|
87
|
+
try {
|
88
|
+
await driver.client.transaction().execute(
|
89
|
+
async (trx) => {
|
90
|
+
// entities
|
91
|
+
await delete_search_of(trx, id_or_handle);
|
92
|
+
// delete me
|
93
|
+
await delete_me(trx, table_name, id_or_handle);
|
94
|
+
}
|
95
|
+
);
|
96
|
+
|
97
|
+
} catch(e) {
|
98
|
+
console.log(e);
|
99
|
+
return false;
|
100
|
+
}
|
101
|
+
return true;
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
/**
|
107
|
+
* @param {SQL} driver
|
108
|
+
* @returns {db_col["list"]}
|
109
|
+
*/
|
110
|
+
const list = (driver) => {
|
111
|
+
return async (query) => {
|
112
|
+
|
113
|
+
const items = await driver.client
|
114
|
+
.selectFrom(table_name)
|
115
|
+
.selectAll()
|
116
|
+
.select(eb => [
|
117
|
+
with_search(eb, eb.ref('notifications.id'), driver.dialectType),
|
118
|
+
].filter(Boolean))
|
119
|
+
.where(
|
120
|
+
(eb) => {
|
121
|
+
return query_to_eb(eb, query, table_name);
|
122
|
+
}
|
123
|
+
)
|
124
|
+
.orderBy(query_to_sort(query))
|
125
|
+
.limit(query.limitToLast ?? query.limit ?? 10)
|
126
|
+
.execute();
|
127
|
+
|
128
|
+
if(query.limitToLast) items.reverse();
|
129
|
+
|
130
|
+
return sanitize_array(items);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
|
135
|
+
/**
|
136
|
+
* @param {SQL} driver
|
137
|
+
* @return {db_col}}
|
138
|
+
* */
|
139
|
+
export const impl = (driver) => {
|
140
|
+
|
141
|
+
return {
|
142
|
+
get: get(driver),
|
143
|
+
upsert: upsert(driver),
|
144
|
+
upsertBulk: upsertBulk(driver),
|
145
|
+
remove: remove(driver),
|
146
|
+
list: list(driver),
|
147
|
+
count: count_regular(driver, table_name),
|
148
|
+
}
|
149
|
+
}
|