Skip to content
This repository was archived by the owner on Sep 4, 2024. It is now read-only.

Commit c99bb59

Browse files
authored
feat(repository): add support for relational query (#6)
* feat(repository): add support for relational query Supported relations are `@hasOne`, `@hasMany`, `@hasMany through`, `@referencesMany` and `@belongsTo`. No Extra configuration needed to use them, inclusion requests are parsed from `include` filter itself. * fix: remove dependency from juggler datasource SequelizeDataSource no longer extends juggler.Datasource, and SequelizeCrudRepository implements it's own inclusion resolvers BREAKING CHANGE: `SequelizeRepository` is renamed to `SequelizeCrudRepository` * test(repository): add test cases for relations namely for fields, order and limit filter along with createAll, updateAll, delete and relations such as `@hasOne`, `@hasMany`, `@belongsTo` `@hasMany through`, `@referencesMany` and for INNER JOIN using `required: true` flag
1 parent 8e4f1e7 commit c99bb59

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+4463
-494
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,5 @@ typings/
6262

6363
# Cache used by TypeScript's incremental build
6464
*.tsbuildinfo
65+
66+
/src/sequelize/usercrud.sequelize.repository.base.ts

package-lock.json

Lines changed: 618 additions & 303 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "loopback4-sequelize",
33
"version": "1.0.0",
4-
"description": "Loopback 4 extension that provides Sequelize powered repository methods",
4+
"description": "Loopback 4 Extension That Provides Sequelize Crud Repository Compatible With Default Loopback Models.",
55
"keywords": [
66
"loopback-extension",
77
"loopback",
@@ -68,6 +68,8 @@
6868
"@types/node": "^14.18.26",
6969
"cz-conventional-changelog": "^3.3.0",
7070
"eslint": "^8.22.0",
71+
"pg": "^8.8.0",
72+
"pg-hstore": "^2.3.4",
7173
"semantic-release": "^19.0.5",
7274
"source-map-support": "^0.5.21",
7375
"sqlite3": "^5.1.2",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import {
2+
repository,
3+
} from '@loopback/repository';
4+
import {
5+
param,
6+
get,
7+
getModelSchemaRef,
8+
} from '@loopback/rest';
9+
import {
10+
Book,
11+
Category,
12+
} from '../models';
13+
import {BookRepository} from '../repositories';
14+
15+
export class BookCategoryController {
16+
constructor(
17+
@repository(BookRepository)
18+
public bookRepository: BookRepository,
19+
) { }
20+
21+
@get('/books/{id}/category', {
22+
responses: {
23+
'200': {
24+
description: 'Category belonging to Book',
25+
content: {
26+
'application/json': {
27+
schema: {type: 'array', items: getModelSchemaRef(Category)},
28+
},
29+
},
30+
},
31+
},
32+
})
33+
async getCategory(
34+
@param.path.number('id') id: typeof Book.prototype.id,
35+
): Promise<Category> {
36+
return this.bookRepository.category(id);
37+
}
38+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import {
2+
Count,
3+
CountSchema,
4+
Filter,
5+
FilterExcludingWhere,
6+
repository,
7+
Where,
8+
} from '@loopback/repository';
9+
import {
10+
del,
11+
get,
12+
getModelSchemaRef,
13+
param,
14+
patch,
15+
post,
16+
put,
17+
requestBody,
18+
response,
19+
} from '@loopback/rest';
20+
import {Book} from '../models';
21+
import {BookRepository} from '../repositories';
22+
import {TestControllerBase} from './test.controller.base';
23+
24+
export class BookController extends TestControllerBase {
25+
constructor(
26+
@repository(BookRepository)
27+
public bookRepository: BookRepository,
28+
) {
29+
super(bookRepository);
30+
}
31+
32+
@post('/books')
33+
@response(200, {
34+
description: 'Book model instance',
35+
content: {'application/json': {schema: getModelSchemaRef(Book)}},
36+
})
37+
async create(
38+
@requestBody({
39+
content: {
40+
'application/json': {
41+
schema: getModelSchemaRef(Book, {
42+
title: 'NewBook',
43+
exclude: ['id'],
44+
}),
45+
},
46+
},
47+
})
48+
book: Omit<Book, 'id'>,
49+
): Promise<Book> {
50+
return this.bookRepository.create(book);
51+
}
52+
53+
@post('/books-bulk')
54+
@response(200, {
55+
description: 'Book model instances',
56+
content: {
57+
'application/json': {
58+
schema: {
59+
type: 'array',
60+
items: getModelSchemaRef(Book),
61+
},
62+
},
63+
},
64+
})
65+
async createAll(
66+
@requestBody({
67+
content: {
68+
'application/json': {
69+
schema: {
70+
type: 'array',
71+
items: getModelSchemaRef(Book, {
72+
title: 'NewBook',
73+
exclude: ['id'],
74+
}),
75+
},
76+
},
77+
},
78+
})
79+
books: Array<Omit<Book, 'id'>>,
80+
): Promise<Book[]> {
81+
return this.bookRepository.createAll(books);
82+
}
83+
84+
@get('/books/count')
85+
@response(200, {
86+
description: 'Book model count',
87+
content: {'application/json': {schema: CountSchema}},
88+
})
89+
async count(@param.where(Book) where?: Where<Book>): Promise<Count> {
90+
return this.bookRepository.count(where);
91+
}
92+
93+
@get('/books')
94+
@response(200, {
95+
description: 'Array of Book model instances',
96+
content: {
97+
'application/json': {
98+
schema: {
99+
type: 'array',
100+
items: getModelSchemaRef(Book, {includeRelations: true}),
101+
},
102+
},
103+
},
104+
})
105+
async find(@param.filter(Book) filter?: Filter<Book>): Promise<Book[]> {
106+
return this.bookRepository.find(filter);
107+
}
108+
109+
@patch('/books')
110+
@response(200, {
111+
description: 'Book PATCH success count',
112+
content: {'application/json': {schema: CountSchema}},
113+
})
114+
async updateAll(
115+
@requestBody({
116+
content: {
117+
'application/json': {
118+
schema: getModelSchemaRef(Book, {partial: true}),
119+
},
120+
},
121+
})
122+
book: Book,
123+
@param.where(Book) where?: Where<Book>,
124+
): Promise<Count> {
125+
return this.bookRepository.updateAll(book, where);
126+
}
127+
128+
@get('/books/{id}')
129+
@response(200, {
130+
description: 'Book model instance',
131+
content: {
132+
'application/json': {
133+
schema: getModelSchemaRef(Book, {includeRelations: true}),
134+
},
135+
},
136+
})
137+
async findById(
138+
@param.path.number('id') id: number,
139+
@param.filter(Book, {exclude: 'where'}) filter?: FilterExcludingWhere<Book>,
140+
): Promise<Book> {
141+
return this.bookRepository.findById(id, filter);
142+
}
143+
144+
@patch('/books/{id}')
145+
@response(204, {
146+
description: 'Book PATCH success',
147+
})
148+
async updateById(
149+
@param.path.number('id') id: number,
150+
@requestBody({
151+
content: {
152+
'application/json': {
153+
schema: getModelSchemaRef(Book, {partial: true}),
154+
},
155+
},
156+
})
157+
book: Book,
158+
): Promise<void> {
159+
await this.bookRepository.updateById(id, book);
160+
}
161+
162+
@put('/books/{id}')
163+
@response(204, {
164+
description: 'Book PUT success',
165+
})
166+
async replaceById(
167+
@param.path.number('id') id: number,
168+
@requestBody() book: Book,
169+
): Promise<void> {
170+
await this.bookRepository.replaceById(id, book);
171+
}
172+
173+
@del('/books/{id}')
174+
@response(204, {
175+
description: 'Book DELETE success',
176+
})
177+
async deleteById(@param.path.number('id') id: number): Promise<void> {
178+
await this.bookRepository.deleteById(id);
179+
}
180+
181+
@get('/books/sync-sequelize-model')
182+
@response(200)
183+
async syncSequelizeModel(): Promise<void> {
184+
await this.beforeEach({syncAll: true});
185+
}
186+
}

0 commit comments

Comments
 (0)