diff --git a/packages/core/database/src/__tests__/repository/find.test.ts b/packages/core/database/src/__tests__/repository/find.test.ts index 59abaa76f..264bd8618 100644 --- a/packages/core/database/src/__tests__/repository/find.test.ts +++ b/packages/core/database/src/__tests__/repository/find.test.ts @@ -5,9 +5,7 @@ import { Collection } from '../../collection'; describe('find with associations', () => { let db: Database; beforeEach(async () => { - db = mockDatabase({ - tablePrefix: '', - }); + db = mockDatabase(); await db.clean({ drop: true }); }); @@ -16,6 +14,80 @@ describe('find with associations', () => { await db.close(); }); + it('should filter by association array field', async () => { + const User = db.collection({ + name: 'users', + fields: [ + { + type: 'string', + name: 'name', + }, + { + type: 'hasMany', + name: 'posts', + }, + ], + }); + + const Post = db.collection({ + name: 'posts', + fields: [ + { + type: 'array', + name: 'tags', + }, + { + type: 'string', + name: 'title', + }, + ], + }); + + await db.sync(); + + await User.repository.create({ + values: [ + { + name: 'u1', + posts: [ + { + tags: ['t1'], + title: 'u1p1', + }, + ], + }, + ], + }); + + const posts = await Post.repository.find({ + filter: { + tags: { + $match: ['t1'], + }, + }, + }); + + expect(posts.length).toEqual(1); + + const filter = { + $and: [ + { + posts: { + tags: { + $match: ['t1'], + }, + }, + }, + ], + }; + + const results = await User.repository.find({ + filter, + }); + + expect(results[0].get('name')).toEqual('u1'); + }); + it('should filter by association field', async () => { const User = db.collection({ name: 'users', diff --git a/packages/core/database/src/operators/array.ts b/packages/core/database/src/operators/array.ts index 25c5e6531..c17b7220f 100644 --- a/packages/core/database/src/operators/array.ts +++ b/packages/core/database/src/operators/array.ts @@ -11,6 +11,11 @@ const escape = (value, ctx) => { return sequelize.escape(value); }; +const getQueryInterface = (ctx) => { + const sequelize = ctx.db.sequelize; + return sequelize.getQueryInterface(); +}; + const sqliteExistQuery = (value, ctx) => { const fieldName = getFieldName(ctx); const name = ctx.fullName === fieldName ? `"${ctx.model.name}"."${fieldName}"` : `"${fieldName}"`; @@ -45,10 +50,9 @@ export default { const fieldName = getFieldName(ctx); if (isPg(ctx)) { - return { - [Op.contained]: value, - [Op.contains]: value, - }; + const name = ctx.fullName === fieldName ? `"${ctx.model.name}"."${fieldName}"` : `"${fieldName}"`; + const queryValue = escape(JSON.stringify(value), ctx); + return Sequelize.literal(`${name} @> ${queryValue}::JSONB AND ${name} <@ ${queryValue}::JSONB`); } value = escape(JSON.stringify(value.sort()), ctx);