Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
BACKEND CHALLENGES
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Phạm Quang Bảo
BACKEND CHALLENGES
Commits
3be0edb2
Commit
3be0edb2
authored
May 16, 2026
by
Phạm Quang Bảo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add fillter classes for method get
parent
38e7d8fd
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
164 additions
and
65 deletions
+164
-65
package.json
code/package.json
+9
-1
index.ts
code/src/controllers/api/v1.0/classes/index.ts
+23
-5
swagger-output.json
code/src/docs/swagger/swagger-output.json
+59
-13
index.ts
code/src/index.ts
+1
-7
classes.ts
code/src/models/classes.ts
+2
-3
courses.ts
code/src/models/courses.ts
+2
-3
enrollments.ts
code/src/models/enrollments.ts
+2
-3
roles.ts
code/src/models/roles.ts
+2
-3
user_auth.ts
code/src/models/user_auth.ts
+2
-3
users.ts
code/src/models/users.ts
+2
-3
ClassesProvider.ts
code/src/providers/ClassesProvider.ts
+15
-10
database-gen.ts
code/src/scripts/database-gen.ts
+6
-0
schemas.ts
code/src/templates/swagger/classes/schemas.ts
+11
-11
config.ts
code/src/templates/swagger/config.ts
+22
-0
tsconfig.json
code/tsconfig.json
+6
-0
No files found.
code/package.json
View file @
3be0edb2
...
...
@@ -3,13 +3,21 @@
"version"
:
"1.0.0"
,
"description"
:
""
,
"author"
:
"PhamQuangBao"
,
"type"
:
"commonjs"
,
"main"
:
"./src/index.ts"
,
"scripts"
:
{
"dev"
:
"tsx watch ./src/index.ts"
,
"test"
:
"echo
\"
Error: no test specified
\"
&& exit 1"
,
"gen:db"
:
"sequelize-auto -h localhost -d challenge_db -u postgres -x 123456 -p 2550 --dialect postgres --lang ts -o ./src/models"
,
"gen:db"
:
"sequelize-auto -h localhost -d challenge_db -u postgres -x 123456 -p 2550 --dialect postgres --lang ts -o ./src/models
--caseProp s --useDefine
"
,
"gen:swagger"
:
"tsx src/scripts/swagger-gen.ts"
},
"imports"
:
{
"#models/*"
:
"./src/models/*"
,
"#controllers/*"
:
"./src/controllers/*"
,
"#services/*"
:
"./src/services/*"
,
"#providers/*"
:
"./src/providers/*"
,
"#docs/*"
:
"./src/docs/*"
},
"dependencies"
:
{
"express"
:
"^5.2.1"
,
"express-automatic-routes"
:
"^1.1.0"
,
...
...
code/src/controllers/api/v1.0/classes/index.ts
View file @
3be0edb2
...
...
@@ -11,8 +11,11 @@ export default (_express: Application) => {
* /api/v1.0/classes:
* get:
* tags: [Classes]
* summary: Lấy danh sách lớp học
* description: Trả về danh sách lớp học.
* parameters:
* - $ref: '#/components/parameters/filters'
* - $ref: '#/components/parameters/sort'
* - $ref: '#/components/parameters/page'
* - $ref: '#/components/parameters/pageSize'
* responses:
* 200:
* description: Trả về danh sách lớp học thành công
...
...
@@ -25,8 +28,23 @@ export default (_express: Application) => {
*/
get
:
{
handler
:
async
(
req
,
res
)
=>
{
const
classes
=
await
classesProvider
.
getAllClasses
();
try
{
// 1. Lấy các tham số từ Query String (được Swagger gửi lên)
const
{
filters
,
sort
,
page
,
pageSize
}
=
req
.
query
;
// 2. Truyền các tham số này vào hàm xử lý
const
classes
=
await
classesProvider
.
getAllClasses
({
filters
:
filters
as
string
,
sort
:
sort
as
string
,
page
:
page
?
parseInt
(
page
as
string
)
:
1
,
pageSize
:
pageSize
?
parseInt
(
pageSize
as
string
)
:
10
});
return
res
.
json
(
classes
);
}
catch
(
error
)
{
console
.
error
(
'Error getting classes:'
,
error
);
return
res
.
status
(
500
).
json
({
error
:
(
error
as
Error
).
message
});
}
}
}
};
...
...
code/src/docs/swagger/swagger-output.json
View file @
3be0edb2
...
...
@@ -34,6 +34,17 @@
"nullable"
:
true
,
"example"
:
"Lớp chuyên toán"
},
"course_id"
:
{
"type"
:
"string"
,
"format"
:
"uuid"
,
"nullable"
:
true
,
"example"
:
"7c1a4d9c-3a2b-4c58-9df4-8e2c2d9a3c10"
},
"status"
:
{
"type"
:
"string"
,
"nullable"
:
true
,
"example"
:
"active"
},
"created_at"
:
{
"type"
:
"string"
,
"format"
:
"date-time"
,
...
...
@@ -55,18 +66,41 @@
"format"
:
"uuid"
,
"nullable"
:
true
,
"example"
:
"2b4f6f8e-19f6-4c5d-93c2-4d7a7c3d1e11"
}
}
}
},
"course_id"
:
{
"type"
:
"string"
,
"format"
:
"uuid"
,
"nullable"
:
true
,
"example"
:
"7c1a4d9c-3a2b-4c58-9df4-8e2c2d9a3c10"
"parameters"
:
{
"filters"
:
{
"name"
:
"filters"
,
"in"
:
"query"
,
"schema"
:
{
"type"
:
"string"
}
},
"status"
:
{
"sort"
:
{
"name"
:
"sort"
,
"in"
:
"query"
,
"schema"
:
{
"type"
:
"string"
,
"nullable"
:
true
,
"example"
:
"active"
"enum"
:
[
"asc"
,
"desc"
]
}
},
"page"
:
{
"name"
:
"page"
,
"in"
:
"query"
,
"schema"
:
{
"type"
:
"integer"
}
},
"pageSize"
:
{
"name"
:
"pageSize"
,
"in"
:
"query"
,
"schema"
:
{
"type"
:
"integer"
}
}
}
...
...
@@ -77,8 +111,20 @@
"tags"
:
[
"Classes"
],
"summary"
:
"Lấy danh sách lớp học"
,
"description"
:
"Trả về danh sách lớp học."
,
"parameters"
:
[
{
"$ref"
:
"#/components/parameters/filters"
},
{
"$ref"
:
"#/components/parameters/sort"
},
{
"$ref"
:
"#/components/parameters/page"
},
{
"$ref"
:
"#/components/parameters/pageSize"
}
],
"responses"
:
{
"200"
:
{
"description"
:
"Trả về danh sách lớp học thành công"
,
...
...
code/src/index.ts
View file @
3be0edb2
...
...
@@ -12,13 +12,7 @@ _autoroutes(app, {
log
:
true
});
const
swaggerOptions
=
{
swaggerOptions
:
{
url
:
'/swagger.json'
,
},
};
app
.
use
(
'/swagger'
,
swaggerUi
.
serve
,
swaggerUi
.
setup
(
swaggerFile
,
swaggerOptions
));
app
.
use
(
'/swagger'
,
swaggerUi
.
serve
,
swaggerUi
.
setup
(
swaggerFile
));
app
.
listen
(
port
,
()
=>
{
console
.
log
(
`Example app listening on port
${
port
}
`
)
...
...
code/src/models/classes.ts
View file @
3be0edb2
...
...
@@ -50,7 +50,7 @@ export class classes extends Model<classesAttributes, classesCreationAttributes>
createCourse
!
:
Sequelize
.
BelongsToCreateAssociationMixin
<
courses
>
;
static
initModel
(
sequelize
:
Sequelize
.
Sequelize
):
typeof
classes
{
return
classes
.
init
(
{
return
sequelize
.
define
(
'classes'
,
{
id
:
{
type
:
DataTypes
.
UUID
,
allowNull
:
false
,
...
...
@@ -86,7 +86,6 @@ export class classes extends Model<classesAttributes, classesCreationAttributes>
allowNull
:
true
}
},
{
sequelize
,
tableName
:
'classes'
,
schema
:
'public'
,
timestamps
:
true
,
...
...
@@ -99,6 +98,6 @@ export class classes extends Model<classesAttributes, classesCreationAttributes>
]
},
]
});
})
as
typeof
classes
;
}
}
code/src/models/courses.ts
View file @
3be0edb2
...
...
@@ -38,7 +38,7 @@ export class courses extends Model<coursesAttributes, coursesCreationAttributes>
countClasses
!
:
Sequelize
.
HasManyCountAssociationsMixin
;
static
initModel
(
sequelize
:
Sequelize
.
Sequelize
):
typeof
courses
{
return
courses
.
init
(
{
return
sequelize
.
define
(
'courses'
,
{
id
:
{
type
:
DataTypes
.
UUID
,
allowNull
:
false
,
...
...
@@ -62,7 +62,6 @@ export class courses extends Model<coursesAttributes, coursesCreationAttributes>
allowNull
:
true
}
},
{
sequelize
,
tableName
:
'courses'
,
schema
:
'public'
,
timestamps
:
true
,
...
...
@@ -75,6 +74,6 @@ export class courses extends Model<coursesAttributes, coursesCreationAttributes>
]
},
]
});
})
as
typeof
courses
;
}
}
code/src/models/enrollments.ts
View file @
3be0edb2
...
...
@@ -35,7 +35,7 @@ export class enrollments extends Model<enrollmentsAttributes, enrollmentsCreatio
createUser
!
:
Sequelize
.
BelongsToCreateAssociationMixin
<
users
>
;
static
initModel
(
sequelize
:
Sequelize
.
Sequelize
):
typeof
enrollments
{
return
enrollments
.
init
(
{
return
sequelize
.
define
(
'enrollments'
,
{
id
:
{
type
:
DataTypes
.
UUID
,
allowNull
:
false
,
...
...
@@ -63,10 +63,9 @@ export class enrollments extends Model<enrollmentsAttributes, enrollmentsCreatio
allowNull
:
true
}
},
{
sequelize
,
tableName
:
'enrollments'
,
schema
:
'public'
,
timestamps
:
true
});
})
as
typeof
enrollments
;
}
}
code/src/models/roles.ts
View file @
3be0edb2
...
...
@@ -36,7 +36,7 @@ export class roles extends Model<rolesAttributes, rolesCreationAttributes> imple
countUsers
!
:
Sequelize
.
HasManyCountAssociationsMixin
;
static
initModel
(
sequelize
:
Sequelize
.
Sequelize
):
typeof
roles
{
return
roles
.
init
(
{
return
sequelize
.
define
(
'roles'
,
{
id
:
{
type
:
DataTypes
.
UUID
,
allowNull
:
false
,
...
...
@@ -56,7 +56,6 @@ export class roles extends Model<rolesAttributes, rolesCreationAttributes> imple
allowNull
:
true
}
},
{
sequelize
,
tableName
:
'roles'
,
schema
:
'public'
,
timestamps
:
true
,
...
...
@@ -69,6 +68,6 @@ export class roles extends Model<rolesAttributes, rolesCreationAttributes> imple
]
},
]
});
})
as
typeof
roles
;
}
}
code/src/models/user_auth.ts
View file @
3be0edb2
...
...
@@ -27,7 +27,7 @@ export class user_auth extends Model<user_authAttributes, user_authCreationAttri
createUser
!
:
Sequelize
.
BelongsToCreateAssociationMixin
<
users
>
;
static
initModel
(
sequelize
:
Sequelize
.
Sequelize
):
typeof
user_auth
{
return
user_auth
.
init
(
{
return
sequelize
.
define
(
'user_auth'
,
{
id
:
{
type
:
DataTypes
.
UUID
,
allowNull
:
false
,
...
...
@@ -47,7 +47,6 @@ export class user_auth extends Model<user_authAttributes, user_authCreationAttri
allowNull
:
true
}
},
{
sequelize
,
tableName
:
'user_auth'
,
schema
:
'public'
,
timestamps
:
true
,
...
...
@@ -60,6 +59,6 @@ export class user_auth extends Model<user_authAttributes, user_authCreationAttri
]
},
]
});
})
as
typeof
user_auth
;
}
}
code/src/models/users.ts
View file @
3be0edb2
...
...
@@ -61,7 +61,7 @@ export class users extends Model<usersAttributes, usersCreationAttributes> imple
countUser_auths
!
:
Sequelize
.
HasManyCountAssociationsMixin
;
static
initModel
(
sequelize
:
Sequelize
.
Sequelize
):
typeof
users
{
return
users
.
init
(
{
return
sequelize
.
define
(
'users'
,
{
id
:
{
type
:
DataTypes
.
UUID
,
allowNull
:
false
,
...
...
@@ -97,7 +97,6 @@ export class users extends Model<usersAttributes, usersCreationAttributes> imple
}
}
},
{
sequelize
,
tableName
:
'users'
,
schema
:
'public'
,
timestamps
:
true
,
...
...
@@ -110,6 +109,6 @@ export class users extends Model<usersAttributes, usersCreationAttributes> imple
]
},
]
});
})
as
typeof
users
;
}
}
code/src/providers/ClassesProvider.ts
View file @
3be0edb2
import
{
models
}
from
'#scripts/database-gen.js'
;
import
{
Op
}
from
'sequelize'
;
export
class
ClassesProvider
{
async
getAllClasses
()
{
try
{
const
data
=
await
models
.
classes
.
findAll
({
attributes
:
[
'id'
,
'name'
],
order
:
[[
'id'
,
'DESC'
]]
});
async
getAllClasses
(
params
:
{
filters
?:
string
,
sort
?:
string
,
page
?:
number
,
pageSize
?:
number
})
{
const
{
filters
,
sort
,
page
=
1
,
pageSize
=
10
}
=
params
;
const
offset
=
(
page
-
1
)
*
pageSize
;
return
data
;
}
catch
(
error
)
{
console
.
error
(
"Lỗi khi lấy danh sách classes:"
,
error
);
throw
error
;
const
where
:
any
=
{};
if
(
filters
)
{
where
.
name
=
{
[
Op
.
like
]:
`%
${
filters
}
%`
};
}
return
await
models
.
classes
.
findAndCountAll
({
where
,
order
:
sort
?
[[
'created_at'
,
sort
]]
:
[[
'created_at'
,
'DESC'
]],
limit
:
pageSize
,
offset
:
offset
});
}
async
getClassById
(
classId
:
number
)
{
...
...
code/src/scripts/database-gen.ts
View file @
3be0edb2
...
...
@@ -6,6 +6,12 @@ const sequelize = new Sequelize('challenge_db', 'postgres', '123456', {
port
:
2550
,
dialect
:
'postgres'
,
logging
:
false
,
define
:
{
underscored
:
true
,
timestamps
:
false
,
createdAt
:
'created_at'
,
updatedAt
:
'updated_at'
,
},
});
const
models
=
initModels
(
sequelize
);
...
...
code/src/templates/swagger/classes/schemas.ts
View file @
3be0edb2
...
...
@@ -27,6 +27,17 @@ const classSchemas = {
nullable
:
true
,
example
:
'Lớp chuyên toán'
,
},
course_id
:
{
type
:
'string'
,
format
:
'uuid'
,
nullable
:
true
,
example
:
'7c1a4d9c-3a2b-4c58-9df4-8e2c2d9a3c10'
,
},
status
:
{
type
:
'string'
,
nullable
:
true
,
example
:
'active'
,
},
created_at
:
{
type
:
'string'
,
format
:
'date-time'
,
...
...
@@ -49,17 +60,6 @@ const classSchemas = {
nullable
:
true
,
example
:
'2b4f6f8e-19f6-4c5d-93c2-4d7a7c3d1e11'
,
},
course_id
:
{
type
:
'string'
,
format
:
'uuid'
,
nullable
:
true
,
example
:
'7c1a4d9c-3a2b-4c58-9df4-8e2c2d9a3c10'
,
},
status
:
{
type
:
'string'
,
nullable
:
true
,
example
:
'active'
,
},
},
},
};
...
...
code/src/templates/swagger/config.ts
View file @
3be0edb2
...
...
@@ -14,6 +14,28 @@ const swaggerOptions: Options = {
schemas
:
{
...
classSchemas
,
},
parameters
:
{
filters
:
{
name
:
'filters'
,
in
:
'query'
,
schema
:
{
type
:
'string'
}
},
sort
:
{
name
:
'sort'
,
in
:
'query'
,
schema
:
{
type
:
'string'
,
enum
:
[
'asc'
,
'desc'
]
}
},
page
:
{
name
:
'page'
,
in
:
'query'
,
schema
:
{
type
:
'integer'
}
},
pageSize
:
{
name
:
'pageSize'
,
in
:
'query'
,
schema
:
{
type
:
'integer'
}
},
}
},
},
...
...
code/tsconfig.json
View file @
3be0edb2
...
...
@@ -37,9 +37,15 @@
"#models/*"
:
[
"./src/models/*"
],
"#controllers/*"
:
[
"./src/controllers/*"
],
"#interfaces/*"
:
[
"./src/interfaces/*"
],
"#docs/*"
:
[
"./src/docs/*"
],
"#*"
:
[
"./src/*"
]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment