@platformatic/sql-mapper 0.0.23

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 (36) hide show
  1. package/.nyc_output/0208d41a-48bc-4675-a861-0475eb461a17.json +1 -0
  2. package/.nyc_output/588169a6-88e9-4949-af5a-631822d7dc42.json +1 -0
  3. package/.nyc_output/5bbdf331-cd01-4869-9d54-3d708610224a.json +1 -0
  4. package/.nyc_output/6d7c60ad-a404-4a1d-af86-8a334cff5f02.json +1 -0
  5. package/.nyc_output/8dae7e8c-5022-4a0c-a5b3-bf547f97961b.json +1 -0
  6. package/.nyc_output/f63bf7c5-4f58-4b46-a822-6f5ccf5a54a8.json +1 -0
  7. package/.nyc_output/processinfo/0208d41a-48bc-4675-a861-0475eb461a17.json +1 -0
  8. package/.nyc_output/processinfo/588169a6-88e9-4949-af5a-631822d7dc42.json +1 -0
  9. package/.nyc_output/processinfo/5bbdf331-cd01-4869-9d54-3d708610224a.json +1 -0
  10. package/.nyc_output/processinfo/6d7c60ad-a404-4a1d-af86-8a334cff5f02.json +1 -0
  11. package/.nyc_output/processinfo/8dae7e8c-5022-4a0c-a5b3-bf547f97961b.json +1 -0
  12. package/.nyc_output/processinfo/f63bf7c5-4f58-4b46-a822-6f5ccf5a54a8.json +1 -0
  13. package/.nyc_output/processinfo/index.json +1 -0
  14. package/.taprc +1 -0
  15. package/LICENSE +201 -0
  16. package/NOTICE +13 -0
  17. package/README.md +13 -0
  18. package/lib/entity.js +287 -0
  19. package/lib/queries/index.js +23 -0
  20. package/lib/queries/mariadb.js +11 -0
  21. package/lib/queries/mysql-shared.js +62 -0
  22. package/lib/queries/mysql.js +104 -0
  23. package/lib/queries/pg.js +79 -0
  24. package/lib/queries/shared.js +100 -0
  25. package/lib/queries/sqlite.js +169 -0
  26. package/lib/utils.js +14 -0
  27. package/mapper.d.ts +308 -0
  28. package/mapper.js +155 -0
  29. package/package.json +44 -0
  30. package/test/entity.test.js +344 -0
  31. package/test/helper.js +66 -0
  32. package/test/hooks.test.js +325 -0
  33. package/test/inserted_at_updated_at.test.js +132 -0
  34. package/test/mapper.test.js +288 -0
  35. package/test/types/mapper.test-d.ts +64 -0
  36. package/test/where.test.js +316 -0
