feat: embedded entities (#369)
This commit is contained in:
parent
017f997b94
commit
e306f78fb2
@ -1,5 +1,6 @@
|
|||||||
import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
|
import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'
|
||||||
import { CatEntity } from './cat.entity'
|
import { CatEntity } from './cat.entity'
|
||||||
|
import { SizeEmbed } from './size.embed'
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class CatToyEntity {
|
export class CatToyEntity {
|
||||||
@ -9,6 +10,9 @@ export class CatToyEntity {
|
|||||||
@Column()
|
@Column()
|
||||||
name: string
|
name: string
|
||||||
|
|
||||||
|
@Column(() => SizeEmbed)
|
||||||
|
size: SizeEmbed
|
||||||
|
|
||||||
@ManyToOne(() => CatEntity, (cat) => cat.toys)
|
@ManyToOne(() => CatEntity, (cat) => cat.toys)
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
cat: CatEntity
|
cat: CatEntity
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
} from 'typeorm'
|
} from 'typeorm'
|
||||||
import { CatToyEntity } from './cat-toy.entity'
|
import { CatToyEntity } from './cat-toy.entity'
|
||||||
import { CatHomeEntity } from './cat-home.entity'
|
import { CatHomeEntity } from './cat-home.entity'
|
||||||
|
import { SizeEmbed } from './size.embed'
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class CatEntity {
|
export class CatEntity {
|
||||||
@ -25,6 +26,9 @@ export class CatEntity {
|
|||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
age: number | null
|
age: number | null
|
||||||
|
|
||||||
|
@Column(() => SizeEmbed)
|
||||||
|
size: SizeEmbed
|
||||||
|
|
||||||
@OneToMany(() => CatToyEntity, (catToy) => catToy.cat)
|
@OneToMany(() => CatToyEntity, (catToy) => catToy.cat)
|
||||||
toys: CatToyEntity[]
|
toys: CatToyEntity[]
|
||||||
|
|
||||||
|
12
src/__tests__/size.embed.ts
Normal file
12
src/__tests__/size.embed.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Column } from 'typeorm'
|
||||||
|
|
||||||
|
export class SizeEmbed {
|
||||||
|
@Column()
|
||||||
|
height: number
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
width: number
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
length: number
|
||||||
|
}
|
@ -36,17 +36,17 @@ describe('paginate', () => {
|
|||||||
catToyRepo = connection.getRepository(CatToyEntity)
|
catToyRepo = connection.getRepository(CatToyEntity)
|
||||||
catHomeRepo = connection.getRepository(CatHomeEntity)
|
catHomeRepo = connection.getRepository(CatHomeEntity)
|
||||||
cats = await catRepo.save([
|
cats = await catRepo.save([
|
||||||
catRepo.create({ name: 'Milo', color: 'brown', age: 6 }),
|
catRepo.create({ name: 'Milo', color: 'brown', age: 6, size: { height: 25, width: 10, length: 40 } }),
|
||||||
catRepo.create({ name: 'Garfield', color: 'ginger', age: 5 }),
|
catRepo.create({ name: 'Garfield', color: 'ginger', age: 5, size: { height: 30, width: 15, length: 45 } }),
|
||||||
catRepo.create({ name: 'Shadow', color: 'black', age: 4 }),
|
catRepo.create({ name: 'Shadow', color: 'black', age: 4, size: { height: 25, width: 10, length: 50 } }),
|
||||||
catRepo.create({ name: 'George', color: 'white', age: 3 }),
|
catRepo.create({ name: 'George', color: 'white', age: 3, size: { height: 35, width: 12, length: 40 } }),
|
||||||
catRepo.create({ name: 'Leche', color: 'white', age: null }),
|
catRepo.create({ name: 'Leche', color: 'white', age: null, size: { height: 10, width: 5, length: 15 } }),
|
||||||
])
|
])
|
||||||
catToys = await catToyRepo.save([
|
catToys = await catToyRepo.save([
|
||||||
catToyRepo.create({ name: 'Fuzzy Thing', cat: cats[0] }),
|
catToyRepo.create({ name: 'Fuzzy Thing', cat: cats[0], size: { height: 10, width: 10, length: 10 } }),
|
||||||
catToyRepo.create({ name: 'Stuffed Mouse', cat: cats[0] }),
|
catToyRepo.create({ name: 'Stuffed Mouse', cat: cats[0], size: { height: 5, width: 5, length: 12 } }),
|
||||||
catToyRepo.create({ name: 'Mouse', cat: cats[0] }),
|
catToyRepo.create({ name: 'Mouse', cat: cats[0], size: { height: 6, width: 4, length: 13 } }),
|
||||||
catToyRepo.create({ name: 'String', cat: cats[1] }),
|
catToyRepo.create({ name: 'String', cat: cats[1], size: { height: 1, width: 1, length: 50 } }),
|
||||||
])
|
])
|
||||||
catHomes = await catHomeRepo.save([
|
catHomes = await catHomeRepo.save([
|
||||||
catHomeRepo.create({ name: 'Box', cat: cats[0] }),
|
catHomeRepo.create({ name: 'Box', cat: cats[0] }),
|
||||||
@ -627,7 +627,7 @@ describe('paginate', () => {
|
|||||||
relations: ['cat'],
|
relations: ['cat'],
|
||||||
sortableColumns: ['id', 'name'],
|
sortableColumns: ['id', 'name'],
|
||||||
filterableColumns: {
|
filterableColumns: {
|
||||||
createdAt: [FilterOperator.BTW],
|
'cat.age': [FilterOperator.BTW],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
const query: PaginateQuery = {
|
const query: PaginateQuery = {
|
||||||
@ -642,10 +642,453 @@ describe('paginate', () => {
|
|||||||
expect(result.meta.filter).toStrictEqual({
|
expect(result.meta.filter).toStrictEqual({
|
||||||
'cat.age': '$btw:6,10',
|
'cat.age': '$btw:6,10',
|
||||||
})
|
})
|
||||||
expect(result.data).toStrictEqual([catHomes[0], catHomes[1]])
|
expect(result.data).toStrictEqual([catHomes[0]])
|
||||||
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.cat.age=$btw:6,10')
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.cat.age=$btw:6,10')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should return result based on sort on embedded entity', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'size.height', 'size.length', 'size.width'],
|
||||||
|
searchableColumns: ['name'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
sortBy: [
|
||||||
|
['size.height', 'ASC'],
|
||||||
|
['size.length', 'ASC'],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
const orderedCats = [cats[4], cats[0], cats[2], cats[1], cats[3]]
|
||||||
|
expect(result.data).toStrictEqual(orderedCats)
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=size.height:ASC&sortBy=size.length:ASC')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on sort on embedded entity when other relations loaded', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'size.height', 'size.length', 'size.width'],
|
||||||
|
searchableColumns: ['name'],
|
||||||
|
relations: ['home', 'toys'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
sortBy: [
|
||||||
|
['size.height', 'DESC'],
|
||||||
|
['size.length', 'DESC'],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
const copyCats = cats.map((cat: CatEntity) => {
|
||||||
|
const copy = clone(cat)
|
||||||
|
copy.home = null
|
||||||
|
copy.toys = []
|
||||||
|
return copy
|
||||||
|
})
|
||||||
|
|
||||||
|
const copyHomes = catHomes.map((home: CatHomeEntity) => {
|
||||||
|
const copy = clone(home)
|
||||||
|
delete copy.cat
|
||||||
|
return copy
|
||||||
|
})
|
||||||
|
copyCats[0].home = copyHomes[0]
|
||||||
|
copyCats[1].home = copyHomes[1]
|
||||||
|
|
||||||
|
const copyToys = catToys.map((toy: CatToyEntity) => {
|
||||||
|
const copy = clone(toy)
|
||||||
|
delete copy.cat
|
||||||
|
return copy
|
||||||
|
})
|
||||||
|
copyCats[0].toys = [copyToys[0], copyToys[1], copyToys[2]]
|
||||||
|
copyCats[1].toys = [copyToys[3]]
|
||||||
|
|
||||||
|
const orderedCats = [copyCats[3], copyCats[1], copyCats[2], copyCats[0], copyCats[4]]
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual(orderedCats)
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=size.height:DESC&sortBy=size.length:DESC')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on sort on embedded entity on one-to-many relation', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'toys.size.height', 'toys.size.length', 'toys.size.width'],
|
||||||
|
searchableColumns: ['name'],
|
||||||
|
relations: ['toys'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
sortBy: [
|
||||||
|
['id', 'DESC'],
|
||||||
|
['toys.size.height', 'ASC'],
|
||||||
|
['toys.size.length', 'ASC'],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
const toy0 = clone(catToys[0])
|
||||||
|
delete toy0.cat
|
||||||
|
|
||||||
|
const toy1 = clone(catToys[1])
|
||||||
|
delete toy1.cat
|
||||||
|
|
||||||
|
const toy2 = clone(catToys[2])
|
||||||
|
delete toy2.cat
|
||||||
|
|
||||||
|
const toy3 = clone(catToys[3])
|
||||||
|
delete toy3.cat
|
||||||
|
|
||||||
|
const orderedCats = [
|
||||||
|
Object.assign(clone(cats[4]), { toys: [] }),
|
||||||
|
Object.assign(clone(cats[3]), { toys: [] }),
|
||||||
|
Object.assign(clone(cats[2]), { toys: [] }),
|
||||||
|
Object.assign(clone(cats[1]), { toys: [toy3] }),
|
||||||
|
Object.assign(clone(cats[0]), { toys: [toy1, toy2, toy0] }),
|
||||||
|
]
|
||||||
|
expect(result.data).toStrictEqual(orderedCats)
|
||||||
|
expect(result.links.current).toBe(
|
||||||
|
'?page=1&limit=20&sortBy=id:DESC&sortBy=toys.size.height:ASC&sortBy=toys.size.length:ASC'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on sort on embedded entity on many-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatToyEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'cat.size.height', 'cat.size.length', 'cat.size.width'],
|
||||||
|
searchableColumns: ['name'],
|
||||||
|
relations: ['cat'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
sortBy: [
|
||||||
|
['cat.size.height', 'DESC'],
|
||||||
|
['cat.size.length', 'DESC'],
|
||||||
|
['name', 'ASC'],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
|
||||||
|
const orderedToys = [catToys[3], catToys[0], catToys[2], catToys[1]]
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual(orderedToys)
|
||||||
|
expect(result.links.current).toBe(
|
||||||
|
'?page=1&limit=20&sortBy=cat.size.height:DESC&sortBy=cat.size.length:DESC&sortBy=name:ASC'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on sort on embedded entity on one-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatHomeEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'cat.size.height', 'cat.size.length', 'cat.size.width'],
|
||||||
|
searchableColumns: ['name'],
|
||||||
|
relations: ['cat'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
sortBy: [['cat.size.height', 'DESC']],
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatHomeEntity>(query, catHomeRepo, config)
|
||||||
|
const orderedHomes = [catHomes[1], catHomes[0]]
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual(orderedHomes)
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=cat.size.height:DESC')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on search on embedded entity', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'size.height', 'size.length', 'size.width'],
|
||||||
|
searchableColumns: ['size.height'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
search: '10',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual([cats[4]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=10')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on search term on embedded entity when other relations loaded', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'size.height', 'size.length', 'size.width'],
|
||||||
|
searchableColumns: ['size.height'],
|
||||||
|
relations: ['home', 'toys'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
search: '10',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
expect(result.meta.search).toStrictEqual('10')
|
||||||
|
|
||||||
|
const copyCat = clone(cats[4])
|
||||||
|
copyCat.home = null
|
||||||
|
copyCat.toys = []
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual([copyCat])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=10')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on search term on embedded entity on many-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatToyEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'cat.size.height', 'cat.size.length', 'cat.size.width'],
|
||||||
|
searchableColumns: ['cat.size.height'],
|
||||||
|
relations: ['cat'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
search: '30',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
|
||||||
|
expect(result.meta.search).toStrictEqual('30')
|
||||||
|
expect(result.data).toStrictEqual([catToys[3]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=30')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on search term on embedded entity on one-to-many relation', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'toys.size.height', 'toys.size.length', 'toys.size.width'],
|
||||||
|
searchableColumns: ['toys.size.height'],
|
||||||
|
relations: ['toys'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
search: '1',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
const toy0 = clone(catToys[0])
|
||||||
|
delete toy0.cat
|
||||||
|
|
||||||
|
const toy3 = clone(catToys[3])
|
||||||
|
delete toy3.cat
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual([
|
||||||
|
Object.assign(clone(cats[0]), { toys: [toy0] }),
|
||||||
|
Object.assign(clone(cats[1]), { toys: [toy3] }),
|
||||||
|
])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on search term on embedded entity on one-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatHomeEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'cat.size.height', 'cat.size.length', 'cat.size.width'],
|
||||||
|
searchableColumns: ['cat.size.height'],
|
||||||
|
relations: ['cat'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
search: '30',
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatHomeEntity>(query, catHomeRepo, config)
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual([catHomes[1]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&search=30')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on sort and search on embedded many-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatToyEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'cat.size.height', 'cat.size.length', 'cat.size.width'],
|
||||||
|
searchableColumns: ['cat.size.width'],
|
||||||
|
relations: ['cat'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
search: '1',
|
||||||
|
sortBy: [['cat.size.height', 'DESC']],
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
|
||||||
|
expect(result.meta.search).toStrictEqual('1')
|
||||||
|
expect(result.data).toStrictEqual([catToys[3], catToys[0], catToys[1], catToys[2]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=cat.size.height:DESC&search=1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on filter on embedded entity', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'size.height', 'size.length', 'size.width'],
|
||||||
|
searchableColumns: ['size.height'],
|
||||||
|
filterableColumns: {
|
||||||
|
'size.height': [FilterOperator.NOT],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
filter: {
|
||||||
|
'size.height': '$not:25',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual([cats[1], cats[3], cats[4]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.size.height=$not:25')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on filter on embedded entity when other relations loaded', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
sortableColumns: ['id', 'name', 'size.height', 'size.length', 'size.width'],
|
||||||
|
searchableColumns: ['size.height'],
|
||||||
|
filterableColumns: {
|
||||||
|
'size.height': [FilterOperator.NOT],
|
||||||
|
},
|
||||||
|
relations: ['home'],
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
filter: {
|
||||||
|
'size.height': '$not:25',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
const home = clone(catHomes[1])
|
||||||
|
delete home.cat
|
||||||
|
|
||||||
|
const copyCats = [
|
||||||
|
Object.assign(clone(cats[1]), { home: home }),
|
||||||
|
Object.assign(clone(cats[3]), { home: null }),
|
||||||
|
Object.assign(clone(cats[4]), { home: null }),
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(result.data).toStrictEqual(copyCats)
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.size.height=$not:25')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on filter on embedded on many-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatToyEntity> = {
|
||||||
|
relations: ['cat'],
|
||||||
|
sortableColumns: ['id', 'name'],
|
||||||
|
filterableColumns: {
|
||||||
|
'cat.size.height': [FilterOperator.NOT],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
filter: {
|
||||||
|
'cat.size.height': '$not:25',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatToyEntity>(query, catToyRepo, config)
|
||||||
|
|
||||||
|
expect(result.meta.filter).toStrictEqual({
|
||||||
|
'cat.size.height': '$not:25',
|
||||||
|
})
|
||||||
|
expect(result.data).toStrictEqual([catToys[3]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.cat.size.height=$not:25')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on filter on embedded on one-to-many relation', async () => {
|
||||||
|
const config: PaginateConfig<CatEntity> = {
|
||||||
|
relations: ['toys'],
|
||||||
|
sortableColumns: ['id', 'name'],
|
||||||
|
filterableColumns: {
|
||||||
|
'toys.size.height': [FilterOperator.EQ],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
filter: {
|
||||||
|
'toys.size.height': '$eq:1',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatEntity>(query, catRepo, config)
|
||||||
|
|
||||||
|
const cat2 = clone(cats[1])
|
||||||
|
const catToys3 = clone(catToys[3])
|
||||||
|
delete catToys3.cat
|
||||||
|
cat2.toys = [catToys3]
|
||||||
|
|
||||||
|
expect(result.meta.filter).toStrictEqual({
|
||||||
|
'toys.size.height': '$eq:1',
|
||||||
|
})
|
||||||
|
expect(result.data).toStrictEqual([cat2])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.toys.size.height=$eq:1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on filter on embedded on one-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatHomeEntity> = {
|
||||||
|
relations: ['cat'],
|
||||||
|
sortableColumns: ['id', 'name'],
|
||||||
|
filterableColumns: {
|
||||||
|
'cat.size.height': [FilterOperator.EQ],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
filter: {
|
||||||
|
'cat.size.height': '$eq:30',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatHomeEntity>(query, catHomeRepo, config)
|
||||||
|
|
||||||
|
expect(result.meta.filter).toStrictEqual({
|
||||||
|
'cat.size.height': '$eq:30',
|
||||||
|
})
|
||||||
|
expect(result.data).toStrictEqual([catHomes[1]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.cat.size.height=$eq:30')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on $in filter on embedded on one-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatHomeEntity> = {
|
||||||
|
relations: ['cat'],
|
||||||
|
sortableColumns: ['id', 'name'],
|
||||||
|
filterableColumns: {
|
||||||
|
'cat.size.height': [FilterOperator.IN],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
filter: {
|
||||||
|
'cat.size.height': '$in:10,30,35',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatHomeEntity>(query, catHomeRepo, config)
|
||||||
|
|
||||||
|
expect(result.meta.filter).toStrictEqual({
|
||||||
|
'cat.size.height': '$in:10,30,35',
|
||||||
|
})
|
||||||
|
expect(result.data).toStrictEqual([catHomes[1]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.cat.size.height=$in:10,30,35')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return result based on $btw filter on embedded on one-to-one relation', async () => {
|
||||||
|
const config: PaginateConfig<CatHomeEntity> = {
|
||||||
|
relations: ['cat'],
|
||||||
|
sortableColumns: ['id', 'name'],
|
||||||
|
filterableColumns: {
|
||||||
|
'cat.size.height': [FilterOperator.BTW],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const query: PaginateQuery = {
|
||||||
|
path: '',
|
||||||
|
filter: {
|
||||||
|
'cat.size.height': '$btw:18,33',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await paginate<CatHomeEntity>(query, catHomeRepo, config)
|
||||||
|
|
||||||
|
expect(result.meta.filter).toStrictEqual({
|
||||||
|
'cat.size.height': '$btw:18,33',
|
||||||
|
})
|
||||||
|
expect(result.data).toStrictEqual([catHomes[0], catHomes[1]])
|
||||||
|
expect(result.links.current).toBe('?page=1&limit=20&sortBy=id:ASC&filter.cat.size.height=$btw:18,33')
|
||||||
|
})
|
||||||
|
|
||||||
it('should return result based on where array and filter', async () => {
|
it('should return result based on where array and filter', async () => {
|
||||||
const config: PaginateConfig<CatEntity> = {
|
const config: PaginateConfig<CatEntity> = {
|
||||||
sortableColumns: ['id'],
|
sortableColumns: ['id'],
|
||||||
|
@ -245,7 +245,7 @@ export async function paginate<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const order of sortBy) {
|
for (const order of sortBy) {
|
||||||
if (order[0].split('.').length > 1) {
|
if (queryBuilder.expressionMap.mainAlias.metadata.hasRelationWithPropertyPath(order[0].split('.')[0])) {
|
||||||
queryBuilder.addOrderBy(`${queryBuilder.alias}_${order[0]}`, order[1], nullSort)
|
queryBuilder.addOrderBy(`${queryBuilder.alias}_${order[0]}`, order[1], nullSort)
|
||||||
} else {
|
} else {
|
||||||
queryBuilder.addOrderBy(`${queryBuilder.alias}.${order[0]}`, order[1], nullSort)
|
queryBuilder.addOrderBy(`${queryBuilder.alias}.${order[0]}`, order[1], nullSort)
|
||||||
@ -278,9 +278,14 @@ export async function paginate<T>(
|
|||||||
for (const column of searchBy) {
|
for (const column of searchBy) {
|
||||||
const propertyPath = (column as string).split('.')
|
const propertyPath = (column as string).split('.')
|
||||||
if (propertyPath.length > 1) {
|
if (propertyPath.length > 1) {
|
||||||
|
const alias = queryBuilder.expressionMap.mainAlias.metadata.hasRelationWithPropertyPath(
|
||||||
|
propertyPath[0]
|
||||||
|
)
|
||||||
|
? `${qb.alias}_${column}`
|
||||||
|
: `${qb.alias}.${column}`
|
||||||
const condition: WherePredicateOperator = {
|
const condition: WherePredicateOperator = {
|
||||||
operator: 'ilike',
|
operator: 'ilike',
|
||||||
parameters: [`${qb.alias}_${column}`, `:${column}`],
|
parameters: [alias, `:${column}`],
|
||||||
}
|
}
|
||||||
qb.orWhere(qb['createWhereConditionExpression'](condition), {
|
qb.orWhere(qb['createWhereConditionExpression'](condition), {
|
||||||
[column]: `%${query.search}%`,
|
[column]: `%${query.search}%`,
|
||||||
@ -308,19 +313,24 @@ export async function paginate<T>(
|
|||||||
) as WherePredicateOperator
|
) as WherePredicateOperator
|
||||||
let parameters = { [column]: filter[column].value }
|
let parameters = { [column]: filter[column].value }
|
||||||
// TODO: refactor below
|
// TODO: refactor below
|
||||||
|
const alias = queryBuilder.expressionMap.mainAlias.metadata.hasRelationWithPropertyPath(
|
||||||
|
propertyPath[0]
|
||||||
|
)
|
||||||
|
? `${qb.alias}_${column}`
|
||||||
|
: `${qb.alias}.${column}`
|
||||||
switch (condition.operator) {
|
switch (condition.operator) {
|
||||||
case 'between':
|
case 'between':
|
||||||
condition.parameters = [`${qb.alias}_${column}`, `:${column}_from`, `:${column}_to`]
|
condition.parameters = [alias, `:${column}_from`, `:${column}_to`]
|
||||||
parameters = {
|
parameters = {
|
||||||
[column + '_from']: filter[column].value[0],
|
[column + '_from']: filter[column].value[0],
|
||||||
[column + '_to']: filter[column].value[1],
|
[column + '_to']: filter[column].value[1],
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'in':
|
case 'in':
|
||||||
condition.parameters = [`${qb.alias}_${column}`, `:...${column}`]
|
condition.parameters = [alias, `:...${column}`]
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
condition.parameters = [`${qb.alias}_${column}`, `:${column}`]
|
condition.parameters = [alias, `:${column}`]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
qb.andWhere(qb['createWhereConditionExpression'](condition), parameters)
|
qb.andWhere(qb['createWhereConditionExpression'](condition), parameters)
|
||||||
|
Loading…
Reference in New Issue
Block a user