@platformatic/sql-mapper 0.45.1 → 0.46.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.
@@ -1,132 +0,0 @@
1
- 'use strict'
2
-
3
- const { test } = require('tap')
4
- const { clear, connInfo, isSQLite } = require('./helper')
5
- const { connect } = require('..')
6
-
7
- const fakeLogger = {
8
- trace: () => {},
9
- error: () => {}
10
- }
11
-
12
- test('entity transactions', async ({ equal, same, teardown, rejects }) => {
13
- async function onDatabaseLoad (db, sql) {
14
- await clear(db, sql)
15
- teardown(() => db.dispose())
16
- if (isSQLite) {
17
- await db.query(sql`CREATE TABLE pages (
18
- id INTEGER PRIMARY KEY,
19
- title VARCHAR(42)
20
- );`)
21
- } else {
22
- await db.query(sql`CREATE TABLE pages (
23
- id SERIAL PRIMARY KEY,
24
- title VARCHAR(255) NOT NULL
25
- );`)
26
- }
27
- await db.query(sql`INSERT INTO pages (title) VALUES ('foo')`)
28
- await db.query(sql`INSERT INTO pages (title) VALUES ('bar')`)
29
- }
30
- const mapper = await connect({
31
- connectionString: connInfo.connectionString,
32
- log: fakeLogger,
33
- onDatabaseLoad,
34
- ignore: {},
35
- hooks: {}
36
- })
37
- const pageEntity = mapper.entities.page
38
-
39
- // insert + rollback
40
- {
41
- const findResult = await pageEntity.find({ fields: ['title'] })
42
- same(findResult, [{ title: 'foo' }, { title: 'bar' }])
43
-
44
- try {
45
- await mapper.db.tx(async tx => {
46
- same(await pageEntity.save({
47
- input: { title: 'new page' },
48
- fields: ['title'],
49
- tx
50
- }), { title: 'new page' })
51
- const findResult = await pageEntity.find({ fields: ['title'], tx })
52
- same(findResult, [{ title: 'foo' }, { title: 'bar' }, { title: 'new page' }])
53
- throw new Error('rollback')
54
- })
55
- } catch (e) {
56
- // rollback
57
- }
58
-
59
- const afterRollback = await pageEntity.find({ fields: ['title'] })
60
- same(afterRollback, [{ title: 'foo' }, { title: 'bar' }])
61
- }
62
-
63
- // update + rollback
64
- {
65
- const findResult = await pageEntity.find({ fields: ['id', 'title'], where: { id: { eq: 1 } } })
66
- same(findResult, [{ id: 1, title: 'foo' }])
67
-
68
- try {
69
- await mapper.db.tx(async tx => {
70
- same(await pageEntity.save({
71
- input: { id: 1, title: 'changed' },
72
- fields: ['id', 'title'],
73
- tx
74
- }), { id: 1, title: 'changed' })
75
- const findResult = await pageEntity.find({ fields: ['id', 'title'], where: { id: { eq: 1 } }, tx })
76
- same(findResult, [{ id: 1, title: 'changed' }])
77
- throw new Error('rollback')
78
- })
79
- } catch (e) {
80
- // rollback
81
- }
82
- const afterRollback = await pageEntity.find({ fields: ['id', 'title'], where: { id: { eq: 1 } } })
83
- same(afterRollback, [{ id: 1, title: 'foo' }])
84
- }
85
-
86
- // delete
87
- {
88
- const findResult = await pageEntity.find({ fields: ['title'] })
89
- same(findResult, [{ title: 'foo' }, { title: 'bar' }])
90
-
91
- try {
92
- await mapper.db.tx(async tx => {
93
- same(await pageEntity.delete({
94
- where: {
95
- id: { eq: 1 }
96
- },
97
- tx
98
- }), [{ id: 1, title: 'foo' }])
99
- const findResult = await pageEntity.find({ fields: ['id', 'title'], where: { id: { eq: 1 } }, tx })
100
- same(findResult, [])
101
- throw new Error('rollback')
102
- })
103
- } catch (e) {
104
- // rollback
105
- }
106
- const afterRollback = await pageEntity.find({ fields: ['title'] })
107
- same(afterRollback, [{ title: 'foo' }, { title: 'bar' }])
108
- }
109
-
110
- // count
111
- {
112
- const countResult = await pageEntity.count()
113
- same(countResult, 2)
114
- try {
115
- await mapper.db.tx(async tx => {
116
- same(await pageEntity.save({
117
- input: { title: 'new page' },
118
- fields: ['title'],
119
- tx
120
- }), { title: 'new page' })
121
- const countResult = await pageEntity.count({ tx })
122
- same(countResult, 3)
123
- throw new Error('rollback')
124
- })
125
- } catch (e) {
126
- // rollback
127
- }
128
-
129
- const afterRollback = await pageEntity.count()
130
- same(afterRollback, 2)
131
- }
132
- })
package/test/helper.js DELETED
@@ -1,112 +0,0 @@
1
- 'use strict'
2
-
3
- // Needed to work with dates & postgresql
4
- // See https://node-postgres.com/features/types/
5
- process.env.TZ = 'UTC'
6
-
7
- const connInfo = {
8
- autoTimestamp: {
9
- createdAt: 'inserted_at',
10
- updatedAt: 'updated_at'
11
- }
12
- }
13
-
14
- if (!process.env.DB || process.env.DB === 'postgresql') {
15
- connInfo.connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'
16
- module.exports.isPg = true
17
- } else if (process.env.DB === 'mariadb') {
18
- connInfo.connectionString = 'mysql://root@127.0.0.1:3307/graph'
19
- connInfo.poolSize = 10
20
- module.exports.isMysql = true
21
- } else if (process.env.DB === 'mysql') {
22
- connInfo.connectionString = 'mysql://root@127.0.0.1/graph'
23
- connInfo.poolSize = 10
24
- module.exports.isMysql = true
25
- } else if (process.env.DB === 'mysql8') {
26
- connInfo.connectionString = 'mysql://root@127.0.0.1:3308/graph'
27
- connInfo.poolSize = 10
28
- module.exports.isMysql = true
29
- module.exports.isMysql8 = true
30
- } else if (process.env.DB === 'sqlite') {
31
- connInfo.connectionString = 'sqlite://:memory:'
32
- module.exports.isSQLite = true
33
- }
34
-
35
- module.exports.connInfo = connInfo
36
-
37
- module.exports.clear = async function (db, sql) {
38
- try {
39
- await db.query(sql`DROP TABLE graphs`)
40
- } catch {
41
- }
42
-
43
- try {
44
- await db.query(sql`DROP TABLE editors`)
45
- } catch {
46
- }
47
-
48
- try {
49
- await db.query(sql`DROP TABLE pages`)
50
- } catch (err) {
51
- }
52
-
53
- try {
54
- await db.query(sql`DROP TABLE comments`)
55
- } catch (err) {
56
- }
57
-
58
- try {
59
- await db.query(sql`DROP TABLE categories`)
60
- } catch {
61
- }
62
-
63
- try {
64
- await db.query(sql`DROP TABLE posts`)
65
- } catch {
66
- }
67
-
68
- try {
69
- await db.query(sql`DROP TABLE simple_types`)
70
- } catch {
71
- }
72
-
73
- try {
74
- await db.query(sql`DROP TABLE owners`)
75
- } catch {
76
- }
77
-
78
- try {
79
- await db.query(sql`DROP TABLE users`)
80
- } catch {
81
- }
82
-
83
- try {
84
- await db.query(sql`DROP TABLE versions`)
85
- } catch {
86
- }
87
-
88
- try {
89
- await db.query(sql`DROP TYPE pagetype`)
90
- } catch {
91
- }
92
-
93
- try {
94
- await db.query(sql`DROP TABLE test1.pages`)
95
- } catch (err) {
96
- }
97
-
98
- try {
99
- await db.query(sql`DROP TABLE test2.users`)
100
- } catch (err) {
101
- }
102
-
103
- try {
104
- await db.query(sql`DROP TABLE test2.pages`)
105
- } catch (err) {
106
- }
107
-
108
- try {
109
- await db.query(sql`DROP TABLE generated_test`)
110
- } catch (err) {
111
- }
112
- }
@@ -1,325 +0,0 @@
1
- 'use strict'
2
-
3
- const { test } = require('tap')
4
- const { connect } = require('..')
5
- const { clear, connInfo, isSQLite } = require('./helper')
6
- const fakeLogger = {
7
- trace: () => {},
8
- error: () => {}
9
- }
10
-
11
- test('basic hooks', async ({ pass, teardown, same, equal, plan, fail }) => {
12
- plan(14)
13
- const mapper = await connect({
14
- ...connInfo,
15
- log: fakeLogger,
16
- async onDatabaseLoad (db, sql) {
17
- teardown(() => db.dispose())
18
- pass('onDatabaseLoad called')
19
-
20
- await clear(db, sql)
21
-
22
- if (isSQLite) {
23
- await db.query(sql`CREATE TABLE pages (
24
- id INTEGER PRIMARY KEY,
25
- title VARCHAR(42)
26
- );`)
27
- } else {
28
- await db.query(sql`CREATE TABLE pages (
29
- id SERIAL PRIMARY KEY,
30
- title VARCHAR(42)
31
- );`)
32
- }
33
- },
34
- hooks: {
35
- Page: {
36
- noKey () {
37
- fail('noKey should never be called')
38
- },
39
- async save (original, { input, ctx, fields }) {
40
- pass('save called')
41
-
42
- if (!input.id) {
43
- same(input, {
44
- title: 'Hello'
45
- })
46
-
47
- return original({
48
- input: {
49
- title: 'Hello from hook'
50
- },
51
- fields
52
- })
53
- } else {
54
- same(input, {
55
- id: 1,
56
- title: 'Hello World'
57
- })
58
-
59
- return original({
60
- input: {
61
- id: 1,
62
- title: 'Hello from hook 2'
63
- },
64
- fields
65
- })
66
- }
67
- },
68
- async find (original, args) {
69
- pass('find called')
70
-
71
- same(args.where, {
72
- id: {
73
- eq: '1'
74
- }
75
- })
76
- args.where = {
77
- id: {
78
- eq: '2'
79
- }
80
- }
81
- same(args.fields, ['id', 'title'])
82
- return original(args)
83
- },
84
- async insert (original, args) {
85
- pass('insert called')
86
-
87
- same(args.inputs, [{
88
- title: 'hello'
89
- }, {
90
- title: 'world'
91
- }])
92
- same(args.fields, ['id', 'title'])
93
- return original(args)
94
- }
95
- }
96
- }
97
- })
98
-
99
- const entity = mapper.entities.page
100
-
101
- same(await entity.save({ input: { title: 'Hello' } }), {
102
- id: 1,
103
- title: 'Hello from hook'
104
- })
105
-
106
- same(await entity.find({ where: { id: { eq: 1 } }, fields: ['id', 'title'] }), [])
107
-
108
- same(await entity.save({ input: { id: 1, title: 'Hello World' } }), {
109
- id: 1,
110
- title: 'Hello from hook 2'
111
- })
112
-
113
- await entity.insert({ inputs: [{ title: 'hello' }, { title: 'world' }], fields: ['id', 'title'] })
114
- })
115
-
116
- test('addEntityHooks', async ({ pass, teardown, same, equal, plan, fail, throws }) => {
117
- plan(15)
118
- const mapper = await connect({
119
- ...connInfo,
120
- log: fakeLogger,
121
- async onDatabaseLoad (db, sql) {
122
- teardown(() => db.dispose())
123
- pass('onDatabaseLoad called')
124
-
125
- await clear(db, sql)
126
-
127
- if (isSQLite) {
128
- await db.query(sql`CREATE TABLE pages (
129
- id INTEGER PRIMARY KEY,
130
- title VARCHAR(42)
131
- );`)
132
- } else {
133
- await db.query(sql`CREATE TABLE pages (
134
- id SERIAL PRIMARY KEY,
135
- title VARCHAR(42)
136
- );`)
137
- }
138
- }
139
- })
140
-
141
- throws(() => mapper.addEntityHooks('user', {}), 'Cannot find entity user')
142
-
143
- mapper.addEntityHooks('page', {
144
- noKey () {
145
- fail('noKey should never be called')
146
- },
147
- async save (original, { input, ctx, fields }) {
148
- pass('save called')
149
-
150
- if (!input.id) {
151
- same(input, {
152
- title: 'Hello'
153
- })
154
-
155
- return original({
156
- input: {
157
- title: 'Hello from hook'
158
- },
159
- fields
160
- })
161
- } else {
162
- same(input, {
163
- id: 1,
164
- title: 'Hello World'
165
- })
166
-
167
- return original({
168
- input: {
169
- id: 1,
170
- title: 'Hello from hook 2'
171
- },
172
- fields
173
- })
174
- }
175
- },
176
- async find (original, args) {
177
- pass('find called')
178
-
179
- same(args.where, {
180
- id: {
181
- eq: '1'
182
- }
183
- })
184
- args.where = {
185
- id: {
186
- eq: '2'
187
- }
188
- }
189
- same(args.fields, ['id', 'title'])
190
- return original(args)
191
- },
192
- async insert (original, args) {
193
- pass('insert called')
194
-
195
- same(args.inputs, [{
196
- title: 'hello'
197
- }, {
198
- title: 'world'
199
- }])
200
- same(args.fields, ['id', 'title'])
201
- return original(args)
202
- }
203
- })
204
-
205
- const entity = mapper.entities.page
206
-
207
- same(await entity.save({ input: { title: 'Hello' } }), {
208
- id: 1,
209
- title: 'Hello from hook'
210
- })
211
-
212
- same(await entity.find({ where: { id: { eq: 1 } }, fields: ['id', 'title'] }), [])
213
-
214
- same(await entity.save({ input: { id: 1, title: 'Hello World' } }), {
215
- id: 1,
216
- title: 'Hello from hook 2'
217
- })
218
-
219
- await entity.insert({ inputs: [{ title: 'hello' }, { title: 'world' }], fields: ['id', 'title'] })
220
- })
221
-
222
- test('basic hooks with smaller cap name', async ({ pass, teardown, same, equal, plan, fail }) => {
223
- plan(14)
224
- const mapper = await connect({
225
- ...connInfo,
226
- log: fakeLogger,
227
- async onDatabaseLoad (db, sql) {
228
- teardown(() => db.dispose())
229
- pass('onDatabaseLoad called')
230
-
231
- await clear(db, sql)
232
-
233
- if (isSQLite) {
234
- await db.query(sql`CREATE TABLE pages (
235
- id INTEGER PRIMARY KEY,
236
- title VARCHAR(42)
237
- );`)
238
- } else {
239
- await db.query(sql`CREATE TABLE pages (
240
- id SERIAL PRIMARY KEY,
241
- title VARCHAR(42)
242
- );`)
243
- }
244
- },
245
- hooks: {
246
- page: {
247
- noKey () {
248
- fail('noKey should never be called')
249
- },
250
- async save (original, { input, ctx, fields }) {
251
- pass('save called')
252
-
253
- if (!input.id) {
254
- same(input, {
255
- title: 'Hello'
256
- })
257
-
258
- return original({
259
- input: {
260
- title: 'Hello from hook'
261
- },
262
- fields
263
- })
264
- } else {
265
- same(input, {
266
- id: 1,
267
- title: 'Hello World'
268
- })
269
-
270
- return original({
271
- input: {
272
- id: 1,
273
- title: 'Hello from hook 2'
274
- },
275
- fields
276
- })
277
- }
278
- },
279
- async find (original, args) {
280
- pass('find called')
281
-
282
- same(args.where, {
283
- id: {
284
- eq: '1'
285
- }
286
- })
287
- args.where = {
288
- id: {
289
- eq: '2'
290
- }
291
- }
292
- same(args.fields, ['id', 'title'])
293
- return original(args)
294
- },
295
- async insert (original, args) {
296
- pass('insert called')
297
-
298
- same(args.inputs, [{
299
- title: 'hello'
300
- }, {
301
- title: 'world'
302
- }])
303
- same(args.fields, ['id', 'title'])
304
- return original(args)
305
- }
306
- }
307
- }
308
- })
309
-
310
- const entity = mapper.entities.page
311
-
312
- same(await entity.save({ input: { title: 'Hello' } }), {
313
- id: 1,
314
- title: 'Hello from hook'
315
- })
316
-
317
- same(await entity.find({ where: { id: { eq: 1 } }, fields: ['id', 'title'] }), [])
318
-
319
- same(await entity.save({ input: { id: 1, title: 'Hello World' } }), {
320
- id: 1,
321
- title: 'Hello from hook 2'
322
- })
323
-
324
- await entity.insert({ inputs: [{ title: 'hello' }, { title: 'world' }], fields: ['id', 'title'] })
325
- })
@@ -1,132 +0,0 @@
1
- 'use strict'
2
-
3
- const { test } = require('tap')
4
- const { clear, connInfo, isSQLite, isMysql } = require('./helper')
5
- const { setTimeout } = require('timers/promises')
6
- const { connect } = require('..')
7
- const fakeLogger = {
8
- trace: () => {},
9
- error: () => {}
10
- }
11
-
12
- async function createBasicPages (db, sql) {
13
- if (isSQLite) {
14
- await db.query(sql`CREATE TABLE pages (
15
- id INTEGER PRIMARY KEY,
16
- title VARCHAR(42),
17
- inserted_at TIMESTAMP,
18
- updated_at TIMESTAMP
19
- );`)
20
- } else if (isMysql) {
21
- await db.query(sql`CREATE TABLE pages (
22
- id SERIAL PRIMARY KEY,
23
- title VARCHAR(42),
24
- inserted_at TIMESTAMP NULL DEFAULT NULL,
25
- updated_at TIMESTAMP NULL DEFAULT NULL
26
- );`)
27
- } else {
28
- await db.query(sql`CREATE TABLE pages (
29
- id SERIAL PRIMARY KEY,
30
- title VARCHAR(42),
31
- inserted_at TIMESTAMP,
32
- updated_at TIMESTAMP
33
- );`)
34
- }
35
- }
36
-
37
- test('inserted_at updated_at happy path', async ({ pass, teardown, same, equal, not, comment, notSame }) => {
38
- const mapper = await connect({
39
- ...connInfo,
40
- log: fakeLogger,
41
- async onDatabaseLoad (db, sql) {
42
- teardown(() => db.dispose())
43
- pass('onDatabaseLoad called')
44
-
45
- await clear(db, sql)
46
- await createBasicPages(db, sql)
47
- }
48
- })
49
-
50
- const entity = mapper.entities.page
51
-
52
- equal(entity.fields.inserted_at.autoTimestamp, true)
53
- equal(entity.fields.updated_at.autoTimestamp, true)
54
-
55
- const original = await entity.save({
56
- input: { title: 'Hello' }
57
- })
58
- not(original.insertedAt, null, 'insertedAt')
59
- not(original.updatedAt, null, 'updatedAt')
60
- comment(`insertedAt: ${original.insertedAt}`)
61
- comment(`updatedAt: ${original.updatedAt}`)
62
-
63
- {
64
- const [data] = await entity.find({ where: { id: { eq: original.id } } })
65
- same(data.insertedAt, original.insertedAt, 'insertedAt')
66
- same(data.updatedAt, original.updatedAt, 'updatedAt')
67
- comment(`insertedAt: ${data.insertedAt}`)
68
- comment(`updatedAt: ${data.updatedAt}`)
69
- }
70
-
71
- await setTimeout(1000) // await 1s
72
-
73
- let updated
74
- {
75
- const data = await entity.save({
76
- input: { id: original.id, title: 'Hello World' }
77
- })
78
- same(data.insertedAt, original.insertedAt, 'insertedAt')
79
- notSame(data.updatedAt, original.updatedAt, 'updatedAt')
80
- updated = data
81
- comment(`insertedAt: ${data.insertedAt}`)
82
- comment(`updatedAt: ${data.updatedAt}`)
83
- }
84
-
85
- {
86
- const [data] = await entity.find({ where: { id: { eq: original.id } } })
87
- same(data.insertedAt, updated.insertedAt, 'insertedAt')
88
- same(data.updatedAt, updated.updatedAt, 'updatedAt')
89
- comment(`insertedAt: ${data.insertedAt}`)
90
- comment(`updatedAt: ${data.updatedAt}`)
91
- }
92
- })
93
-
94
- test('bulk insert adds inserted_at updated_at', async ({ pass, teardown, same, equal, not, comment }) => {
95
- const mapper = await connect({
96
- ...connInfo,
97
- log: fakeLogger,
98
- async onDatabaseLoad (db, sql) {
99
- teardown(() => db.dispose())
100
- pass('onDatabaseLoad called')
101
-
102
- await clear(db, sql)
103
- await createBasicPages(db, sql)
104
- }
105
- })
106
-
107
- const entity = mapper.entities.page
108
-
109
- {
110
- const pages = await entity.insert({
111
- inputs: [
112
- { title: 'Page 1' },
113
- { title: 'Page 2' },
114
- { title: 'Page 3' }
115
- ]
116
- })
117
- for (const page of pages) {
118
- not(page.insertedAt, null, 'insertedAt')
119
- not(page.updatedAt, null, 'updatedAt')
120
- same(page.insertedAt, page.updatedAt, 'insertedAt === updatedAt')
121
- }
122
- }
123
-
124
- {
125
- const pages = await entity.find()
126
- for (const page of pages) {
127
- not(page.insertedAt, null, 'insertedAt')
128
- not(page.updatedAt, null, 'updatedAt')
129
- same(page.insertedAt, page.updatedAt, 'insertedAt === updatedAt')
130
- }
131
- }
132
- })