@@ -0,0 +1,288 @@
1
+
2
+ const { test } = require('tap')
3
+ const { connect, plugin } = require('..')
4
+ const { clear, connInfo, isPg, isMysql, isSQLite } = require('./helper')
5
+ const fastify = require('fastify')
6
+
7
+ const fakeLogger = {
8
+ trace: () => {},
9
+ error: () => {}
10
+ }
11
+
12
+ test('should throw if no connection string is provided', async ({ equal }) => {
13
+ try {
14
+ await connect({
15
+ connectionString: false
16
+ })
17
+ } catch (err) {
18
+ equal(err.message, 'connectionString is required')
19
+ }
20
+ })
21
+
22
+ test('[PG] return entities', { skip: !isPg }, async ({ pass, teardown, equal }) => {
23
+ async function onDatabaseLoad (db, sql) {
24
+ await clear(db, sql)
25
+ teardown(() => db.dispose())
26
+
27
+ await db.query(sql`CREATE TABLE pages (
28
+ id SERIAL PRIMARY KEY,
29
+ title VARCHAR(255) NOT NULL
30
+ );`)
31
+ }
32
+ const mapper = await connect({
33
+ connectionString: connInfo.connectionString,
34
+ log: fakeLogger,
35
+ onDatabaseLoad,
36
+ ignore: {},
37
+ hooks: {}
38
+ })
39
+ const pageEntity = mapper.entities.page
40
+ equal(pageEntity.name, 'Page')
41
+ equal(pageEntity.singularName, 'page')
42
+ equal(pageEntity.pluralName, 'pages')
43
+ pass()
44
+ })
45
+
46
+ test('[mysql] return entities', { skip: !isMysql }, async ({ pass, teardown, equal }) => {
47
+ async function onDatabaseLoad (db, sql) {
48
+ await clear(db, sql)
49
+ teardown(() => db.dispose())
50
+
51
+ await db.query(sql`CREATE TABLE pages (
52
+ id SERIAL PRIMARY KEY,
53
+ title VARCHAR(255) NOT NULL
54
+ );`)
55
+ }
56
+ const mapper = await connect({
57
+ connectionString: connInfo.connectionString,
58
+ log: fakeLogger,
59
+ onDatabaseLoad,
60
+ ignore: {},
61
+ hooks: {}
62
+ })
63
+ const pageEntity = mapper.entities.page
64
+ equal(pageEntity.name, 'Page')
65
+ equal(pageEntity.singularName, 'page')
66
+ equal(pageEntity.pluralName, 'pages')
67
+ pass()
68
+ })
69
+
70
+ test('[sqlite] return entities', { skip: !isSQLite }, async ({ pass, teardown, equal }) => {
71
+ async function onDatabaseLoad (db, sql) {
72
+ teardown(async () => await clear(db, sql))
73
+ teardown(() => db.dispose())
74
+
75
+ await db.query(sql`CREATE TABLE IF NOT EXISTS pages (
76
+ id SERIAL PRIMARY KEY,
77
+ title VARCHAR(255) NOT NULL
78
+ );`)
79
+ }
80
+ const mapper = await connect({
81
+ connectionString: connInfo.connectionString,
82
+ log: fakeLogger,
83
+ onDatabaseLoad,
84
+ ignore: {},
85
+ hooks: {}
86
+ })
87
+ const pageEntity = mapper.entities.page
88
+ equal(pageEntity.name, 'Page')
89
+ equal(pageEntity.singularName, 'page')
90
+ equal(pageEntity.pluralName, 'pages')
91
+ pass()
92
+ })
93
+
94
+ test('ignore tables', async ({ teardown, has }) => {
95
+ async function onDatabaseLoad (db, sql) {
96
+ teardown(async () => await clear(db, sql))
97
+ teardown(() => db.dispose())
98
+
99
+ await db.query(sql`CREATE TABLE IF NOT EXISTS pages (
100
+ id SERIAL PRIMARY KEY,
101
+ title VARCHAR(255) NOT NULL
102
+ );`)
103
+
104
+ await db.query(sql`CREATE TABLE IF NOT EXISTS users (
105
+ id SERIAL PRIMARY KEY,
106
+ username VARCHAR(255) NOT NULL
107
+ );`)
108
+ }
109
+ const mapper = await connect({
110
+ connectionString: connInfo.connectionString,
111
+ log: fakeLogger,
112
+ onDatabaseLoad,
113
+ ignore: { users: true },
114
+ hooks: {}
115
+ })
116
+ has(mapper.entities.users, undefined)
117
+ })
118
+
119
+ test('[PG] return entities with Fastify', { skip: !isPg }, async ({ pass, teardown, equal }) => {
120
+ async function onDatabaseLoad (db, sql) {
121
+ teardown(async () => await clear(db, sql))
122
+
123
+ await db.query(sql`CREATE TABLE IF NOT EXISTS pages (
124
+ id SERIAL PRIMARY KEY,
125
+ title VARCHAR(255) NOT NULL
126
+ );`)
127
+ }
128
+ const app = fastify()
129
+ teardown(() => app.close())
130
+ app.register(plugin, {
131
+ connectionString: connInfo.connectionString,
132
+ log: fakeLogger,
133
+ onDatabaseLoad
134
+ })
135
+ await app.ready()
136
+ const pageEntity = app.platformatic.entities.page
137
+ equal(pageEntity.name, 'Page')
138
+ equal(pageEntity.singularName, 'page')
139
+ equal(pageEntity.pluralName, 'pages')
140
+ pass()
141
+ })
142
+
143
+ test('[mysql] return entities', { skip: !isMysql }, async ({ pass, teardown, equal }) => {
144
+ async function onDatabaseLoad (db, sql) {
145
+ teardown(async () => await clear(db, sql))
146
+
147
+ await db.query(sql`CREATE TABLE IF NOT EXISTS pages (
148
+ id SERIAL PRIMARY KEY,
149
+ title VARCHAR(255) NOT NULL
150
+ );`)
151
+ }
152
+ const app = fastify()
153
+ teardown(() => app.close())
154
+ app.register(plugin, {
155
+ connectionString: connInfo.connectionString,
156
+ onDatabaseLoad
157
+ })
158
+ await app.ready()
159
+ const pageEntity = app.platformatic.entities.page
160
+ equal(pageEntity.name, 'Page')
161
+ equal(pageEntity.singularName, 'page')
162
+ equal(pageEntity.pluralName, 'pages')
163
+ pass()
164
+ })
165
+
166
+ test('[sqlite] return entities', { skip: !isSQLite }, async ({ pass, teardown, equal }) => {
167
+ async function onDatabaseLoad (db, sql) {
168
+ teardown(async () => await clear(db, sql))
169
+
170
+ await db.query(sql`CREATE TABLE IF NOT EXISTS pages (
171
+ id SERIAL PRIMARY KEY,
172
+ title VARCHAR(255) NOT NULL
173
+ );`)
174
+ }
175
+ const app = fastify()
176
+ teardown(() => app.close())
177
+ app.register(plugin, {
178
+ connectionString: connInfo.connectionString,
179
+ onDatabaseLoad
180
+ })
181
+ await app.ready()
182
+ const pageEntity = app.platformatic.entities.page
183
+ equal(pageEntity.name, 'Page')
184
+ equal(pageEntity.singularName, 'page')
185
+ equal(pageEntity.pluralName, 'pages')
186
+ pass()
187
+ })
188
+
189
+ test('missing connectionString', async ({ rejects }) => {
190
+ const app = fastify()
191
+ app.register(plugin)
192
+
193
+ await rejects(app.ready(), /connectionString/)
194
+ })
195
+
196
+ test('[pg] throws if no primary key', { skip: !isPg }, async ({ pass, teardown, equal }) => {
197
+ async function onDatabaseLoad (db, sql) {
198
+ await clear(db, sql)
199
+ teardown(() => db.dispose())
200
+
201
+ await db.query(sql`CREATE TABLE IF NOT EXISTS pages (
202
+ id SERIAL,
203
+ title VARCHAR(255) NOT NULL
204
+ );`)
205
+ }
206
+ try {
207
+ await connect({
208
+ connectionString: connInfo.connectionString,
209
+ log: fakeLogger,
210
+ onDatabaseLoad,
211
+ ignore: {},
212
+ hooks: {}
213
+ })
214
+ } catch (err) {
215
+ equal(err.message, 'Cannot find primary key for Page entity')
216
+ }
217
+ })
218
+
219
+ test('[mysql] throws if no primary key', { skip: !isMysql }, async ({ pass, teardown, equal }) => {
220
+ async function onDatabaseLoad (db, sql) {
221
+ await clear(db, sql)
222
+ teardown(() => db.dispose())
223
+
224
+ await db.query(sql`CREATE TABLE pages (
225
+ id SERIAL,
226
+ title VARCHAR(255) NOT NULL
227
+ );`)
228
+ }
229
+ try {
230
+ await connect({
231
+ connectionString: connInfo.connectionString,
232
+ log: fakeLogger,
233
+ onDatabaseLoad,
234
+ ignore: {},
235
+ hooks: {}
236
+ })
237
+ } catch (err) {
238
+ equal(err.message, 'Cannot find primary key for Page entity')
239
+ }
240
+ })
241
+
242
+ test('[sqlite] throws if primary key is not defined', { skip: !isSQLite }, async ({ pass, teardown, equal }) => {
243
+ async function onDatabaseLoad (db, sql) {
244
+ await clear(db, sql)
245
+
246
+ await db.query(sql`CREATE TABLE pages(
247
+ id INTEGER NOT NULL,
248
+ title TEXT NOT NULL
249
+ );
250
+ `)
251
+ }
252
+ try {
253
+ await connect({
254
+ connectionString: connInfo.connectionString,
255
+ log: fakeLogger,
256
+ onDatabaseLoad,
257
+ ignore: {},
258
+ hooks: {}
259
+ })
260
+ } catch (err) {
261
+ equal(err.message, 'Cannot find primary key for Page entity')
262
+ }
263
+ })
264
+
265
+ test('[sqlite] throws with multiple primary keys', { skip: !isSQLite }, async ({ pass, teardown, equal }) => {
266
+ async function onDatabaseLoad (db, sql) {
267
+ await clear(db, sql)
268
+
269
+ await db.query(sql`CREATE TABLE pages(
270
+ id INTEGER NOT NULL,
271
+ author_id INTEGER NOT NULL,
272
+ title TEXT NOT NULL,
273
+ PRIMARY KEY (id, author_id)
274
+ );
275
+ `)
276
+ }
277
+ try {
278
+ await connect({
279
+ connectionString: connInfo.connectionString,
280
+ log: fakeLogger,
281
+ onDatabaseLoad,
282
+ ignore: {},
283
+ hooks: {}
284
+ })
285
+ } catch (err) {
286
+ equal(err.message, 'Table pages has 2 primary keys')
287
+ }
288
+ })
@@ -0,0 +1,64 @@
1
+ import { expectType } from 'tsd'
2
+ import { SQL, SQLQuery } from '@databases/sql'
3
+ import { fastify, FastifyInstance } from 'fastify'
4
+ import {
5
+ connect,
6
+ plugin,
7
+ utils,
8
+ Entity,
9
+ DBEntityField,
10
+ Database,
11
+ WhereCondition,
12
+ SQLMapperPluginInterface,
13
+ EntityHooks,
14
+ } from '../../mapper'
15
+
16
+ const pluginOptions: SQLMapperPluginInterface = await connect({ connectionString: '' })
17
+ expectType<Database>(pluginOptions.db)
18
+ expectType<SQL>(pluginOptions.sql)
19
+ expectType<(entityName: string, hooks: EntityHooks) => any>(pluginOptions.addEntityHooks)
20
+ expectType<{ [entityName: string]: Entity }>(pluginOptions.entities)
21
+
22
+ interface EntityFields {
23
+ id: number,
24
+ name: string,
25
+ }
26
+
27
+ const entity: Entity<EntityFields> = pluginOptions.entities.entityName
28
+ expectType<string>(entity.name)
29
+ expectType<string>(entity.singularName)
30
+ expectType<string>(entity.pluralName)
31
+ expectType<string>(entity.primaryKey)
32
+ expectType<string>(entity.table)
33
+ expectType<any[]>(entity.relations)
34
+ expectType<{ [columnName: string]: DBEntityField }>(entity.fields)
35
+ expectType<{ [columnName: string]: DBEntityField }>(entity.camelCasedFields)
36
+ expectType<(input: { [columnName: string]: any }) => { [columnName: string]: any }>(entity.fixInput)
37
+ expectType<(input: { [columnName: string]: any }) => { [columnName: string]: any }>(entity.fixOutput)
38
+ expectType<Partial<EntityFields>[]>(await entity.find())
39
+ expectType<Partial<EntityFields>[]>(await entity.insert({ inputs: [{ id: 1, name: 'test' }] }))
40
+ expectType<Partial<EntityFields>>(await entity.save({ input: { id: 1, name: 'test' } }))
41
+ expectType<Partial<EntityFields>[]>(await entity.delete())
42
+
43
+ expectType<SQLMapperPluginInterface>(await connect({ connectionString: '' }))
44
+ expectType<SQLMapperPluginInterface>(await connect({ connectionString: '', autoTimestamp: true }))
45
+ expectType<SQLMapperPluginInterface>(await connect({ connectionString: '', hooks: {} }))
46
+ expectType<SQLMapperPluginInterface>(await connect({ connectionString: '', hooks: {
47
+ Page: {
48
+ async find(options: any): Promise<any[]> { return [] },
49
+ async insert(options: { inputs: any[], fields?: string[] }): Promise<any[]> { return [] },
50
+ async save(options: { input: any, fields?: string[] }): Promise<any> { return {} },
51
+ async delete(options?: { where: WhereCondition, fields: string[] }): Promise<any[]> { return [] },
52
+ }
53
+ }}))
54
+ expectType<SQLMapperPluginInterface>(await connect({ connectionString: '', ignore: {} }))
55
+ expectType<SQLMapperPluginInterface>(await connect({ connectionString: '', onDatabaseLoad(db: Database, sql: SQL) {
56
+ expectType<(query: SQLQuery) => Promise<any[]>>(db.query)
57
+ expectType<() => Promise<void>>(db.dispose)
58
+ }}))
59
+
60
+ const instance: FastifyInstance = fastify()
61
+ instance.register(plugin, { connectionString: '', autoTimestamp: true })
62
+ instance.register((instance) => { expectType<SQLMapperPluginInterface>(instance.platformatic) })
63
+
64
+ expectType<(str: string) => string>(utils.toSingular)
@@ -0,0 +1,316 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('tap')
4
+ const { connect } = require('..')
5
+ const { clear, connInfo, isMysql, isSQLite } = require('./helper')
6
+ const fakeLogger = {
7
+ trace: () => {},
8
+ error: () => {}
9
+ }
10
+
11
+ test('list', async ({ pass, teardown, same, equal }) => {
12
+ const mapper = await connect({
13
+ ...connInfo,
14
+ log: fakeLogger,
15
+ async onDatabaseLoad (db, sql) {
16
+ teardown(() => db.dispose())
17
+ pass('onDatabaseLoad called')
18
+
19
+ await clear(db, sql)
20
+
21
+ if (isSQLite) {
22
+ await db.query(sql`CREATE TABLE posts (
23
+ id INTEGER PRIMARY KEY,
24
+ title VARCHAR(42),
25
+ long_text TEXT,
26
+ counter INTEGER
27
+ );`)
28
+ } else {
29
+ await db.query(sql`CREATE TABLE posts (
30
+ id SERIAL PRIMARY KEY,
31
+ title VARCHAR(42),
32
+ long_text TEXT,
33
+ counter INTEGER
34
+ );`)
35
+ }
36
+ }
37
+ })
38
+
39
+ const entity = mapper.entities.post
40
+
41
+ const posts = [{
42
+ title: 'Dog',
43
+ longText: 'Foo',
44
+ counter: 10
45
+ }, {
46
+ title: 'Cat',
47
+ longText: 'Bar',
48
+ counter: 20
49
+ }, {
50
+ title: 'Mouse',
51
+ longText: 'Baz',
52
+ counter: 30
53
+ }, {
54
+ title: 'Duck',
55
+ longText: 'A duck tale',
56
+ counter: 40
57
+ }]
58
+
59
+ await entity.insert({
60
+ inputs: posts
61
+ })
62
+
63
+ same(await entity.find({ where: { title: { eq: 'Dog' } }, fields: ['id', 'title', 'longText'] }), [{
64
+ id: '1',
65
+ title: 'Dog',
66
+ longText: 'Foo'
67
+ }])
68
+
69
+ same(await entity.find({ limit: 1, offset: 0, fields: ['id', 'title', 'longText'] }), [{
70
+ id: '1',
71
+ title: 'Dog',
72
+ longText: 'Foo'
73
+ }])
74
+
75
+ same(await entity.find({ limit: 1, offset: 0, orderBy: [{ field: 'id', direction: 'desc' }], fields: ['id', 'title'] }), [{
76
+ id: '4',
77
+ title: 'Duck'
78
+ }])
79
+
80
+ same(await entity.find({ where: { title: { neq: 'Dog' } }, fields: ['id', 'title', 'longText'] }), [{
81
+ id: '2',
82
+ title: 'Cat',
83
+ longText: 'Bar'
84
+ }, {
85
+ id: '3',
86
+ title: 'Mouse',
87
+ longText: 'Baz'
88
+ }, {
89
+ id: '4',
90
+ title: 'Duck',
91
+ longText: 'A duck tale'
92
+ }])
93
+
94
+ same(await entity.find({ where: { counter: { gt: 10 } }, fields: ['id', 'title', 'longText'] }), [{
95
+ id: '2',
96
+ title: 'Cat',
97
+ longText: 'Bar'
98
+ }, {
99
+ id: '3',
100
+ title: 'Mouse',
101
+ longText: 'Baz'
102
+ }, {
103
+ id: '4',
104
+ title: 'Duck',
105
+ longText: 'A duck tale'
106
+ }])
107
+
108
+ same(await entity.find({ where: { counter: { lt: 40 } }, fields: ['id', 'title', 'longText'] }), [{
109
+ id: '1',
110
+ title: 'Dog',
111
+ longText: 'Foo'
112
+ }, {
113
+ id: '2',
114
+ title: 'Cat',
115
+ longText: 'Bar'
116
+ }, {
117
+ id: '3',
118
+ title: 'Mouse',
119
+ longText: 'Baz'
120
+ }])
121
+
122
+ same(await entity.find({ where: { counter: { lte: 30 } }, fields: ['id', 'title', 'longText'] }), [{
123
+ id: '1',
124
+ title: 'Dog',
125
+ longText: 'Foo'
126
+ }, {
127
+ id: '2',
128
+ title: 'Cat',
129
+ longText: 'Bar'
130
+ }, {
131
+ id: '3',
132
+ title: 'Mouse',
133
+ longText: 'Baz'
134
+ }])
135
+
136
+ same(await entity.find({ where: { counter: { gte: 20 } }, fields: ['id', 'title', 'longText'] }), [{
137
+ id: '2',
138
+ title: 'Cat',
139
+ longText: 'Bar'
140
+ }, {
141
+ id: '3',
142
+ title: 'Mouse',
143
+ longText: 'Baz'
144
+ }, {
145
+ id: '4',
146
+ title: 'Duck',
147
+ longText: 'A duck tale'
148
+ }])
149
+
150
+ same(await entity.find({ where: { counter: { in: [20, 30] } }, fields: ['id', 'title', 'longText'] }), [{
151
+ id: '2',
152
+ title: 'Cat',
153
+ longText: 'Bar'
154
+ }, {
155
+ id: '3',
156
+ title: 'Mouse',
157
+ longText: 'Baz'
158
+ }])
159
+
160
+ same(await entity.find({ where: { counter: { nin: [10, 40] } }, fields: ['id', 'title', 'longText'] }), [{
161
+ id: '2',
162
+ title: 'Cat',
163
+ longText: 'Bar'
164
+ }, {
165
+ id: '3',
166
+ title: 'Mouse',
167
+ longText: 'Baz'
168
+ }])
169
+
170
+ same(await entity.find({ where: { counter: { gt: 10, lt: 40 } }, fields: ['id', 'title', 'longText'] }), [{
171
+ id: '2',
172
+ title: 'Cat',
173
+ longText: 'Bar'
174
+ }, {
175
+ id: '3',
176
+ title: 'Mouse',
177
+ longText: 'Baz'
178
+ }])
179
+ })
180
+
181
+ test('foreign keys', async ({ pass, teardown, same, equal }) => {
182
+ const mapper = await connect({
183
+ ...connInfo,
184
+ log: fakeLogger,
185
+ async onDatabaseLoad (db, sql) {
186
+ teardown(() => db.dispose())
187
+ pass('onDatabaseLoad called')
188
+
189
+ await clear(db, sql)
190
+
191
+ if (isMysql) {
192
+ await db.query(sql`
193
+ CREATE TABLE owners (
194
+ id SERIAL PRIMARY KEY,
195
+ name VARCHAR(255)
196
+ );
197
+ CREATE TABLE posts (
198
+ id SERIAL PRIMARY KEY,
199
+ title VARCHAR(42),
200
+ long_text TEXT,
201
+ counter INTEGER,
202
+ owner_id BIGINT UNSIGNED,
203
+ FOREIGN KEY (owner_id) REFERENCES owners(id) ON DELETE CASCADE
204
+ );
205
+ `)
206
+ } else if (isSQLite) {
207
+ await db.query(sql`
208
+ CREATE TABLE owners (
209
+ id INTEGER PRIMARY KEY,
210
+ name VARCHAR(255)
211
+ );
212
+ `)
213
+
214
+ await db.query(sql`
215
+ CREATE TABLE posts (
216
+ id INTEGER PRIMARY KEY,
217
+ title VARCHAR(42),
218
+ long_text TEXT,
219
+ counter INTEGER,
220
+ owner_id BIGINT UNSIGNED,
221
+ FOREIGN KEY (owner_id) REFERENCES owners(id) ON DELETE CASCADE
222
+ );
223
+ `)
224
+ } else {
225
+ await db.query(sql`
226
+ CREATE TABLE owners (
227
+ id SERIAL PRIMARY KEY,
228
+ name VARCHAR(255)
229
+ );
230
+ CREATE TABLE posts (
231
+ id SERIAL PRIMARY KEY,
232
+ title VARCHAR(42),
233
+ long_text TEXT,
234
+ counter INTEGER,
235
+ owner_id INTEGER REFERENCES owners(id)
236
+ );`)
237
+ }
238
+ }
239
+ })
240
+
241
+ const owners = [{
242
+ name: 'Matteo'
243
+ }, {
244
+ name: 'Luca'
245
+ }]
246
+
247
+ const posts = [{
248
+ title: 'Dog',
249
+ longText: 'Foo',
250
+ counter: 10
251
+ }, {
252
+ title: 'Cat',
253
+ longText: 'Bar',
254
+ counter: 20
255
+ }, {
256
+ title: 'Mouse',
257
+ longText: 'Baz',
258
+ counter: 30
259
+ }, {
260
+ title: 'Duck',
261
+ longText: 'A duck tale',
262
+ counter: 40
263
+ }]
264
+
265
+ {
266
+ const res = await mapper.entities.owner.insert({
267
+ inputs: owners
268
+ })
269
+ const toAssign = [...posts]
270
+ for (const owner of res) {
271
+ toAssign.shift().ownerId = owner.id
272
+ toAssign.shift().ownerId = owner.id
273
+ }
274
+ await mapper.entities.post.insert({
275
+ inputs: posts
276
+ })
277
+ }
278
+
279
+ {
280
+ const owners = await mapper.entities.owner.find()
281
+ equal(owners.length, 2)
282
+
283
+ for (const owner of owners) {
284
+ owner.posts = await mapper.entities.post.find({ where: { ownerId: { eq: owner.id } }, fields: ['id', 'title', 'longText'] })
285
+ }
286
+ same(owners, [{
287
+ id: '1',
288
+ name: 'Matteo',
289
+ posts: [{
290
+ id: '1',
291
+ title: 'Dog',
292
+ longText: 'Foo',
293
+ ownerId: '1'
294
+ }, {
295
+ id: '2',
296
+ title: 'Cat',
297
+ longText: 'Bar',
298
+ ownerId: '1'
299
+ }]
300
+ }, {
301
+ id: '2',
302
+ name: 'Luca',
303
+ posts: [{
304
+ id: '3',
305
+ title: 'Mouse',
306
+ longText: 'Baz',
307
+ ownerId: '2'
308
+ }, {
309
+ id: '4',
310
+ title: 'Duck',
311
+ longText: 'A duck tale',
312
+ ownerId: '2'
313
+ }]
314
+ }])
315
+ }
316
+ })