course management and course data seed implementations
This commit is contained in:
parent
aae54e928a
commit
64c25699e9
|
|
@ -287,3 +287,93 @@ VALUES
|
|||
(16, 'The speaker is promising to arrive on time.', 2, TRUE),
|
||||
(16, 'The speaker might arrive late.', 3, FALSE),
|
||||
(16, 'The speaker has already arrived.', 4, FALSE);
|
||||
|
||||
-- ======================================================
|
||||
-- Course Management Seed Data
|
||||
-- ======================================================
|
||||
|
||||
-- Course Categories
|
||||
INSERT INTO course_categories (name, is_active, created_at) VALUES
|
||||
('Programming', TRUE, CURRENT_TIMESTAMP),
|
||||
('Data Science', TRUE, CURRENT_TIMESTAMP),
|
||||
('Web Development', TRUE, CURRENT_TIMESTAMP);
|
||||
|
||||
-- Courses
|
||||
INSERT INTO courses (category_id, title, description, is_active) VALUES
|
||||
(1, 'Python Programming Fundamentals', 'Learn Python from basics to advanced concepts', TRUE),
|
||||
(1, 'JavaScript for Beginners', 'Master JavaScript programming language', TRUE),
|
||||
(1, 'Advanced Java Development', 'Deep dive into Java enterprise development', TRUE),
|
||||
(2, 'Data Analysis with Python', 'Learn data manipulation and analysis using pandas', TRUE),
|
||||
(2, 'Machine Learning Basics', 'Introduction to machine learning algorithms', TRUE),
|
||||
(3, 'Full Stack Web Development', 'Complete guide to modern web development', TRUE),
|
||||
(3, 'React.js Masterclass', 'Build dynamic user interfaces with React', TRUE);
|
||||
|
||||
-- Programs
|
||||
INSERT INTO programs (course_id, title, description, thumbnail, display_order, is_active) VALUES
|
||||
(1, 'Python Basics', 'Fundamental concepts of Python programming', NULL, 1, TRUE),
|
||||
(1, 'Python Intermediate', 'Object-oriented programming and data structures', NULL, 2, TRUE),
|
||||
(1, 'Python Advanced', 'Advanced Python concepts and best practices', NULL, 3, TRUE),
|
||||
(2, 'JavaScript Fundamentals', 'Core JavaScript concepts and syntax', NULL, 1, TRUE),
|
||||
(2, 'DOM Manipulation', 'Working with the Document Object Model', NULL, 2, TRUE),
|
||||
(3, 'Java Core Concepts', 'Essential Java programming principles', NULL, 1, TRUE),
|
||||
(3, 'Spring Framework', 'Building enterprise applications with Spring', NULL, 2, TRUE);
|
||||
|
||||
-- Levels
|
||||
INSERT INTO levels (program_id, title, description, level_index, is_active) VALUES
|
||||
(1, 'Getting Started', 'Introduction to Python and basic syntax', 1, TRUE),
|
||||
(1, 'Data Types & Variables', 'Understanding Python data types and variables', 2, TRUE),
|
||||
(1, 'Control Flow', 'Conditional statements and loops', 3, TRUE),
|
||||
|
||||
(2, 'Functions', 'Writing and using functions in Python', 1, TRUE),
|
||||
(2, 'Lists & Dictionaries', 'Working with Python collections', 2, TRUE),
|
||||
(2, 'File Operations', 'Reading and writing files', 3, TRUE);
|
||||
|
||||
-- Modules
|
||||
INSERT INTO modules (level_id, title, content, display_order, is_active) VALUES
|
||||
(1, 'Installing Python', 'Setting up Python development environment', 1, TRUE),
|
||||
(1, 'Your First Python Program', 'Writing and running your first Python script', 2, TRUE),
|
||||
(2, 'Numbers and Strings', 'Working with numeric and text data types', 1, TRUE),
|
||||
(2, 'Variables and Assignment', 'Understanding variables and assignment operators', 2, TRUE),
|
||||
(3, 'Conditional Statements', 'Using if, elif, and else statements', 1, TRUE),
|
||||
(3, 'Loops in Python', 'For and while loops with examples', 2, TRUE);
|
||||
|
||||
-- Module Videos
|
||||
INSERT INTO module_videos (
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
visibility,
|
||||
is_active
|
||||
) VALUES
|
||||
(1, 'Python Installation Guide', 'Installing Python', 'https://example.com/python-install.mp4', 900, '1080p', 'public', TRUE),
|
||||
(2, 'Hello World in Python', 'First Python program', 'https://example.com/python-hello.mp4', 1200, '1080p', 'public', TRUE),
|
||||
(3, 'Numbers and Math', 'Numeric types in Python', 'https://example.com/python-numbers.mp4', 1500, '720p', 'public', TRUE);
|
||||
|
||||
-- Practices
|
||||
INSERT INTO practices (
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
persona,
|
||||
is_active
|
||||
) VALUES
|
||||
('LEVEL', 1, 'Python Basics Assessment', 'Test Python basics', 'beginner', TRUE),
|
||||
('LEVEL', 2, 'Data Types Practice', 'Practice Python data types', 'beginner', TRUE),
|
||||
('MODULE', 3, 'Control Flow Quiz', 'Assess control flow knowledge', 'beginner', TRUE);
|
||||
|
||||
-- Practice Questions
|
||||
INSERT INTO practice_questions (
|
||||
practice_id,
|
||||
question,
|
||||
sample_answer,
|
||||
tips,
|
||||
type
|
||||
) VALUES
|
||||
(1, 'What is the correct way to print "Hello World" in Python?', 'print("Hello World")', 'Use print()', 'MCQ'),
|
||||
(1, 'Which is a valid Python variable name?', 'my_variable', 'Variables cannot start with numbers', 'MCQ'),
|
||||
(2, 'How do you convert "123" to an integer?', 'int("123")', 'Use int()', 'MCQ'),
|
||||
(3, 'How many times does range(3) loop run?', '3', 'Starts from zero', 'MCQ');
|
||||
|
|
|
|||
|
|
@ -78,3 +78,59 @@ SELECT setval(
|
|||
COALESCE((SELECT MAX(id) FROM reported_issues), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- course_categories.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('course_categories', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM course_categories), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- courses.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('courses', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM courses), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- programs.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('programs', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM programs), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- levels.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('levels', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM levels), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- modules.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('modules', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM modules), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- module_videos.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('module_videos', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM module_videos), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- practices.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('practices', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM practices), 1),
|
||||
true
|
||||
);
|
||||
|
||||
-- practice_questions.id (BIGSERIAL)
|
||||
SELECT setval(
|
||||
pg_get_serial_sequence('practice_questions', 'id'),
|
||||
COALESCE((SELECT MAX(id) FROM practice_questions), 1),
|
||||
true
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,50 +3,37 @@ INSERT INTO course_categories (
|
|||
name,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- name
|
||||
$2 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at;
|
||||
VALUES ($1, COALESCE($2, true))
|
||||
RETURNING *;
|
||||
|
||||
|
||||
-- name: GetCourseCategoryByID :one
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at
|
||||
SELECT *
|
||||
FROM course_categories
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListActiveCourseCategories :many
|
||||
|
||||
-- name: GetAllCourseCategories :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at
|
||||
FROM course_categories
|
||||
WHERE is_active = TRUE
|
||||
ORDER BY created_at DESC;
|
||||
ORDER BY created_at DESC
|
||||
LIMIT sqlc.narg('limit')::INT
|
||||
OFFSET sqlc.narg('offset')::INT;
|
||||
|
||||
-- name: UpdateCourseCategory :one
|
||||
|
||||
-- name: UpdateCourseCategory :exec
|
||||
UPDATE course_categories
|
||||
SET
|
||||
name = $2,
|
||||
is_active = $3
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at;
|
||||
name = COALESCE($1, name),
|
||||
is_active = COALESCE($2, is_active)
|
||||
WHERE id = $3;
|
||||
|
||||
-- name: DeactivateCourseCategory :exec
|
||||
UPDATE course_categories
|
||||
SET is_active = FALSE
|
||||
|
||||
-- name: DeleteCourseCategory :exec
|
||||
DELETE FROM course_categories
|
||||
WHERE id = $1;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,14 +7,37 @@ INSERT INTO programs (
|
|||
display_order,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- course_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4, -- thumbnail
|
||||
$5, -- display_order
|
||||
$6 -- is_active
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, COALESCE($5, 0), COALESCE($6, true))
|
||||
RETURNING *;
|
||||
|
||||
|
||||
-- name: GetProgramsByCourse :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
course_id,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
display_order,
|
||||
is_active
|
||||
FROM programs
|
||||
WHERE course_id = $1
|
||||
ORDER BY display_order ASC;
|
||||
|
||||
-- name: UpdateProgramPartial :exec
|
||||
UPDATE programs
|
||||
SET
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
thumbnail = COALESCE($3, thumbnail),
|
||||
display_order = COALESCE($4, display_order),
|
||||
is_active = COALESCE($5, is_active)
|
||||
WHERE id = $6;
|
||||
|
||||
-- name: DeleteProgram :one
|
||||
DELETE FROM programs
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
course_id,
|
||||
|
|
@ -24,6 +47,7 @@ RETURNING
|
|||
display_order,
|
||||
is_active;
|
||||
|
||||
|
||||
-- name: GetProgramByID :one
|
||||
SELECT
|
||||
id,
|
||||
|
|
@ -63,7 +87,7 @@ FROM programs
|
|||
WHERE is_active = TRUE
|
||||
ORDER BY display_order ASC;
|
||||
|
||||
-- name: UpdateProgram :one
|
||||
-- name: UpdateProgramFull :one
|
||||
UPDATE programs
|
||||
SET
|
||||
course_id = $2,
|
||||
|
|
@ -82,6 +106,7 @@ RETURNING
|
|||
display_order,
|
||||
is_active;
|
||||
|
||||
|
||||
-- name: DeactivateProgram :exec
|
||||
UPDATE programs
|
||||
SET is_active = FALSE
|
||||
|
|
|
|||
|
|
@ -5,31 +5,19 @@ INSERT INTO courses (
|
|||
description,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- category_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active;
|
||||
VALUES ($1, $2, $3, COALESCE($4, true))
|
||||
RETURNING *;
|
||||
|
||||
|
||||
-- name: GetCourseByID :one
|
||||
SELECT
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active
|
||||
SELECT *
|
||||
FROM courses
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListCoursesByCategory :many
|
||||
|
||||
-- name: GetCoursesByCategory :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
|
|
@ -37,37 +25,20 @@ SELECT
|
|||
is_active
|
||||
FROM courses
|
||||
WHERE category_id = $1
|
||||
AND is_active = TRUE
|
||||
ORDER BY id DESC;
|
||||
ORDER BY id DESC
|
||||
LIMIT sqlc.narg('limit')::INT
|
||||
OFFSET sqlc.narg('offset')::INT;
|
||||
|
||||
-- name: ListActiveCourses :many
|
||||
SELECT
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active
|
||||
FROM courses
|
||||
WHERE is_active = TRUE
|
||||
ORDER BY id DESC;
|
||||
|
||||
-- name: UpdateCourse :one
|
||||
-- name: UpdateCourse :exec
|
||||
UPDATE courses
|
||||
SET
|
||||
category_id = $2,
|
||||
title = $3,
|
||||
description = $4,
|
||||
is_active = $5
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active;
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
is_active = COALESCE($3, is_active)
|
||||
WHERE id = $4;
|
||||
|
||||
-- name: DeactivateCourse :exec
|
||||
UPDATE courses
|
||||
SET is_active = FALSE
|
||||
|
||||
-- name: DeleteCourse :exec
|
||||
DELETE FROM courses
|
||||
WHERE id = $1;
|
||||
|
||||
|
|
|
|||
16
db/query/learning_tree.sql
Normal file
16
db/query/learning_tree.sql
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
-- name: GetFullLearningTree :many
|
||||
SELECT
|
||||
c.id AS course_id,
|
||||
c.title AS course_title,
|
||||
p.id AS program_id,
|
||||
p.title AS program_title,
|
||||
l.id AS level_id,
|
||||
l.title AS level_title,
|
||||
m.id AS module_id,
|
||||
m.title AS module_title
|
||||
FROM courses c
|
||||
JOIN programs p ON p.course_id = c.id
|
||||
JOIN levels l ON l.program_id = p.id
|
||||
LEFT JOIN modules m ON m.level_id = l.id
|
||||
WHERE c.is_active = true
|
||||
ORDER BY p.display_order, l.level_index, m.display_order;
|
||||
|
|
@ -6,34 +6,13 @@ INSERT INTO modules (
|
|||
display_order,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- level_id
|
||||
$2, -- title
|
||||
$3, -- content
|
||||
$4, -- display_order
|
||||
$5 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
content,
|
||||
display_order,
|
||||
is_active;
|
||||
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, true))
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetModuleByID :one
|
||||
SELECT
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
content,
|
||||
display_order,
|
||||
is_active
|
||||
FROM modules
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListModulesByLevel :many
|
||||
-- name: GetModulesByLevel :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
|
|
@ -42,26 +21,19 @@ SELECT
|
|||
is_active
|
||||
FROM modules
|
||||
WHERE level_id = $1
|
||||
AND is_active = TRUE
|
||||
ORDER BY display_order ASC, id ASC;
|
||||
ORDER BY display_order ASC;
|
||||
|
||||
-- name: UpdateModule :one
|
||||
|
||||
-- name: UpdateModule :exec
|
||||
UPDATE modules
|
||||
SET
|
||||
title = $2,
|
||||
content = $3,
|
||||
display_order = $4,
|
||||
is_active = $5
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
content,
|
||||
display_order,
|
||||
is_active;
|
||||
title = COALESCE($1, title),
|
||||
content = COALESCE($2, content),
|
||||
display_order = COALESCE($3, display_order),
|
||||
is_active = COALESCE($4, is_active)
|
||||
WHERE id = $5;
|
||||
|
||||
-- name: DeactivateModule :exec
|
||||
UPDATE modules
|
||||
SET is_active = FALSE
|
||||
|
||||
-- name: DeleteModule :exec
|
||||
DELETE FROM modules
|
||||
WHERE id = $1;
|
||||
|
|
|
|||
|
|
@ -6,136 +6,50 @@ INSERT INTO module_videos (
|
|||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
visibility,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- module_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4, -- video_url
|
||||
$5, -- duration
|
||||
$6, -- resolution
|
||||
|
||||
$7, -- is_published
|
||||
$8, -- publish_date
|
||||
$9, -- visibility
|
||||
|
||||
$10, -- instructor_id
|
||||
$11, -- thumbnail
|
||||
$12 -- is_active
|
||||
$1, $2, $3, $4, $5, $6,
|
||||
$7, $8, $9,
|
||||
COALESCE($10, true)
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active;
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetModuleVideoByID :one
|
||||
SELECT
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active
|
||||
FROM module_videos
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListPublishedVideosByModule :many
|
||||
SELECT
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail
|
||||
FROM module_videos
|
||||
WHERE module_id = $1
|
||||
AND is_active = TRUE
|
||||
AND is_published = TRUE
|
||||
ORDER BY publish_date ASC, id ASC;
|
||||
|
||||
-- name: ListAllVideosByModule :many
|
||||
SELECT
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active
|
||||
FROM module_videos
|
||||
WHERE module_id = $1
|
||||
ORDER BY id ASC;
|
||||
|
||||
-- name: UpdateModuleVideo :one
|
||||
-- name: PublishModuleVideo :exec
|
||||
UPDATE module_videos
|
||||
SET
|
||||
title = $2,
|
||||
description = $3,
|
||||
video_url = $4,
|
||||
duration = $5,
|
||||
resolution = $6,
|
||||
|
||||
is_published = $7,
|
||||
publish_date = $8,
|
||||
visibility = $9,
|
||||
|
||||
instructor_id = $10,
|
||||
thumbnail = $11,
|
||||
is_active = $12
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active;
|
||||
|
||||
-- name: DeactivateModuleVideo :exec
|
||||
UPDATE module_videos
|
||||
SET is_active = FALSE
|
||||
is_published = true,
|
||||
publish_date = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
|
||||
|
||||
-- name: GetPublishedVideosByModule :many
|
||||
SELECT *
|
||||
FROM module_videos
|
||||
WHERE module_id = $1
|
||||
AND is_published = true
|
||||
AND is_active = true
|
||||
ORDER BY publish_date ASC;
|
||||
|
||||
|
||||
-- name: UpdateModuleVideo :exec
|
||||
UPDATE module_videos
|
||||
SET
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
video_url = COALESCE($3, video_url),
|
||||
duration = COALESCE($4, duration),
|
||||
resolution = COALESCE($5, resolution),
|
||||
visibility = COALESCE($6, visibility),
|
||||
thumbnail = COALESCE($7, thumbnail),
|
||||
is_active = COALESCE($8, is_active)
|
||||
WHERE id = $9;
|
||||
|
||||
|
||||
-- name: DeleteModuleVideo :exec
|
||||
DELETE FROM module_videos
|
||||
WHERE id = $1;
|
||||
|
|
|
|||
|
|
@ -8,71 +8,26 @@ INSERT INTO practice_questions (
|
|||
tips,
|
||||
type
|
||||
)
|
||||
VALUES (
|
||||
$1, -- practice_id
|
||||
$2, -- question
|
||||
$3, -- question_voice_prompt
|
||||
$4, -- sample_answer_voice_prompt
|
||||
$5, -- sample_answer
|
||||
$6, -- tips
|
||||
$7 -- type (MCQ, TRUE_FALSE, SHORT)
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type;
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetPracticeQuestionByID :one
|
||||
SELECT
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type
|
||||
FROM practice_questions
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListPracticeQuestions :many
|
||||
SELECT
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type
|
||||
-- name: GetQuestionsByPractice :many
|
||||
SELECT *
|
||||
FROM practice_questions
|
||||
WHERE practice_id = $1
|
||||
ORDER BY id ASC;
|
||||
|
||||
-- name: UpdatePracticeQuestion :one
|
||||
|
||||
-- name: UpdatePracticeQuestion :exec
|
||||
UPDATE practice_questions
|
||||
SET
|
||||
question = $2,
|
||||
question_voice_prompt = $3,
|
||||
sample_answer_voice_prompt = $4,
|
||||
sample_answer = $5,
|
||||
tips = $6,
|
||||
type = $7
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type;
|
||||
question = COALESCE($1, question),
|
||||
sample_answer = COALESCE($2, sample_answer),
|
||||
tips = COALESCE($3, tips),
|
||||
type = COALESCE($4, type)
|
||||
WHERE id = $5;
|
||||
|
||||
|
||||
-- name: DeletePracticeQuestion :exec
|
||||
DELETE FROM practice_questions
|
||||
|
|
|
|||
|
|
@ -8,74 +8,29 @@ INSERT INTO practices (
|
|||
persona,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- owner_type (LEVEL | MODULE)
|
||||
$2, -- owner_id
|
||||
$3, -- title
|
||||
$4, -- description
|
||||
$5, -- banner_image
|
||||
$6, -- persona
|
||||
$7 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active;
|
||||
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, true))
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetPracticeByID :one
|
||||
SELECT
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active
|
||||
FROM practices
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListPracticesByOwner :many
|
||||
SELECT
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active
|
||||
-- name: GetPracticesByOwner :many
|
||||
SELECT *
|
||||
FROM practices
|
||||
WHERE owner_type = $1
|
||||
AND owner_id = $2
|
||||
AND is_active = TRUE
|
||||
ORDER BY id ASC;
|
||||
AND is_active = true;
|
||||
|
||||
-- name: UpdatePractice :one
|
||||
|
||||
-- name: UpdatePractice :exec
|
||||
UPDATE practices
|
||||
SET
|
||||
title = $2,
|
||||
description = $3,
|
||||
banner_image = $4,
|
||||
persona = $5,
|
||||
is_active = $6
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active;
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
banner_image = COALESCE($3, banner_image),
|
||||
persona = COALESCE($4, persona),
|
||||
is_active = COALESCE($5, is_active)
|
||||
WHERE id = $6;
|
||||
|
||||
-- name: DeactivatePractice :exec
|
||||
UPDATE practices
|
||||
SET is_active = FALSE
|
||||
|
||||
-- name: DeletePractice :exec
|
||||
DELETE FROM practices
|
||||
WHERE id = $1;
|
||||
|
|
|
|||
|
|
@ -4,48 +4,15 @@ INSERT INTO levels (
|
|||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- program_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4, -- level_index
|
||||
$5, -- number_of_modules
|
||||
$6, -- number_of_practices
|
||||
$7, -- number_of_videos
|
||||
$8 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active;
|
||||
VALUES ($1, $2, $3, $4, COALESCE($5, true))
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetLevelByID :one
|
||||
SELECT
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active
|
||||
FROM levels
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: ListLevelsByProgram :many
|
||||
-- name: GetLevelsByProgram :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
|
|
@ -57,32 +24,37 @@ SELECT
|
|||
is_active
|
||||
FROM levels
|
||||
WHERE program_id = $1
|
||||
AND is_active = TRUE
|
||||
ORDER BY level_index ASC;
|
||||
|
||||
-- name: UpdateLevel :one
|
||||
|
||||
-- name: UpdateLevel :exec
|
||||
UPDATE levels
|
||||
SET
|
||||
title = $2,
|
||||
description = $3,
|
||||
level_index = $4,
|
||||
number_of_modules = $5,
|
||||
number_of_practices = $6,
|
||||
number_of_videos = $7,
|
||||
is_active = $8
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active;
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
level_index = COALESCE($3, level_index),
|
||||
is_active = COALESCE($4, is_active)
|
||||
WHERE id = $5;
|
||||
|
||||
-- name: DeactivateLevel :exec
|
||||
|
||||
-- name: IncrementLevelModuleCount :exec
|
||||
UPDATE levels
|
||||
SET is_active = FALSE
|
||||
SET number_of_modules = number_of_modules + 1
|
||||
WHERE id = $1;
|
||||
|
||||
|
||||
-- name: IncrementLevelPracticeCount :exec
|
||||
UPDATE levels
|
||||
SET number_of_practices = number_of_practices + 1
|
||||
WHERE id = $1;
|
||||
|
||||
|
||||
-- name: IncrementLevelVideoCount :exec
|
||||
UPDATE levels
|
||||
SET number_of_videos = number_of_videos + 1
|
||||
WHERE id = $1;
|
||||
|
||||
|
||||
-- name: DeleteLevel :exec
|
||||
DELETE FROM levels
|
||||
WHERE id = $1;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ services:
|
|||
image: dpage/pgadmin4:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "5050:80"
|
||||
- "5051:80"
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: admin@local.dev
|
||||
PGADMIN_DEFAULT_PASSWORD: admin
|
||||
|
|
|
|||
2546
docs/docs.go
2546
docs/docs.go
File diff suppressed because it is too large
Load Diff
2546
docs/swagger.json
2546
docs/swagger.json
File diff suppressed because it is too large
Load Diff
1919
docs/swagger.yaml
1919
docs/swagger.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -7,6 +7,8 @@ package dbgen
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const CreateCourseCategory = `-- name: CreateCourseCategory :one
|
||||
|
|
@ -14,24 +16,17 @@ INSERT INTO course_categories (
|
|||
name,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- name
|
||||
$2 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at
|
||||
VALUES ($1, COALESCE($2, true))
|
||||
RETURNING id, name, is_active, created_at
|
||||
`
|
||||
|
||||
type CreateCourseCategoryParams struct {
|
||||
Name string `json:"name"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Column2 interface{} `json:"column_2"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateCourseCategory(ctx context.Context, arg CreateCourseCategoryParams) (CourseCategory, error) {
|
||||
row := q.db.QueryRow(ctx, CreateCourseCategory, arg.Name, arg.IsActive)
|
||||
row := q.db.QueryRow(ctx, CreateCourseCategory, arg.Name, arg.Column2)
|
||||
var i CourseCategory
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
|
|
@ -42,24 +37,71 @@ func (q *Queries) CreateCourseCategory(ctx context.Context, arg CreateCourseCate
|
|||
return i, err
|
||||
}
|
||||
|
||||
const DeactivateCourseCategory = `-- name: DeactivateCourseCategory :exec
|
||||
UPDATE course_categories
|
||||
SET is_active = FALSE
|
||||
const DeleteCourseCategory = `-- name: DeleteCourseCategory :exec
|
||||
DELETE FROM course_categories
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeactivateCourseCategory(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeactivateCourseCategory, id)
|
||||
func (q *Queries) DeleteCourseCategory(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeleteCourseCategory, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const GetCourseCategoryByID = `-- name: GetCourseCategoryByID :one
|
||||
const GetAllCourseCategories = `-- name: GetAllCourseCategories :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at
|
||||
FROM course_categories
|
||||
ORDER BY created_at DESC
|
||||
LIMIT $2::INT
|
||||
OFFSET $1::INT
|
||||
`
|
||||
|
||||
type GetAllCourseCategoriesParams struct {
|
||||
Offset pgtype.Int4 `json:"offset"`
|
||||
Limit pgtype.Int4 `json:"limit"`
|
||||
}
|
||||
|
||||
type GetAllCourseCategoriesRow struct {
|
||||
TotalCount int64 `json:"total_count"`
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllCourseCategories(ctx context.Context, arg GetAllCourseCategoriesParams) ([]GetAllCourseCategoriesRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllCourseCategories, arg.Offset, arg.Limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetAllCourseCategoriesRow
|
||||
for rows.Next() {
|
||||
var i GetAllCourseCategoriesRow
|
||||
if err := rows.Scan(
|
||||
&i.TotalCount,
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetCourseCategoryByID = `-- name: GetCourseCategoryByID :one
|
||||
SELECT id, name, is_active, created_at
|
||||
FROM course_categories
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
|
|
@ -75,69 +117,21 @@ func (q *Queries) GetCourseCategoryByID(ctx context.Context, id int64) (CourseCa
|
|||
return i, err
|
||||
}
|
||||
|
||||
const ListActiveCourseCategories = `-- name: ListActiveCourseCategories :many
|
||||
SELECT
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at
|
||||
FROM course_categories
|
||||
WHERE is_active = TRUE
|
||||
ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
func (q *Queries) ListActiveCourseCategories(ctx context.Context) ([]CourseCategory, error) {
|
||||
rows, err := q.db.Query(ctx, ListActiveCourseCategories)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []CourseCategory
|
||||
for rows.Next() {
|
||||
var i CourseCategory
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateCourseCategory = `-- name: UpdateCourseCategory :one
|
||||
const UpdateCourseCategory = `-- name: UpdateCourseCategory :exec
|
||||
UPDATE course_categories
|
||||
SET
|
||||
name = $2,
|
||||
is_active = $3
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
name,
|
||||
is_active,
|
||||
created_at
|
||||
name = COALESCE($1, name),
|
||||
is_active = COALESCE($2, is_active)
|
||||
WHERE id = $3
|
||||
`
|
||||
|
||||
type UpdateCourseCategoryParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateCourseCategory(ctx context.Context, arg UpdateCourseCategoryParams) (CourseCategory, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateCourseCategory, arg.ID, arg.Name, arg.IsActive)
|
||||
var i CourseCategory
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Name,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
)
|
||||
return i, err
|
||||
func (q *Queries) UpdateCourseCategory(ctx context.Context, arg UpdateCourseCategoryParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateCourseCategory, arg.Name, arg.IsActive, arg.ID)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,22 +20,8 @@ INSERT INTO programs (
|
|||
display_order,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- course_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4, -- thumbnail
|
||||
$5, -- display_order
|
||||
$6 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
course_id,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
display_order,
|
||||
is_active
|
||||
VALUES ($1, $2, $3, $4, COALESCE($5, 0), COALESCE($6, true))
|
||||
RETURNING id, course_id, title, description, thumbnail, display_order, is_active
|
||||
`
|
||||
|
||||
type CreateProgramParams struct {
|
||||
|
|
@ -43,8 +29,8 @@ type CreateProgramParams struct {
|
|||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Column5 interface{} `json:"column_5"`
|
||||
Column6 interface{} `json:"column_6"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateProgram(ctx context.Context, arg CreateProgramParams) (Program, error) {
|
||||
|
|
@ -53,8 +39,8 @@ func (q *Queries) CreateProgram(ctx context.Context, arg CreateProgramParams) (P
|
|||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Thumbnail,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.Column5,
|
||||
arg.Column6,
|
||||
)
|
||||
var i Program
|
||||
err := row.Scan(
|
||||
|
|
@ -80,6 +66,34 @@ func (q *Queries) DeactivateProgram(ctx context.Context, id int64) error {
|
|||
return err
|
||||
}
|
||||
|
||||
const DeleteProgram = `-- name: DeleteProgram :one
|
||||
DELETE FROM programs
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
course_id,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
display_order,
|
||||
is_active
|
||||
`
|
||||
|
||||
func (q *Queries) DeleteProgram(ctx context.Context, id int64) (Program, error) {
|
||||
row := q.db.QueryRow(ctx, DeleteProgram, id)
|
||||
var i Program
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CourseID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Thumbnail,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetProgramByID = `-- name: GetProgramByID :one
|
||||
SELECT
|
||||
id,
|
||||
|
|
@ -108,6 +122,61 @@ func (q *Queries) GetProgramByID(ctx context.Context, id int64) (Program, error)
|
|||
return i, err
|
||||
}
|
||||
|
||||
const GetProgramsByCourse = `-- name: GetProgramsByCourse :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
course_id,
|
||||
title,
|
||||
description,
|
||||
thumbnail,
|
||||
display_order,
|
||||
is_active
|
||||
FROM programs
|
||||
WHERE course_id = $1
|
||||
ORDER BY display_order ASC
|
||||
`
|
||||
|
||||
type GetProgramsByCourseRow struct {
|
||||
TotalCount int64 `json:"total_count"`
|
||||
ID int64 `json:"id"`
|
||||
CourseID int64 `json:"course_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetProgramsByCourse(ctx context.Context, courseID int64) ([]GetProgramsByCourseRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetProgramsByCourse, courseID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetProgramsByCourseRow
|
||||
for rows.Next() {
|
||||
var i GetProgramsByCourseRow
|
||||
if err := rows.Scan(
|
||||
&i.TotalCount,
|
||||
&i.ID,
|
||||
&i.CourseID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.Thumbnail,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const ListActivePrograms = `-- name: ListActivePrograms :many
|
||||
SELECT
|
||||
id,
|
||||
|
|
@ -193,7 +262,7 @@ func (q *Queries) ListProgramsByCourse(ctx context.Context, courseID int64) ([]P
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateProgram = `-- name: UpdateProgram :one
|
||||
const UpdateProgramFull = `-- name: UpdateProgramFull :one
|
||||
UPDATE programs
|
||||
SET
|
||||
course_id = $2,
|
||||
|
|
@ -213,7 +282,7 @@ RETURNING
|
|||
is_active
|
||||
`
|
||||
|
||||
type UpdateProgramParams struct {
|
||||
type UpdateProgramFullParams struct {
|
||||
ID int64 `json:"id"`
|
||||
CourseID int64 `json:"course_id"`
|
||||
Title string `json:"title"`
|
||||
|
|
@ -223,8 +292,8 @@ type UpdateProgramParams struct {
|
|||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateProgram(ctx context.Context, arg UpdateProgramParams) (Program, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateProgram,
|
||||
func (q *Queries) UpdateProgramFull(ctx context.Context, arg UpdateProgramFullParams) (Program, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateProgramFull,
|
||||
arg.ID,
|
||||
arg.CourseID,
|
||||
arg.Title,
|
||||
|
|
@ -245,3 +314,35 @@ func (q *Queries) UpdateProgram(ctx context.Context, arg UpdateProgramParams) (P
|
|||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateProgramPartial = `-- name: UpdateProgramPartial :exec
|
||||
UPDATE programs
|
||||
SET
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
thumbnail = COALESCE($3, thumbnail),
|
||||
display_order = COALESCE($4, display_order),
|
||||
is_active = COALESCE($5, is_active)
|
||||
WHERE id = $6
|
||||
`
|
||||
|
||||
type UpdateProgramPartialParams struct {
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateProgramPartial(ctx context.Context, arg UpdateProgramPartialParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateProgramPartial,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.Thumbnail,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,25 +18,15 @@ INSERT INTO courses (
|
|||
description,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- category_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active
|
||||
VALUES ($1, $2, $3, COALESCE($4, true))
|
||||
RETURNING id, category_id, title, description, is_active
|
||||
`
|
||||
|
||||
type CreateCourseParams struct {
|
||||
CategoryID int64 `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Column4 interface{} `json:"column_4"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateCourse(ctx context.Context, arg CreateCourseParams) (Course, error) {
|
||||
|
|
@ -44,7 +34,7 @@ func (q *Queries) CreateCourse(ctx context.Context, arg CreateCourseParams) (Cou
|
|||
arg.CategoryID,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.IsActive,
|
||||
arg.Column4,
|
||||
)
|
||||
var i Course
|
||||
err := row.Scan(
|
||||
|
|
@ -57,24 +47,18 @@ func (q *Queries) CreateCourse(ctx context.Context, arg CreateCourseParams) (Cou
|
|||
return i, err
|
||||
}
|
||||
|
||||
const DeactivateCourse = `-- name: DeactivateCourse :exec
|
||||
UPDATE courses
|
||||
SET is_active = FALSE
|
||||
const DeleteCourse = `-- name: DeleteCourse :exec
|
||||
DELETE FROM courses
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeactivateCourse(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeactivateCourse, id)
|
||||
func (q *Queries) DeleteCourse(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeleteCourse, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const GetCourseByID = `-- name: GetCourseByID :one
|
||||
SELECT
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active
|
||||
SELECT id, category_id, title, description, is_active
|
||||
FROM courses
|
||||
WHERE id = $1
|
||||
`
|
||||
|
|
@ -92,46 +76,9 @@ func (q *Queries) GetCourseByID(ctx context.Context, id int64) (Course, error) {
|
|||
return i, err
|
||||
}
|
||||
|
||||
const ListActiveCourses = `-- name: ListActiveCourses :many
|
||||
SELECT
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active
|
||||
FROM courses
|
||||
WHERE is_active = TRUE
|
||||
ORDER BY id DESC
|
||||
`
|
||||
|
||||
func (q *Queries) ListActiveCourses(ctx context.Context) ([]Course, error) {
|
||||
rows, err := q.db.Query(ctx, ListActiveCourses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Course
|
||||
for rows.Next() {
|
||||
var i Course
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.CategoryID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.IsActive,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const ListCoursesByCategory = `-- name: ListCoursesByCategory :many
|
||||
const GetCoursesByCategory = `-- name: GetCoursesByCategory :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
|
|
@ -139,20 +86,37 @@ SELECT
|
|||
is_active
|
||||
FROM courses
|
||||
WHERE category_id = $1
|
||||
AND is_active = TRUE
|
||||
ORDER BY id DESC
|
||||
LIMIT $3::INT
|
||||
OFFSET $2::INT
|
||||
`
|
||||
|
||||
func (q *Queries) ListCoursesByCategory(ctx context.Context, categoryID int64) ([]Course, error) {
|
||||
rows, err := q.db.Query(ctx, ListCoursesByCategory, categoryID)
|
||||
type GetCoursesByCategoryParams struct {
|
||||
CategoryID int64 `json:"category_id"`
|
||||
Offset pgtype.Int4 `json:"offset"`
|
||||
Limit pgtype.Int4 `json:"limit"`
|
||||
}
|
||||
|
||||
type GetCoursesByCategoryRow struct {
|
||||
TotalCount int64 `json:"total_count"`
|
||||
ID int64 `json:"id"`
|
||||
CategoryID int64 `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetCoursesByCategory(ctx context.Context, arg GetCoursesByCategoryParams) ([]GetCoursesByCategoryRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetCoursesByCategory, arg.CategoryID, arg.Offset, arg.Limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Course
|
||||
var items []GetCoursesByCategoryRow
|
||||
for rows.Next() {
|
||||
var i Course
|
||||
var i GetCoursesByCategoryRow
|
||||
if err := rows.Scan(
|
||||
&i.TotalCount,
|
||||
&i.ID,
|
||||
&i.CategoryID,
|
||||
&i.Title,
|
||||
|
|
@ -169,45 +133,28 @@ func (q *Queries) ListCoursesByCategory(ctx context.Context, categoryID int64) (
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateCourse = `-- name: UpdateCourse :one
|
||||
const UpdateCourse = `-- name: UpdateCourse :exec
|
||||
UPDATE courses
|
||||
SET
|
||||
category_id = $2,
|
||||
title = $3,
|
||||
description = $4,
|
||||
is_active = $5
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
category_id,
|
||||
title,
|
||||
description,
|
||||
is_active
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
is_active = COALESCE($3, is_active)
|
||||
WHERE id = $4
|
||||
`
|
||||
|
||||
type UpdateCourseParams struct {
|
||||
ID int64 `json:"id"`
|
||||
CategoryID int64 `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateCourse(ctx context.Context, arg UpdateCourseParams) (Course, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateCourse,
|
||||
arg.ID,
|
||||
arg.CategoryID,
|
||||
func (q *Queries) UpdateCourse(ctx context.Context, arg UpdateCourseParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateCourse,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i Course
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CategoryID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
70
gen/db/learning_tree.sql.go
Normal file
70
gen/db/learning_tree.sql.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.30.0
|
||||
// source: learning_tree.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const GetFullLearningTree = `-- name: GetFullLearningTree :many
|
||||
SELECT
|
||||
c.id AS course_id,
|
||||
c.title AS course_title,
|
||||
p.id AS program_id,
|
||||
p.title AS program_title,
|
||||
l.id AS level_id,
|
||||
l.title AS level_title,
|
||||
m.id AS module_id,
|
||||
m.title AS module_title
|
||||
FROM courses c
|
||||
JOIN programs p ON p.course_id = c.id
|
||||
JOIN levels l ON l.program_id = p.id
|
||||
LEFT JOIN modules m ON m.level_id = l.id
|
||||
WHERE c.is_active = true
|
||||
ORDER BY p.display_order, l.level_index, m.display_order
|
||||
`
|
||||
|
||||
type GetFullLearningTreeRow struct {
|
||||
CourseID int64 `json:"course_id"`
|
||||
CourseTitle string `json:"course_title"`
|
||||
ProgramID int64 `json:"program_id"`
|
||||
ProgramTitle string `json:"program_title"`
|
||||
LevelID int64 `json:"level_id"`
|
||||
LevelTitle string `json:"level_title"`
|
||||
ModuleID pgtype.Int8 `json:"module_id"`
|
||||
ModuleTitle pgtype.Text `json:"module_title"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetFullLearningTree(ctx context.Context) ([]GetFullLearningTreeRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetFullLearningTree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []GetFullLearningTreeRow
|
||||
for rows.Next() {
|
||||
var i GetFullLearningTreeRow
|
||||
if err := rows.Scan(
|
||||
&i.CourseID,
|
||||
&i.CourseTitle,
|
||||
&i.ProgramID,
|
||||
&i.ProgramTitle,
|
||||
&i.LevelID,
|
||||
&i.LevelTitle,
|
||||
&i.ModuleID,
|
||||
&i.ModuleTitle,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
|
@ -19,28 +19,16 @@ INSERT INTO modules (
|
|||
display_order,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- level_id
|
||||
$2, -- title
|
||||
$3, -- content
|
||||
$4, -- display_order
|
||||
$5 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
content,
|
||||
display_order,
|
||||
is_active
|
||||
VALUES ($1, $2, $3, COALESCE($4, 0), COALESCE($5, true))
|
||||
RETURNING id, level_id, title, content, display_order, is_active
|
||||
`
|
||||
|
||||
type CreateModuleParams struct {
|
||||
LevelID int64 `json:"level_id"`
|
||||
Title string `json:"title"`
|
||||
Content pgtype.Text `json:"content"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Column4 interface{} `json:"column_4"`
|
||||
Column5 interface{} `json:"column_5"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Module, error) {
|
||||
|
|
@ -48,8 +36,8 @@ func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Mod
|
|||
arg.LevelID,
|
||||
arg.Title,
|
||||
arg.Content,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.Column4,
|
||||
arg.Column5,
|
||||
)
|
||||
var i Module
|
||||
err := row.Scan(
|
||||
|
|
@ -63,45 +51,19 @@ func (q *Queries) CreateModule(ctx context.Context, arg CreateModuleParams) (Mod
|
|||
return i, err
|
||||
}
|
||||
|
||||
const DeactivateModule = `-- name: DeactivateModule :exec
|
||||
UPDATE modules
|
||||
SET is_active = FALSE
|
||||
const DeleteModule = `-- name: DeleteModule :exec
|
||||
DELETE FROM modules
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeactivateModule(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeactivateModule, id)
|
||||
func (q *Queries) DeleteModule(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeleteModule, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const GetModuleByID = `-- name: GetModuleByID :one
|
||||
SELECT
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
content,
|
||||
display_order,
|
||||
is_active
|
||||
FROM modules
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetModuleByID(ctx context.Context, id int64) (Module, error) {
|
||||
row := q.db.QueryRow(ctx, GetModuleByID, id)
|
||||
var i Module
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.LevelID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const ListModulesByLevel = `-- name: ListModulesByLevel :many
|
||||
const GetModulesByLevel = `-- name: GetModulesByLevel :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
|
|
@ -110,20 +72,30 @@ SELECT
|
|||
is_active
|
||||
FROM modules
|
||||
WHERE level_id = $1
|
||||
AND is_active = TRUE
|
||||
ORDER BY display_order ASC, id ASC
|
||||
ORDER BY display_order ASC
|
||||
`
|
||||
|
||||
func (q *Queries) ListModulesByLevel(ctx context.Context, levelID int64) ([]Module, error) {
|
||||
rows, err := q.db.Query(ctx, ListModulesByLevel, levelID)
|
||||
type GetModulesByLevelRow struct {
|
||||
TotalCount int64 `json:"total_count"`
|
||||
ID int64 `json:"id"`
|
||||
LevelID int64 `json:"level_id"`
|
||||
Title string `json:"title"`
|
||||
Content pgtype.Text `json:"content"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetModulesByLevel(ctx context.Context, levelID int64) ([]GetModulesByLevelRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetModulesByLevel, levelID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Module
|
||||
var items []GetModulesByLevelRow
|
||||
for rows.Next() {
|
||||
var i Module
|
||||
var i GetModulesByLevelRow
|
||||
if err := rows.Scan(
|
||||
&i.TotalCount,
|
||||
&i.ID,
|
||||
&i.LevelID,
|
||||
&i.Title,
|
||||
|
|
@ -141,47 +113,31 @@ func (q *Queries) ListModulesByLevel(ctx context.Context, levelID int64) ([]Modu
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateModule = `-- name: UpdateModule :one
|
||||
const UpdateModule = `-- name: UpdateModule :exec
|
||||
UPDATE modules
|
||||
SET
|
||||
title = $2,
|
||||
content = $3,
|
||||
display_order = $4,
|
||||
is_active = $5
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
level_id,
|
||||
title,
|
||||
content,
|
||||
display_order,
|
||||
is_active
|
||||
title = COALESCE($1, title),
|
||||
content = COALESCE($2, content),
|
||||
display_order = COALESCE($3, display_order),
|
||||
is_active = COALESCE($4, is_active)
|
||||
WHERE id = $5
|
||||
`
|
||||
|
||||
type UpdateModuleParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content pgtype.Text `json:"content"`
|
||||
DisplayOrder int32 `json:"display_order"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateModule(ctx context.Context, arg UpdateModuleParams) (Module, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateModule,
|
||||
arg.ID,
|
||||
func (q *Queries) UpdateModule(ctx context.Context, arg UpdateModuleParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateModule,
|
||||
arg.Title,
|
||||
arg.Content,
|
||||
arg.DisplayOrder,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i Module
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.LevelID,
|
||||
&i.Title,
|
||||
&i.Content,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,45 +19,17 @@ INSERT INTO module_videos (
|
|||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
visibility,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- module_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4, -- video_url
|
||||
$5, -- duration
|
||||
$6, -- resolution
|
||||
|
||||
$7, -- is_published
|
||||
$8, -- publish_date
|
||||
$9, -- visibility
|
||||
|
||||
$10, -- instructor_id
|
||||
$11, -- thumbnail
|
||||
$12 -- is_active
|
||||
$1, $2, $3, $4, $5, $6,
|
||||
$7, $8, $9,
|
||||
COALESCE($10, true)
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active
|
||||
RETURNING id, module_id, title, description, video_url, duration, resolution, is_published, publish_date, visibility, instructor_id, thumbnail, is_active
|
||||
`
|
||||
|
||||
type CreateModuleVideoParams struct {
|
||||
|
|
@ -67,12 +39,10 @@ type CreateModuleVideoParams struct {
|
|||
VideoUrl string `json:"video_url"`
|
||||
Duration int32 `json:"duration"`
|
||||
Resolution pgtype.Text `json:"resolution"`
|
||||
IsPublished bool `json:"is_published"`
|
||||
PublishDate pgtype.Timestamptz `json:"publish_date"`
|
||||
Visibility pgtype.Text `json:"visibility"`
|
||||
InstructorID pgtype.Text `json:"instructor_id"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Visibility pgtype.Text `json:"visibility"`
|
||||
Column10 interface{} `json:"column_10"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateModuleVideo(ctx context.Context, arg CreateModuleVideoParams) (ModuleVideo, error) {
|
||||
|
|
@ -83,12 +53,10 @@ func (q *Queries) CreateModuleVideo(ctx context.Context, arg CreateModuleVideoPa
|
|||
arg.VideoUrl,
|
||||
arg.Duration,
|
||||
arg.Resolution,
|
||||
arg.IsPublished,
|
||||
arg.PublishDate,
|
||||
arg.Visibility,
|
||||
arg.InstructorID,
|
||||
arg.Thumbnail,
|
||||
arg.IsActive,
|
||||
arg.Visibility,
|
||||
arg.Column10,
|
||||
)
|
||||
var i ModuleVideo
|
||||
err := row.Scan(
|
||||
|
|
@ -109,79 +77,27 @@ func (q *Queries) CreateModuleVideo(ctx context.Context, arg CreateModuleVideoPa
|
|||
return i, err
|
||||
}
|
||||
|
||||
const DeactivateModuleVideo = `-- name: DeactivateModuleVideo :exec
|
||||
UPDATE module_videos
|
||||
SET is_active = FALSE
|
||||
const DeleteModuleVideo = `-- name: DeleteModuleVideo :exec
|
||||
DELETE FROM module_videos
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeactivateModuleVideo(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeactivateModuleVideo, id)
|
||||
func (q *Queries) DeleteModuleVideo(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeleteModuleVideo, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const GetModuleVideoByID = `-- name: GetModuleVideoByID :one
|
||||
SELECT
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active
|
||||
FROM module_videos
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetModuleVideoByID(ctx context.Context, id int64) (ModuleVideo, error) {
|
||||
row := q.db.QueryRow(ctx, GetModuleVideoByID, id)
|
||||
var i ModuleVideo
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.VideoUrl,
|
||||
&i.Duration,
|
||||
&i.Resolution,
|
||||
&i.IsPublished,
|
||||
&i.PublishDate,
|
||||
&i.Visibility,
|
||||
&i.InstructorID,
|
||||
&i.Thumbnail,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const ListAllVideosByModule = `-- name: ListAllVideosByModule :many
|
||||
SELECT
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active
|
||||
const GetPublishedVideosByModule = `-- name: GetPublishedVideosByModule :many
|
||||
SELECT id, module_id, title, description, video_url, duration, resolution, is_published, publish_date, visibility, instructor_id, thumbnail, is_active
|
||||
FROM module_videos
|
||||
WHERE module_id = $1
|
||||
ORDER BY id ASC
|
||||
AND is_published = true
|
||||
AND is_active = true
|
||||
ORDER BY publish_date ASC
|
||||
`
|
||||
|
||||
func (q *Queries) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]ModuleVideo, error) {
|
||||
rows, err := q.db.Query(ctx, ListAllVideosByModule, moduleID)
|
||||
func (q *Queries) GetPublishedVideosByModule(ctx context.Context, moduleID int64) ([]ModuleVideo, error) {
|
||||
rows, err := q.db.Query(ctx, GetPublishedVideosByModule, moduleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -214,150 +130,56 @@ func (q *Queries) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const ListPublishedVideosByModule = `-- name: ListPublishedVideosByModule :many
|
||||
SELECT
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail
|
||||
FROM module_videos
|
||||
WHERE module_id = $1
|
||||
AND is_active = TRUE
|
||||
AND is_published = TRUE
|
||||
ORDER BY publish_date ASC, id ASC
|
||||
`
|
||||
|
||||
type ListPublishedVideosByModuleRow struct {
|
||||
ID int64 `json:"id"`
|
||||
ModuleID int64 `json:"module_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
VideoUrl string `json:"video_url"`
|
||||
Duration int32 `json:"duration"`
|
||||
Resolution pgtype.Text `json:"resolution"`
|
||||
PublishDate pgtype.Timestamptz `json:"publish_date"`
|
||||
Visibility pgtype.Text `json:"visibility"`
|
||||
InstructorID pgtype.Text `json:"instructor_id"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]ListPublishedVideosByModuleRow, error) {
|
||||
rows, err := q.db.Query(ctx, ListPublishedVideosByModule, moduleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListPublishedVideosByModuleRow
|
||||
for rows.Next() {
|
||||
var i ListPublishedVideosByModuleRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.VideoUrl,
|
||||
&i.Duration,
|
||||
&i.Resolution,
|
||||
&i.PublishDate,
|
||||
&i.Visibility,
|
||||
&i.InstructorID,
|
||||
&i.Thumbnail,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateModuleVideo = `-- name: UpdateModuleVideo :one
|
||||
const PublishModuleVideo = `-- name: PublishModuleVideo :exec
|
||||
UPDATE module_videos
|
||||
SET
|
||||
title = $2,
|
||||
description = $3,
|
||||
video_url = $4,
|
||||
duration = $5,
|
||||
resolution = $6,
|
||||
|
||||
is_published = $7,
|
||||
publish_date = $8,
|
||||
visibility = $9,
|
||||
|
||||
instructor_id = $10,
|
||||
thumbnail = $11,
|
||||
is_active = $12
|
||||
is_published = true,
|
||||
publish_date = CURRENT_TIMESTAMP
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
module_id,
|
||||
title,
|
||||
description,
|
||||
video_url,
|
||||
duration,
|
||||
resolution,
|
||||
is_published,
|
||||
publish_date,
|
||||
visibility,
|
||||
instructor_id,
|
||||
thumbnail,
|
||||
is_active
|
||||
`
|
||||
|
||||
func (q *Queries) PublishModuleVideo(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, PublishModuleVideo, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateModuleVideo = `-- name: UpdateModuleVideo :exec
|
||||
UPDATE module_videos
|
||||
SET
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
video_url = COALESCE($3, video_url),
|
||||
duration = COALESCE($4, duration),
|
||||
resolution = COALESCE($5, resolution),
|
||||
visibility = COALESCE($6, visibility),
|
||||
thumbnail = COALESCE($7, thumbnail),
|
||||
is_active = COALESCE($8, is_active)
|
||||
WHERE id = $9
|
||||
`
|
||||
|
||||
type UpdateModuleVideoParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
VideoUrl string `json:"video_url"`
|
||||
Duration int32 `json:"duration"`
|
||||
Resolution pgtype.Text `json:"resolution"`
|
||||
IsPublished bool `json:"is_published"`
|
||||
PublishDate pgtype.Timestamptz `json:"publish_date"`
|
||||
Visibility pgtype.Text `json:"visibility"`
|
||||
InstructorID pgtype.Text `json:"instructor_id"`
|
||||
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateModuleVideo(ctx context.Context, arg UpdateModuleVideoParams) (ModuleVideo, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateModuleVideo,
|
||||
arg.ID,
|
||||
func (q *Queries) UpdateModuleVideo(ctx context.Context, arg UpdateModuleVideoParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateModuleVideo,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.VideoUrl,
|
||||
arg.Duration,
|
||||
arg.Resolution,
|
||||
arg.IsPublished,
|
||||
arg.PublishDate,
|
||||
arg.Visibility,
|
||||
arg.InstructorID,
|
||||
arg.Thumbnail,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i ModuleVideo
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.VideoUrl,
|
||||
&i.Duration,
|
||||
&i.Resolution,
|
||||
&i.IsPublished,
|
||||
&i.PublishDate,
|
||||
&i.Visibility,
|
||||
&i.InstructorID,
|
||||
&i.Thumbnail,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,24 +21,8 @@ INSERT INTO practice_questions (
|
|||
tips,
|
||||
type
|
||||
)
|
||||
VALUES (
|
||||
$1, -- practice_id
|
||||
$2, -- question
|
||||
$3, -- question_voice_prompt
|
||||
$4, -- sample_answer_voice_prompt
|
||||
$5, -- sample_answer
|
||||
$6, -- tips
|
||||
$7 -- type (MCQ, TRUE_FALSE, SHORT)
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING id, practice_id, question, question_voice_prompt, sample_answer_voice_prompt, sample_answer, tips, type
|
||||
`
|
||||
|
||||
type CreatePracticeQuestionParams struct {
|
||||
|
|
@ -85,53 +69,15 @@ func (q *Queries) DeletePracticeQuestion(ctx context.Context, id int64) error {
|
|||
return err
|
||||
}
|
||||
|
||||
const GetPracticeQuestionByID = `-- name: GetPracticeQuestionByID :one
|
||||
SELECT
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type
|
||||
FROM practice_questions
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetPracticeQuestionByID(ctx context.Context, id int64) (PracticeQuestion, error) {
|
||||
row := q.db.QueryRow(ctx, GetPracticeQuestionByID, id)
|
||||
var i PracticeQuestion
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.PracticeID,
|
||||
&i.Question,
|
||||
&i.QuestionVoicePrompt,
|
||||
&i.SampleAnswerVoicePrompt,
|
||||
&i.SampleAnswer,
|
||||
&i.Tips,
|
||||
&i.Type,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const ListPracticeQuestions = `-- name: ListPracticeQuestions :many
|
||||
SELECT
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type
|
||||
const GetQuestionsByPractice = `-- name: GetQuestionsByPractice :many
|
||||
SELECT id, practice_id, question, question_voice_prompt, sample_answer_voice_prompt, sample_answer, tips, type
|
||||
FROM practice_questions
|
||||
WHERE practice_id = $1
|
||||
ORDER BY id ASC
|
||||
`
|
||||
|
||||
func (q *Queries) ListPracticeQuestions(ctx context.Context, practiceID int64) ([]PracticeQuestion, error) {
|
||||
rows, err := q.db.Query(ctx, ListPracticeQuestions, practiceID)
|
||||
func (q *Queries) GetQuestionsByPractice(ctx context.Context, practiceID int64) ([]PracticeQuestion, error) {
|
||||
rows, err := q.db.Query(ctx, GetQuestionsByPractice, practiceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -159,57 +105,31 @@ func (q *Queries) ListPracticeQuestions(ctx context.Context, practiceID int64) (
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const UpdatePracticeQuestion = `-- name: UpdatePracticeQuestion :one
|
||||
const UpdatePracticeQuestion = `-- name: UpdatePracticeQuestion :exec
|
||||
UPDATE practice_questions
|
||||
SET
|
||||
question = $2,
|
||||
question_voice_prompt = $3,
|
||||
sample_answer_voice_prompt = $4,
|
||||
sample_answer = $5,
|
||||
tips = $6,
|
||||
type = $7
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
practice_id,
|
||||
question,
|
||||
question_voice_prompt,
|
||||
sample_answer_voice_prompt,
|
||||
sample_answer,
|
||||
tips,
|
||||
type
|
||||
question = COALESCE($1, question),
|
||||
sample_answer = COALESCE($2, sample_answer),
|
||||
tips = COALESCE($3, tips),
|
||||
type = COALESCE($4, type)
|
||||
WHERE id = $5
|
||||
`
|
||||
|
||||
type UpdatePracticeQuestionParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Question string `json:"question"`
|
||||
QuestionVoicePrompt pgtype.Text `json:"question_voice_prompt"`
|
||||
SampleAnswerVoicePrompt pgtype.Text `json:"sample_answer_voice_prompt"`
|
||||
SampleAnswer pgtype.Text `json:"sample_answer"`
|
||||
Tips pgtype.Text `json:"tips"`
|
||||
Type string `json:"type"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePracticeQuestion(ctx context.Context, arg UpdatePracticeQuestionParams) (PracticeQuestion, error) {
|
||||
row := q.db.QueryRow(ctx, UpdatePracticeQuestion,
|
||||
arg.ID,
|
||||
func (q *Queries) UpdatePracticeQuestion(ctx context.Context, arg UpdatePracticeQuestionParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdatePracticeQuestion,
|
||||
arg.Question,
|
||||
arg.QuestionVoicePrompt,
|
||||
arg.SampleAnswerVoicePrompt,
|
||||
arg.SampleAnswer,
|
||||
arg.Tips,
|
||||
arg.Type,
|
||||
arg.ID,
|
||||
)
|
||||
var i PracticeQuestion
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.PracticeID,
|
||||
&i.Question,
|
||||
&i.QuestionVoicePrompt,
|
||||
&i.SampleAnswerVoicePrompt,
|
||||
&i.SampleAnswer,
|
||||
&i.Tips,
|
||||
&i.Type,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,24 +21,8 @@ INSERT INTO practices (
|
|||
persona,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- owner_type (LEVEL | MODULE)
|
||||
$2, -- owner_id
|
||||
$3, -- title
|
||||
$4, -- description
|
||||
$5, -- banner_image
|
||||
$6, -- persona
|
||||
$7 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active
|
||||
VALUES ($1, $2, $3, $4, $5, $6, COALESCE($7, true))
|
||||
RETURNING id, owner_type, owner_id, title, description, banner_image, persona, is_active
|
||||
`
|
||||
|
||||
type CreatePracticeParams struct {
|
||||
|
|
@ -48,7 +32,7 @@ type CreatePracticeParams struct {
|
|||
Description pgtype.Text `json:"description"`
|
||||
BannerImage pgtype.Text `json:"banner_image"`
|
||||
Persona pgtype.Text `json:"persona"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Column7 interface{} `json:"column_7"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreatePractice(ctx context.Context, arg CreatePracticeParams) (Practice, error) {
|
||||
|
|
@ -59,7 +43,7 @@ func (q *Queries) CreatePractice(ctx context.Context, arg CreatePracticeParams)
|
|||
arg.Description,
|
||||
arg.BannerImage,
|
||||
arg.Persona,
|
||||
arg.IsActive,
|
||||
arg.Column7,
|
||||
)
|
||||
var i Practice
|
||||
err := row.Scan(
|
||||
|
|
@ -75,71 +59,31 @@ func (q *Queries) CreatePractice(ctx context.Context, arg CreatePracticeParams)
|
|||
return i, err
|
||||
}
|
||||
|
||||
const DeactivatePractice = `-- name: DeactivatePractice :exec
|
||||
UPDATE practices
|
||||
SET is_active = FALSE
|
||||
const DeletePractice = `-- name: DeletePractice :exec
|
||||
DELETE FROM practices
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeactivatePractice(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeactivatePractice, id)
|
||||
func (q *Queries) DeletePractice(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeletePractice, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const GetPracticeByID = `-- name: GetPracticeByID :one
|
||||
SELECT
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active
|
||||
FROM practices
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetPracticeByID(ctx context.Context, id int64) (Practice, error) {
|
||||
row := q.db.QueryRow(ctx, GetPracticeByID, id)
|
||||
var i Practice
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.OwnerType,
|
||||
&i.OwnerID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.BannerImage,
|
||||
&i.Persona,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const ListPracticesByOwner = `-- name: ListPracticesByOwner :many
|
||||
SELECT
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active
|
||||
const GetPracticesByOwner = `-- name: GetPracticesByOwner :many
|
||||
SELECT id, owner_type, owner_id, title, description, banner_image, persona, is_active
|
||||
FROM practices
|
||||
WHERE owner_type = $1
|
||||
AND owner_id = $2
|
||||
AND is_active = TRUE
|
||||
ORDER BY id ASC
|
||||
AND is_active = true
|
||||
`
|
||||
|
||||
type ListPracticesByOwnerParams struct {
|
||||
type GetPracticesByOwnerParams struct {
|
||||
OwnerType string `json:"owner_type"`
|
||||
OwnerID int64 `json:"owner_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListPracticesByOwner(ctx context.Context, arg ListPracticesByOwnerParams) ([]Practice, error) {
|
||||
rows, err := q.db.Query(ctx, ListPracticesByOwner, arg.OwnerType, arg.OwnerID)
|
||||
func (q *Queries) GetPracticesByOwner(ctx context.Context, arg GetPracticesByOwnerParams) ([]Practice, error) {
|
||||
rows, err := q.db.Query(ctx, GetPracticesByOwner, arg.OwnerType, arg.OwnerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -167,54 +111,34 @@ func (q *Queries) ListPracticesByOwner(ctx context.Context, arg ListPracticesByO
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const UpdatePractice = `-- name: UpdatePractice :one
|
||||
const UpdatePractice = `-- name: UpdatePractice :exec
|
||||
UPDATE practices
|
||||
SET
|
||||
title = $2,
|
||||
description = $3,
|
||||
banner_image = $4,
|
||||
persona = $5,
|
||||
is_active = $6
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
owner_type,
|
||||
owner_id,
|
||||
title,
|
||||
description,
|
||||
banner_image,
|
||||
persona,
|
||||
is_active
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
banner_image = COALESCE($3, banner_image),
|
||||
persona = COALESCE($4, persona),
|
||||
is_active = COALESCE($5, is_active)
|
||||
WHERE id = $6
|
||||
`
|
||||
|
||||
type UpdatePracticeParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
BannerImage pgtype.Text `json:"banner_image"`
|
||||
Persona pgtype.Text `json:"persona"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePractice(ctx context.Context, arg UpdatePracticeParams) (Practice, error) {
|
||||
row := q.db.QueryRow(ctx, UpdatePractice,
|
||||
arg.ID,
|
||||
func (q *Queries) UpdatePractice(ctx context.Context, arg UpdatePracticeParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdatePractice,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.BannerImage,
|
||||
arg.Persona,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i Practice
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.OwnerType,
|
||||
&i.OwnerID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.BannerImage,
|
||||
&i.Persona,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,31 +17,10 @@ INSERT INTO levels (
|
|||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active
|
||||
)
|
||||
VALUES (
|
||||
$1, -- program_id
|
||||
$2, -- title
|
||||
$3, -- description
|
||||
$4, -- level_index
|
||||
$5, -- number_of_modules
|
||||
$6, -- number_of_practices
|
||||
$7, -- number_of_videos
|
||||
$8 -- is_active
|
||||
)
|
||||
RETURNING
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active
|
||||
VALUES ($1, $2, $3, $4, COALESCE($5, true))
|
||||
RETURNING id, program_id, title, description, level_index, number_of_modules, number_of_practices, number_of_videos, is_active
|
||||
`
|
||||
|
||||
type CreateLevelParams struct {
|
||||
|
|
@ -49,10 +28,7 @@ type CreateLevelParams struct {
|
|||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
LevelIndex int32 `json:"level_index"`
|
||||
NumberOfModules int32 `json:"number_of_modules"`
|
||||
NumberOfPractices int32 `json:"number_of_practices"`
|
||||
NumberOfVideos int32 `json:"number_of_videos"`
|
||||
IsActive bool `json:"is_active"`
|
||||
Column5 interface{} `json:"column_5"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateLevel(ctx context.Context, arg CreateLevelParams) (Level, error) {
|
||||
|
|
@ -61,10 +37,7 @@ func (q *Queries) CreateLevel(ctx context.Context, arg CreateLevelParams) (Level
|
|||
arg.Title,
|
||||
arg.Description,
|
||||
arg.LevelIndex,
|
||||
arg.NumberOfModules,
|
||||
arg.NumberOfPractices,
|
||||
arg.NumberOfVideos,
|
||||
arg.IsActive,
|
||||
arg.Column5,
|
||||
)
|
||||
var i Level
|
||||
err := row.Scan(
|
||||
|
|
@ -81,51 +54,19 @@ func (q *Queries) CreateLevel(ctx context.Context, arg CreateLevelParams) (Level
|
|||
return i, err
|
||||
}
|
||||
|
||||
const DeactivateLevel = `-- name: DeactivateLevel :exec
|
||||
UPDATE levels
|
||||
SET is_active = FALSE
|
||||
const DeleteLevel = `-- name: DeleteLevel :exec
|
||||
DELETE FROM levels
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) DeactivateLevel(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeactivateLevel, id)
|
||||
func (q *Queries) DeleteLevel(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, DeleteLevel, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const GetLevelByID = `-- name: GetLevelByID :one
|
||||
SELECT
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active
|
||||
FROM levels
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetLevelByID(ctx context.Context, id int64) (Level, error) {
|
||||
row := q.db.QueryRow(ctx, GetLevelByID, id)
|
||||
var i Level
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProgramID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.LevelIndex,
|
||||
&i.NumberOfModules,
|
||||
&i.NumberOfPractices,
|
||||
&i.NumberOfVideos,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const ListLevelsByProgram = `-- name: ListLevelsByProgram :many
|
||||
const GetLevelsByProgram = `-- name: GetLevelsByProgram :many
|
||||
SELECT
|
||||
COUNT(*) OVER () AS total_count,
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
|
|
@ -137,20 +78,33 @@ SELECT
|
|||
is_active
|
||||
FROM levels
|
||||
WHERE program_id = $1
|
||||
AND is_active = TRUE
|
||||
ORDER BY level_index ASC
|
||||
`
|
||||
|
||||
func (q *Queries) ListLevelsByProgram(ctx context.Context, programID int64) ([]Level, error) {
|
||||
rows, err := q.db.Query(ctx, ListLevelsByProgram, programID)
|
||||
type GetLevelsByProgramRow struct {
|
||||
TotalCount int64 `json:"total_count"`
|
||||
ID int64 `json:"id"`
|
||||
ProgramID int64 `json:"program_id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
LevelIndex int32 `json:"level_index"`
|
||||
NumberOfModules int32 `json:"number_of_modules"`
|
||||
NumberOfPractices int32 `json:"number_of_practices"`
|
||||
NumberOfVideos int32 `json:"number_of_videos"`
|
||||
IsActive bool `json:"is_active"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetLevelsByProgram(ctx context.Context, programID int64) ([]GetLevelsByProgramRow, error) {
|
||||
rows, err := q.db.Query(ctx, GetLevelsByProgram, programID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Level
|
||||
var items []GetLevelsByProgramRow
|
||||
for rows.Next() {
|
||||
var i Level
|
||||
var i GetLevelsByProgramRow
|
||||
if err := rows.Scan(
|
||||
&i.TotalCount,
|
||||
&i.ID,
|
||||
&i.ProgramID,
|
||||
&i.Title,
|
||||
|
|
@ -171,62 +125,64 @@ func (q *Queries) ListLevelsByProgram(ctx context.Context, programID int64) ([]L
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const UpdateLevel = `-- name: UpdateLevel :one
|
||||
const IncrementLevelModuleCount = `-- name: IncrementLevelModuleCount :exec
|
||||
UPDATE levels
|
||||
SET number_of_modules = number_of_modules + 1
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) IncrementLevelModuleCount(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, IncrementLevelModuleCount, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const IncrementLevelPracticeCount = `-- name: IncrementLevelPracticeCount :exec
|
||||
UPDATE levels
|
||||
SET number_of_practices = number_of_practices + 1
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) IncrementLevelPracticeCount(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, IncrementLevelPracticeCount, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const IncrementLevelVideoCount = `-- name: IncrementLevelVideoCount :exec
|
||||
UPDATE levels
|
||||
SET number_of_videos = number_of_videos + 1
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) IncrementLevelVideoCount(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, IncrementLevelVideoCount, id)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateLevel = `-- name: UpdateLevel :exec
|
||||
UPDATE levels
|
||||
SET
|
||||
title = $2,
|
||||
description = $3,
|
||||
level_index = $4,
|
||||
number_of_modules = $5,
|
||||
number_of_practices = $6,
|
||||
number_of_videos = $7,
|
||||
is_active = $8
|
||||
WHERE id = $1
|
||||
RETURNING
|
||||
id,
|
||||
program_id,
|
||||
title,
|
||||
description,
|
||||
level_index,
|
||||
number_of_modules,
|
||||
number_of_practices,
|
||||
number_of_videos,
|
||||
is_active
|
||||
title = COALESCE($1, title),
|
||||
description = COALESCE($2, description),
|
||||
level_index = COALESCE($3, level_index),
|
||||
is_active = COALESCE($4, is_active)
|
||||
WHERE id = $5
|
||||
`
|
||||
|
||||
type UpdateLevelParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description pgtype.Text `json:"description"`
|
||||
LevelIndex int32 `json:"level_index"`
|
||||
NumberOfModules int32 `json:"number_of_modules"`
|
||||
NumberOfPractices int32 `json:"number_of_practices"`
|
||||
NumberOfVideos int32 `json:"number_of_videos"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateLevel(ctx context.Context, arg UpdateLevelParams) (Level, error) {
|
||||
row := q.db.QueryRow(ctx, UpdateLevel,
|
||||
arg.ID,
|
||||
func (q *Queries) UpdateLevel(ctx context.Context, arg UpdateLevelParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateLevel,
|
||||
arg.Title,
|
||||
arg.Description,
|
||||
arg.LevelIndex,
|
||||
arg.NumberOfModules,
|
||||
arg.NumberOfPractices,
|
||||
arg.NumberOfVideos,
|
||||
arg.IsActive,
|
||||
arg.ID,
|
||||
)
|
||||
var i Level
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ProgramID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.LevelIndex,
|
||||
&i.NumberOfModules,
|
||||
&i.NumberOfPractices,
|
||||
&i.NumberOfVideos,
|
||||
&i.IsActive,
|
||||
)
|
||||
return i, err
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
110
internal/domain/course_management.go
Normal file
110
internal/domain/course_management.go
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type TreeModule struct {
|
||||
ID int64
|
||||
Title string
|
||||
}
|
||||
|
||||
type TreeLevel struct {
|
||||
ID int64
|
||||
Title string
|
||||
Modules []TreeModule
|
||||
}
|
||||
|
||||
type TreeProgram struct {
|
||||
ID int64
|
||||
Title string
|
||||
Levels []TreeLevel
|
||||
}
|
||||
|
||||
type TreeCourse struct {
|
||||
ID int64
|
||||
Title string
|
||||
Programs []TreeProgram
|
||||
}
|
||||
|
||||
type CourseCategory struct {
|
||||
ID int64
|
||||
Name string
|
||||
IsActive bool
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type Program struct {
|
||||
ID int64
|
||||
CourseID int64
|
||||
Title string
|
||||
Description *string
|
||||
Thumbnail *string
|
||||
DisplayOrder int32
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type Course struct {
|
||||
ID int64
|
||||
CategoryID int64
|
||||
Title string
|
||||
Description *string
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type Module struct {
|
||||
ID int64
|
||||
LevelID int64
|
||||
Title string
|
||||
Content *string
|
||||
DisplayOrder int32
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type ModuleVideo struct {
|
||||
ID int64
|
||||
ModuleID int64
|
||||
Title string
|
||||
Description *string
|
||||
VideoURL string
|
||||
Duration int32
|
||||
Resolution *string
|
||||
InstructorID *string
|
||||
Thumbnail *string
|
||||
Visibility *string
|
||||
IsPublished bool
|
||||
PublishDate *time.Time
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type PracticeQuestion struct {
|
||||
ID int64
|
||||
PracticeID int64
|
||||
Question string
|
||||
QuestionVoicePrompt *string
|
||||
SampleAnswerVoicePrompt *string
|
||||
SampleAnswer *string
|
||||
Tips *string
|
||||
Type string
|
||||
}
|
||||
|
||||
type Practice struct {
|
||||
ID int64
|
||||
OwnerType string
|
||||
OwnerID int64
|
||||
Title string
|
||||
Description *string
|
||||
BannerImage *string
|
||||
Persona *string
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type Level struct {
|
||||
ID int64
|
||||
ProgramID int64
|
||||
Title string
|
||||
Description *string
|
||||
LevelIndex int
|
||||
NumberOfModules int
|
||||
NumberOfPractices int
|
||||
NumberOfVideos int
|
||||
IsActive bool
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type CourseCategory struct {
|
||||
ID int64
|
||||
Name string // "Learning English", "Other Courses"
|
||||
IsActive bool
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type Course struct {
|
||||
ID int64
|
||||
CategoryID int64
|
||||
Title string
|
||||
Description string
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type Program struct {
|
||||
ID int64
|
||||
CourseID int64
|
||||
Title string
|
||||
Description string
|
||||
Thumbnail string
|
||||
Order int // ordering inside course
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type Level struct {
|
||||
ID int64
|
||||
ProgramID int64
|
||||
Title string // "Beginner", "Level 1"
|
||||
Description string
|
||||
LevelIndex int // 1,2,3...
|
||||
NumberOfModules int
|
||||
NumberOfPractices int
|
||||
NumberOfVideos int
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type Module struct {
|
||||
ID int64
|
||||
LevelID int64
|
||||
Title string
|
||||
Content string
|
||||
Order int
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type ModuleVideo struct {
|
||||
ID int64
|
||||
ModuleID int64
|
||||
Title string
|
||||
Description string
|
||||
VideoURL string
|
||||
Duration int // seconds
|
||||
Resolution string // "720p", "1080p"
|
||||
PublishSettings PublishSettings
|
||||
IsActive bool
|
||||
InstructorId string
|
||||
Thumbnail string
|
||||
}
|
||||
|
||||
type PublishSettings struct {
|
||||
IsPublished bool
|
||||
PublishDate time.Time
|
||||
Visibility string // "public", "private", "unlisted"
|
||||
}
|
||||
|
||||
type Practice struct {
|
||||
ID int64
|
||||
OwnerType string // "LEVEL" | "MODULE"
|
||||
OwnerID int64
|
||||
Title string
|
||||
Description string
|
||||
BannerImage string
|
||||
Persona string
|
||||
IsActive bool
|
||||
}
|
||||
|
||||
type PracticeQuestion struct {
|
||||
ID int64
|
||||
PracticeID int64
|
||||
Question string
|
||||
QuestionVoicePrompt string
|
||||
SampleAnswerVoicePrompt string
|
||||
SampleAnswer string
|
||||
Tips string
|
||||
Type string // MCQ, TRUE_FALSE, SHORT
|
||||
}
|
||||
|
|
@ -1,60 +1,253 @@
|
|||
package ports
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
type CourseStore interface{
|
||||
CreateCourseCategory(ctx context.Context, name string) (domain.CourseCategory, error)
|
||||
GetCourseCategoryByID(ctx context.Context, Id int64) (domain.CourseCategory, error)
|
||||
ListActiveCourseCategories(ctx context.Context) ([]domain.CourseCategory, error)
|
||||
UpdateCourseCategory(ctx context.Context, id int64, name string, isActive bool) (domain.CourseCategory, error)
|
||||
DeactivateCourseCategory(ctx context.Context, id int64) error
|
||||
|
||||
CreateCourse(ctx context.Context, c domain.Course) (domain.Course, error)
|
||||
GetCourseByID(ctx context.Context, id int64) (domain.Course, error)
|
||||
ListCoursesByCategory(ctx context.Context, categoryID int64) ([]domain.Course, error)
|
||||
ListActiveCourses(ctx context.Context) ([]domain.Course, error)
|
||||
UpdateCourse(ctx context.Context, c domain.Course) (domain.Course, error)
|
||||
DeactivateCourse(ctx context.Context, id int64) error
|
||||
|
||||
CreateProgram(ctx context.Context, p domain.Program) (domain.Program, error)
|
||||
GetProgramByID(ctx context.Context, id int64) (domain.Program, error)
|
||||
ListProgramsByCourse(ctx context.Context, courseID int64) ([]domain.Program, error)
|
||||
ListActivePrograms(ctx context.Context) ([]domain.Program, error)
|
||||
UpdateProgram(ctx context.Context, p domain.Program) (domain.Program, error)
|
||||
DeactivateProgram(ctx context.Context, id int64) error
|
||||
|
||||
CreateModule(ctx context.Context, m domain.Module) (domain.Module, error)
|
||||
GetModuleByID(ctx context.Context, id int64) (domain.Module, error)
|
||||
ListModulesByLevel(ctx context.Context, levelID int64) ([]domain.Module, error)
|
||||
UpdateModule(ctx context.Context, m domain.Module) (domain.Module, error)
|
||||
DeactivateModule(ctx context.Context, id int64) error
|
||||
|
||||
CreateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error)
|
||||
GetModuleVideoByID(ctx context.Context, id int64) (domain.ModuleVideo, error)
|
||||
ListAllVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error)
|
||||
ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error)
|
||||
UpdateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error)
|
||||
DeactivateModuleVideo(ctx context.Context, id int64) error
|
||||
|
||||
CreatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error)
|
||||
GetPracticeByID(ctx context.Context, id int64) (domain.Practice, error)
|
||||
ListPracticesByOwner(ctx context.Context, ownerType string, ownerID int64) ([]domain.Practice, error)
|
||||
UpdatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error)
|
||||
DeactivatePractice(ctx context.Context, id int64) error
|
||||
|
||||
CreatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error)
|
||||
GetPracticeQuestionByID(ctx context.Context, id int64) (domain.PracticeQuestion, error)
|
||||
ListPracticeQuestions(ctx context.Context, practiceID int64) ([]domain.PracticeQuestion, error)
|
||||
UpdatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error)
|
||||
DeletePracticeQuestion(ctx context.Context, id int64) error
|
||||
|
||||
CreateLevel(ctx context.Context, l domain.Level) (domain.Level, error)
|
||||
GetLevelByID(ctx context.Context, id int64) (domain.Level, error)
|
||||
ListLevelsByProgram(ctx context.Context, programID int64) ([]domain.Level, error)
|
||||
UpdateLevel(ctx context.Context, l domain.Level) (domain.Level, error)
|
||||
DeactivateLevel(ctx context.Context, id int64) error
|
||||
type CourseStore interface {
|
||||
CreateCourseCategory(
|
||||
ctx context.Context,
|
||||
name string,
|
||||
) (domain.CourseCategory, error)
|
||||
GetCourseCategoryByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.CourseCategory, error)
|
||||
GetAllCourseCategories(
|
||||
ctx context.Context,
|
||||
limit int32,
|
||||
offset int32,
|
||||
) ([]domain.CourseCategory, int64, error)
|
||||
UpdateCourseCategory(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
name *string,
|
||||
isActive *bool,
|
||||
) error
|
||||
DeleteCourseCategory(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error
|
||||
CreateProgram(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
title string,
|
||||
description *string,
|
||||
thumbnail *string,
|
||||
displayOrder *int32,
|
||||
) (domain.Program, error)
|
||||
GetProgramByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Program, error)
|
||||
GetProgramsByCourse(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
) ([]domain.Program, int64, error)
|
||||
ListProgramsByCourse(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
) ([]domain.Program, error)
|
||||
ListActivePrograms(
|
||||
ctx context.Context,
|
||||
) ([]domain.Program, error)
|
||||
UpdateProgramPartial(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
thumbnail *string,
|
||||
displayOrder *int32,
|
||||
isActive *bool,
|
||||
) error
|
||||
UpdateProgramFull(
|
||||
ctx context.Context,
|
||||
program domain.Program,
|
||||
) (domain.Program, error)
|
||||
DeactivateProgram(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error
|
||||
DeleteProgram(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Program, error)
|
||||
CreateCourse(
|
||||
ctx context.Context,
|
||||
categoryID int64,
|
||||
title string,
|
||||
description *string,
|
||||
) (domain.Course, error)
|
||||
GetCourseByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Course, error)
|
||||
GetCoursesByCategory(
|
||||
ctx context.Context,
|
||||
categoryID int64,
|
||||
limit int32,
|
||||
offset int32,
|
||||
) ([]domain.Course, int64, error)
|
||||
UpdateCourse(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
isActive *bool,
|
||||
) error
|
||||
DeleteCourse(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error
|
||||
CreateModule(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
title string,
|
||||
content *string,
|
||||
displayOrder *int32,
|
||||
) (domain.Module, error)
|
||||
GetModulesByLevel(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) ([]domain.Module, int64, error)
|
||||
UpdateModule(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
content *string,
|
||||
displayOrder *int32,
|
||||
isActive *bool,
|
||||
) error
|
||||
DeleteModule(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error
|
||||
CreateModuleVideo(
|
||||
ctx context.Context,
|
||||
moduleID int64,
|
||||
title string,
|
||||
description *string,
|
||||
videoURL string,
|
||||
duration int32,
|
||||
resolution *string,
|
||||
instructorID *string,
|
||||
thumbnail *string,
|
||||
visibility *string,
|
||||
) (domain.ModuleVideo, error)
|
||||
PublishModuleVideo(
|
||||
ctx context.Context,
|
||||
videoID int64,
|
||||
) error
|
||||
GetPublishedVideosByModule(
|
||||
ctx context.Context,
|
||||
moduleID int64,
|
||||
) ([]domain.ModuleVideo, error)
|
||||
UpdateModuleVideo(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
videoURL *string,
|
||||
duration *int32,
|
||||
resolution *string,
|
||||
visibility *string,
|
||||
thumbnail *string,
|
||||
isActive *bool,
|
||||
) error
|
||||
DeleteModuleVideo(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error
|
||||
CreatePracticeQuestion(
|
||||
ctx context.Context,
|
||||
practiceID int64,
|
||||
question string,
|
||||
questionVoicePrompt *string,
|
||||
sampleAnswerVoicePrompt *string,
|
||||
sampleAnswer *string,
|
||||
tips *string,
|
||||
qType string,
|
||||
) (domain.PracticeQuestion, error)
|
||||
GetQuestionsByPractice(
|
||||
ctx context.Context,
|
||||
practiceID int64,
|
||||
) ([]domain.PracticeQuestion, error)
|
||||
UpdatePracticeQuestion(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
question *string,
|
||||
sampleAnswer *string,
|
||||
tips *string,
|
||||
qType *string,
|
||||
) error
|
||||
DeletePracticeQuestion(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error
|
||||
CreatePractice(
|
||||
ctx context.Context,
|
||||
ownerType string,
|
||||
ownerID int64,
|
||||
title string,
|
||||
description *string,
|
||||
bannerImage *string,
|
||||
persona *string,
|
||||
isActive *bool,
|
||||
) (domain.Practice, error)
|
||||
GetPracticesByOwner(
|
||||
ctx context.Context,
|
||||
ownerType string,
|
||||
ownerID int64,
|
||||
) ([]domain.Practice, error)
|
||||
UpdatePractice(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
bannerImage *string,
|
||||
persona *string,
|
||||
isActive *bool,
|
||||
) error
|
||||
DeletePractice(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error
|
||||
CreateLevel(
|
||||
ctx context.Context,
|
||||
programID int64,
|
||||
title string,
|
||||
description *string,
|
||||
levelIndex int,
|
||||
isActive *bool,
|
||||
) (domain.Level, error)
|
||||
GetLevelsByProgram(
|
||||
ctx context.Context,
|
||||
programID int64,
|
||||
) ([]domain.Level, error)
|
||||
UpdateLevel(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
levelIndex *int,
|
||||
isActive *bool,
|
||||
) error
|
||||
IncrementLevelModuleCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error
|
||||
IncrementLevelPracticeCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error
|
||||
IncrementLevelVideoCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error
|
||||
DeleteLevel(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error
|
||||
GetFullLearningTree(ctx context.Context) ([]domain.TreeCourse, error)
|
||||
}
|
||||
|
|
@ -11,65 +11,14 @@ import (
|
|||
|
||||
func NewCourseStore(s *Store) ports.CourseStore { return s }
|
||||
|
||||
func (s *Store) CreateCourseCategory(ctx context.Context, name string) (domain.CourseCategory, error) {
|
||||
tempCategory, err := s.queries.CreateCourseCategory(ctx, dbgen.CreateCourseCategoryParams{
|
||||
func (s *Store) CreateCourseCategory(
|
||||
ctx context.Context,
|
||||
name string,
|
||||
) (domain.CourseCategory, error) {
|
||||
|
||||
row, err := s.queries.CreateCourseCategory(ctx, dbgen.CreateCourseCategoryParams{
|
||||
Name: name,
|
||||
IsActive: true,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.CourseCategory{}, err
|
||||
}
|
||||
|
||||
category := domain.CourseCategory{
|
||||
ID: tempCategory.ID,
|
||||
Name: tempCategory.Name,
|
||||
IsActive: tempCategory.IsActive,
|
||||
CreatedAt: tempCategory.CreatedAt.Time,
|
||||
}
|
||||
|
||||
return category, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetCourseCategoryByID(ctx context.Context, Id int64) (domain.CourseCategory, error) {
|
||||
tempCategory, err := s.queries.GetCourseCategoryByID(ctx, Id)
|
||||
if err != nil {
|
||||
return domain.CourseCategory{}, err
|
||||
}
|
||||
|
||||
category := domain.CourseCategory{
|
||||
ID: tempCategory.ID,
|
||||
Name: tempCategory.Name,
|
||||
IsActive: tempCategory.IsActive,
|
||||
CreatedAt: tempCategory.CreatedAt.Time,
|
||||
}
|
||||
|
||||
return category, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListActiveCourseCategories(ctx context.Context) ([]domain.CourseCategory, error) {
|
||||
rows, err := s.queries.ListActiveCourseCategories(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]domain.CourseCategory, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
result = append(result, domain.CourseCategory{
|
||||
ID: r.ID,
|
||||
Name: r.Name,
|
||||
IsActive: r.IsActive,
|
||||
CreatedAt: r.CreatedAt.Time,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateCourseCategory(ctx context.Context, id int64, name string, isActive bool) (domain.CourseCategory, error) {
|
||||
row, err := s.queries.UpdateCourseCategory(ctx, dbgen.UpdateCourseCategoryParams{
|
||||
ID: id,
|
||||
Name: name,
|
||||
IsActive: isActive,
|
||||
Column2: true,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.CourseCategory{}, err
|
||||
|
|
@ -83,752 +32,90 @@ func (s *Store) UpdateCourseCategory(ctx context.Context, id int64, name string,
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivateCourseCategory(ctx context.Context, id int64) error {
|
||||
return s.queries.DeactivateCourseCategory(ctx, id)
|
||||
}
|
||||
func (s *Store) GetCourseCategoryByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.CourseCategory, error) {
|
||||
|
||||
// Course related methods
|
||||
func (s *Store) CreateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
||||
row, err := s.queries.CreateCourse(ctx, dbgen.CreateCourseParams{
|
||||
CategoryID: c.CategoryID,
|
||||
Title: c.Title,
|
||||
Description: pgtype.Text{String: c.Description, Valid: c.Description != ""},
|
||||
IsActive: c.IsActive,
|
||||
})
|
||||
row, err := s.queries.GetCourseCategoryByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Course{}, err
|
||||
return domain.CourseCategory{}, err
|
||||
}
|
||||
|
||||
return domain.Course{
|
||||
return domain.CourseCategory{
|
||||
ID: row.ID,
|
||||
CategoryID: row.CategoryID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
Name: row.Name,
|
||||
IsActive: row.IsActive,
|
||||
CreatedAt: row.CreatedAt.Time,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetCourseByID(ctx context.Context, id int64) (domain.Course, error) {
|
||||
row, err := s.queries.GetCourseByID(ctx, id)
|
||||
func (s *Store) GetAllCourseCategories(
|
||||
ctx context.Context,
|
||||
limit int32,
|
||||
offset int32,
|
||||
) ([]domain.CourseCategory, int64, error) {
|
||||
|
||||
rows, err := s.queries.GetAllCourseCategories(ctx, dbgen.GetAllCourseCategoriesParams{
|
||||
Limit: pgtype.Int4{Int32: limit},
|
||||
Offset: pgtype.Int4{Int32: offset},
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Course{}, err
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return domain.Course{
|
||||
var (
|
||||
categories []domain.CourseCategory
|
||||
totalCount int64
|
||||
)
|
||||
|
||||
for i, row := range rows {
|
||||
if i == 0 {
|
||||
totalCount = row.TotalCount
|
||||
}
|
||||
|
||||
categories = append(categories, domain.CourseCategory{
|
||||
ID: row.ID,
|
||||
CategoryID: row.CategoryID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
Name: row.Name,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListCoursesByCategory(ctx context.Context, categoryID int64) ([]domain.Course, error) {
|
||||
rows, err := s.queries.ListCoursesByCategory(ctx, categoryID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]domain.Course, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.Course{
|
||||
ID: r.ID,
|
||||
CategoryID: r.CategoryID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
IsActive: r.IsActive,
|
||||
CreatedAt: row.CreatedAt.Time,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
|
||||
return categories, totalCount, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListActiveCourses(ctx context.Context) ([]domain.Course, error) {
|
||||
rows, err := s.queries.ListActiveCourses(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *Store) UpdateCourseCategory(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
name *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
|
||||
var (
|
||||
nameVal string
|
||||
isActiveVal bool
|
||||
)
|
||||
|
||||
if name != nil {
|
||||
nameVal = *name
|
||||
}
|
||||
|
||||
res := make([]domain.Course, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.Course{
|
||||
ID: r.ID,
|
||||
CategoryID: r.CategoryID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
IsActive: r.IsActive,
|
||||
if isActive != nil {
|
||||
isActiveVal = *isActive
|
||||
}
|
||||
|
||||
return s.queries.UpdateCourseCategory(ctx, dbgen.UpdateCourseCategoryParams{
|
||||
Name: nameVal,
|
||||
IsActive: isActiveVal,
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
||||
row, err := s.queries.UpdateCourse(ctx, dbgen.UpdateCourseParams{
|
||||
ID: c.ID,
|
||||
CategoryID: c.CategoryID,
|
||||
Title: c.Title,
|
||||
Description: pgtype.Text{String: c.Description, Valid: c.Description != ""},
|
||||
IsActive: c.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Course{}, err
|
||||
}
|
||||
func (s *Store) DeleteCourseCategory(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
|
||||
return domain.Course{
|
||||
ID: row.ID,
|
||||
CategoryID: row.CategoryID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivateCourse(ctx context.Context, id int64) error {
|
||||
return s.queries.DeactivateCourse(ctx, id)
|
||||
}
|
||||
|
||||
// Program methods
|
||||
func (s *Store) CreateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
||||
row, err := s.queries.CreateProgram(ctx, dbgen.CreateProgramParams{
|
||||
CourseID: p.CourseID,
|
||||
Title: p.Title,
|
||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
||||
Thumbnail: pgtype.Text{String: p.Thumbnail, Valid: p.Thumbnail != ""},
|
||||
DisplayOrder: int32(p.Order),
|
||||
IsActive: p.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Program{}, err
|
||||
}
|
||||
|
||||
return domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
Thumbnail: row.Thumbnail.String,
|
||||
Order: int(row.DisplayOrder),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetProgramByID(ctx context.Context, id int64) (domain.Program, error) {
|
||||
row, err := s.queries.GetProgramByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Program{}, err
|
||||
}
|
||||
|
||||
return domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
Thumbnail: row.Thumbnail.String,
|
||||
Order: int(row.DisplayOrder),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListProgramsByCourse(ctx context.Context, courseID int64) ([]domain.Program, error) {
|
||||
rows, err := s.queries.ListProgramsByCourse(ctx, courseID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]domain.Program, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.Program{
|
||||
ID: r.ID,
|
||||
CourseID: r.CourseID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
Thumbnail: r.Thumbnail.String,
|
||||
Order: int(r.DisplayOrder),
|
||||
IsActive: r.IsActive,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListActivePrograms(ctx context.Context) ([]domain.Program, error) {
|
||||
rows, err := s.queries.ListActivePrograms(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]domain.Program, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.Program{
|
||||
ID: r.ID,
|
||||
CourseID: r.CourseID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
Thumbnail: r.Thumbnail.String,
|
||||
Order: int(r.DisplayOrder),
|
||||
IsActive: r.IsActive,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
||||
row, err := s.queries.UpdateProgram(ctx, dbgen.UpdateProgramParams{
|
||||
ID: p.ID,
|
||||
CourseID: p.CourseID,
|
||||
Title: p.Title,
|
||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
||||
Thumbnail: pgtype.Text{String: p.Thumbnail, Valid: p.Thumbnail != ""},
|
||||
DisplayOrder: int32(p.Order),
|
||||
IsActive: p.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Program{}, err
|
||||
}
|
||||
|
||||
return domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
Thumbnail: row.Thumbnail.String,
|
||||
Order: int(row.DisplayOrder),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivateProgram(ctx context.Context, id int64) error {
|
||||
return s.queries.DeactivateProgram(ctx, id)
|
||||
}
|
||||
|
||||
// Module methods
|
||||
func (s *Store) CreateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
||||
row, err := s.queries.CreateModule(ctx, dbgen.CreateModuleParams{
|
||||
LevelID: m.LevelID,
|
||||
Title: m.Title,
|
||||
Content: pgtype.Text{String: m.Content, Valid: m.Content != ""},
|
||||
DisplayOrder: int32(m.Order),
|
||||
IsActive: m.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Module{}, err
|
||||
}
|
||||
|
||||
return domain.Module{
|
||||
ID: row.ID,
|
||||
LevelID: row.LevelID,
|
||||
Title: row.Title,
|
||||
Content: row.Content.String,
|
||||
Order: int(row.DisplayOrder),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetModuleByID(ctx context.Context, id int64) (domain.Module, error) {
|
||||
row, err := s.queries.GetModuleByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Module{}, err
|
||||
}
|
||||
|
||||
return domain.Module{
|
||||
ID: row.ID,
|
||||
LevelID: row.LevelID,
|
||||
Title: row.Title,
|
||||
Content: row.Content.String,
|
||||
Order: int(row.DisplayOrder),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListModulesByLevel(ctx context.Context, levelID int64) ([]domain.Module, error) {
|
||||
rows, err := s.queries.ListModulesByLevel(ctx, levelID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]domain.Module, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.Module{
|
||||
ID: r.ID,
|
||||
LevelID: r.LevelID,
|
||||
Title: r.Title,
|
||||
Content: r.Content.String,
|
||||
Order: int(r.DisplayOrder),
|
||||
IsActive: r.IsActive,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
||||
row, err := s.queries.UpdateModule(ctx, dbgen.UpdateModuleParams{
|
||||
ID: m.ID,
|
||||
Title: m.Title,
|
||||
Content: pgtype.Text{String: m.Content, Valid: m.Content != ""},
|
||||
DisplayOrder: int32(m.Order),
|
||||
IsActive: m.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Module{}, err
|
||||
}
|
||||
|
||||
return domain.Module{
|
||||
ID: row.ID,
|
||||
LevelID: row.LevelID,
|
||||
Title: row.Title,
|
||||
Content: row.Content.String,
|
||||
Order: int(row.DisplayOrder),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivateModule(ctx context.Context, id int64) error {
|
||||
return s.queries.DeactivateModule(ctx, id)
|
||||
}
|
||||
|
||||
// Module video methods
|
||||
func (s *Store) CreateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
||||
row, err := s.queries.CreateModuleVideo(ctx, dbgen.CreateModuleVideoParams{
|
||||
ModuleID: v.ModuleID,
|
||||
Title: v.Title,
|
||||
Description: pgtype.Text{String: v.Description, Valid: v.Description != ""},
|
||||
VideoUrl: v.VideoURL,
|
||||
Duration: int32(v.Duration),
|
||||
Resolution: pgtype.Text{String: v.Resolution, Valid: v.Resolution != ""},
|
||||
IsPublished: v.PublishSettings.IsPublished,
|
||||
PublishDate: pgtype.Timestamptz{Time: v.PublishSettings.PublishDate, Valid: !v.PublishSettings.PublishDate.IsZero()},
|
||||
Visibility: pgtype.Text{String: v.PublishSettings.Visibility, Valid: v.PublishSettings.Visibility != ""},
|
||||
InstructorID: pgtype.Text{String: v.InstructorId, Valid: v.InstructorId != ""},
|
||||
Thumbnail: pgtype.Text{String: v.Thumbnail, Valid: v.Thumbnail != ""},
|
||||
IsActive: v.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.ModuleVideo{}, err
|
||||
}
|
||||
|
||||
return domain.ModuleVideo{
|
||||
ID: row.ID,
|
||||
ModuleID: row.ModuleID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
VideoURL: row.VideoUrl,
|
||||
Duration: int(row.Duration),
|
||||
Resolution: row.Resolution.String,
|
||||
PublishSettings: domain.PublishSettings{
|
||||
IsPublished: row.IsPublished,
|
||||
PublishDate: row.PublishDate.Time,
|
||||
Visibility: row.Visibility.String,
|
||||
},
|
||||
InstructorId: row.InstructorID.String,
|
||||
Thumbnail: row.Thumbnail.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetModuleVideoByID(ctx context.Context, id int64) (domain.ModuleVideo, error) {
|
||||
row, err := s.queries.GetModuleVideoByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.ModuleVideo{}, err
|
||||
}
|
||||
|
||||
return domain.ModuleVideo{
|
||||
ID: row.ID,
|
||||
ModuleID: row.ModuleID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
VideoURL: row.VideoUrl,
|
||||
Duration: int(row.Duration),
|
||||
Resolution: row.Resolution.String,
|
||||
PublishSettings: domain.PublishSettings{
|
||||
IsPublished: row.IsPublished,
|
||||
PublishDate: row.PublishDate.Time,
|
||||
Visibility: row.Visibility.String,
|
||||
},
|
||||
InstructorId: row.InstructorID.String,
|
||||
Thumbnail: row.Thumbnail.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
||||
rows, err := s.queries.ListAllVideosByModule(ctx, moduleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]domain.ModuleVideo, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.ModuleVideo{
|
||||
ID: r.ID,
|
||||
ModuleID: r.ModuleID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
VideoURL: r.VideoUrl,
|
||||
Duration: int(r.Duration),
|
||||
Resolution: r.Resolution.String,
|
||||
PublishSettings: domain.PublishSettings{
|
||||
IsPublished: r.IsPublished,
|
||||
PublishDate: r.PublishDate.Time,
|
||||
Visibility: r.Visibility.String,
|
||||
},
|
||||
InstructorId: r.InstructorID.String,
|
||||
Thumbnail: r.Thumbnail.String,
|
||||
IsActive: r.IsActive,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
||||
rows, err := s.queries.ListPublishedVideosByModule(ctx, moduleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := make([]domain.ModuleVideo, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.ModuleVideo{
|
||||
ID: r.ID,
|
||||
ModuleID: r.ModuleID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
VideoURL: r.VideoUrl,
|
||||
Duration: int(r.Duration),
|
||||
Resolution: r.Resolution.String,
|
||||
PublishSettings: domain.PublishSettings{
|
||||
IsPublished: true,
|
||||
PublishDate: r.PublishDate.Time,
|
||||
Visibility: r.Visibility.String,
|
||||
},
|
||||
InstructorId: r.InstructorID.String,
|
||||
Thumbnail: r.Thumbnail.String,
|
||||
IsActive: true,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
||||
row, err := s.queries.UpdateModuleVideo(ctx, dbgen.UpdateModuleVideoParams{
|
||||
ID: v.ID,
|
||||
Title: v.Title,
|
||||
Description: pgtype.Text{String: v.Description, Valid: v.Description != ""},
|
||||
VideoUrl: v.VideoURL,
|
||||
Duration: int32(v.Duration),
|
||||
Resolution: pgtype.Text{String: v.Resolution, Valid: v.Resolution != ""},
|
||||
IsPublished: v.PublishSettings.IsPublished,
|
||||
PublishDate: pgtype.Timestamptz{Time: v.PublishSettings.PublishDate, Valid: !v.PublishSettings.PublishDate.IsZero()},
|
||||
Visibility: pgtype.Text{String: v.PublishSettings.Visibility, Valid: v.PublishSettings.Visibility != ""},
|
||||
InstructorID: pgtype.Text{String: v.InstructorId, Valid: v.InstructorId != ""},
|
||||
Thumbnail: pgtype.Text{String: v.Thumbnail, Valid: v.Thumbnail != ""},
|
||||
IsActive: v.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.ModuleVideo{}, err
|
||||
}
|
||||
|
||||
return domain.ModuleVideo{
|
||||
ID: row.ID,
|
||||
ModuleID: row.ModuleID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
VideoURL: row.VideoUrl,
|
||||
Duration: int(row.Duration),
|
||||
Resolution: row.Resolution.String,
|
||||
PublishSettings: domain.PublishSettings{
|
||||
IsPublished: row.IsPublished,
|
||||
PublishDate: row.PublishDate.Time,
|
||||
Visibility: row.Visibility.String,
|
||||
},
|
||||
InstructorId: row.InstructorID.String,
|
||||
Thumbnail: row.Thumbnail.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivateModuleVideo(ctx context.Context, id int64) error {
|
||||
return s.queries.DeactivateModuleVideo(ctx, id)
|
||||
}
|
||||
|
||||
// Practices and practice question methods
|
||||
func (s *Store) CreatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
||||
row, err := s.queries.CreatePractice(ctx, dbgen.CreatePracticeParams{
|
||||
OwnerType: p.OwnerType,
|
||||
OwnerID: p.OwnerID,
|
||||
Title: p.Title,
|
||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
||||
BannerImage: pgtype.Text{String: p.BannerImage, Valid: p.BannerImage != ""},
|
||||
Persona: pgtype.Text{String: p.Persona, Valid: p.Persona != ""},
|
||||
IsActive: p.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Practice{}, err
|
||||
}
|
||||
|
||||
return domain.Practice{
|
||||
ID: row.ID,
|
||||
OwnerType: row.OwnerType,
|
||||
OwnerID: row.OwnerID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
BannerImage: row.BannerImage.String,
|
||||
Persona: row.Persona.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetPracticeByID(ctx context.Context, id int64) (domain.Practice, error) {
|
||||
row, err := s.queries.GetPracticeByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Practice{}, err
|
||||
}
|
||||
return domain.Practice{
|
||||
ID: row.ID,
|
||||
OwnerType: row.OwnerType,
|
||||
OwnerID: row.OwnerID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
BannerImage: row.BannerImage.String,
|
||||
Persona: row.Persona.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListPracticesByOwner(ctx context.Context, ownerType string, ownerID int64) ([]domain.Practice, error) {
|
||||
rows, err := s.queries.ListPracticesByOwner(ctx, dbgen.ListPracticesByOwnerParams{OwnerType: ownerType, OwnerID: ownerID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([]domain.Practice, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.Practice{
|
||||
ID: r.ID,
|
||||
OwnerType: r.OwnerType,
|
||||
OwnerID: r.OwnerID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
BannerImage: r.BannerImage.String,
|
||||
Persona: r.Persona.String,
|
||||
IsActive: r.IsActive,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
||||
row, err := s.queries.UpdatePractice(ctx, dbgen.UpdatePracticeParams{
|
||||
ID: p.ID,
|
||||
Title: p.Title,
|
||||
Description: pgtype.Text{String: p.Description, Valid: p.Description != ""},
|
||||
BannerImage: pgtype.Text{String: p.BannerImage, Valid: p.BannerImage != ""},
|
||||
Persona: pgtype.Text{String: p.Persona, Valid: p.Persona != ""},
|
||||
IsActive: p.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Practice{}, err
|
||||
}
|
||||
return domain.Practice{
|
||||
ID: row.ID,
|
||||
OwnerType: row.OwnerType,
|
||||
OwnerID: row.OwnerID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
BannerImage: row.BannerImage.String,
|
||||
Persona: row.Persona.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivatePractice(ctx context.Context, id int64) error {
|
||||
return s.queries.DeactivatePractice(ctx, id)
|
||||
}
|
||||
|
||||
// Practice question methods
|
||||
func (s *Store) CreatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
||||
row, err := s.queries.CreatePracticeQuestion(ctx, dbgen.CreatePracticeQuestionParams{
|
||||
PracticeID: qn.PracticeID,
|
||||
Question: qn.Question,
|
||||
QuestionVoicePrompt: pgtype.Text{String: qn.QuestionVoicePrompt, Valid: qn.QuestionVoicePrompt != ""},
|
||||
SampleAnswerVoicePrompt: pgtype.Text{String: qn.SampleAnswerVoicePrompt, Valid: qn.SampleAnswerVoicePrompt != ""},
|
||||
SampleAnswer: pgtype.Text{String: qn.SampleAnswer, Valid: qn.SampleAnswer != ""},
|
||||
Tips: pgtype.Text{String: qn.Tips, Valid: qn.Tips != ""},
|
||||
Type: qn.Type,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.PracticeQuestion{}, err
|
||||
}
|
||||
return domain.PracticeQuestion{
|
||||
ID: row.ID,
|
||||
PracticeID: row.PracticeID,
|
||||
Question: row.Question,
|
||||
QuestionVoicePrompt: row.QuestionVoicePrompt.String,
|
||||
SampleAnswerVoicePrompt: row.SampleAnswerVoicePrompt.String,
|
||||
SampleAnswer: row.SampleAnswer.String,
|
||||
Tips: row.Tips.String,
|
||||
Type: row.Type,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetPracticeQuestionByID(ctx context.Context, id int64) (domain.PracticeQuestion, error) {
|
||||
row, err := s.queries.GetPracticeQuestionByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.PracticeQuestion{}, err
|
||||
}
|
||||
return domain.PracticeQuestion{
|
||||
ID: row.ID,
|
||||
PracticeID: row.PracticeID,
|
||||
Question: row.Question,
|
||||
QuestionVoicePrompt: row.QuestionVoicePrompt.String,
|
||||
SampleAnswerVoicePrompt: row.SampleAnswerVoicePrompt.String,
|
||||
SampleAnswer: row.SampleAnswer.String,
|
||||
Tips: row.Tips.String,
|
||||
Type: row.Type,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListPracticeQuestions(ctx context.Context, practiceID int64) ([]domain.PracticeQuestion, error) {
|
||||
rows, err := s.queries.ListPracticeQuestions(ctx, practiceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([]domain.PracticeQuestion, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.PracticeQuestion{
|
||||
ID: r.ID,
|
||||
PracticeID: r.PracticeID,
|
||||
Question: r.Question,
|
||||
QuestionVoicePrompt: r.QuestionVoicePrompt.String,
|
||||
SampleAnswerVoicePrompt: r.SampleAnswerVoicePrompt.String,
|
||||
SampleAnswer: r.SampleAnswer.String,
|
||||
Tips: r.Tips.String,
|
||||
Type: r.Type,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
||||
row, err := s.queries.UpdatePracticeQuestion(ctx, dbgen.UpdatePracticeQuestionParams{
|
||||
ID: qn.ID,
|
||||
Question: qn.Question,
|
||||
QuestionVoicePrompt: pgtype.Text{String: qn.QuestionVoicePrompt, Valid: qn.QuestionVoicePrompt != ""},
|
||||
SampleAnswerVoicePrompt: pgtype.Text{String: qn.SampleAnswerVoicePrompt, Valid: qn.SampleAnswerVoicePrompt != ""},
|
||||
SampleAnswer: pgtype.Text{String: qn.SampleAnswer, Valid: qn.SampleAnswer != ""},
|
||||
Tips: pgtype.Text{String: qn.Tips, Valid: qn.Tips != ""},
|
||||
Type: qn.Type,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.PracticeQuestion{}, err
|
||||
}
|
||||
return domain.PracticeQuestion{
|
||||
ID: row.ID,
|
||||
PracticeID: row.PracticeID,
|
||||
Question: row.Question,
|
||||
QuestionVoicePrompt: row.QuestionVoicePrompt.String,
|
||||
SampleAnswerVoicePrompt: row.SampleAnswerVoicePrompt.String,
|
||||
SampleAnswer: row.SampleAnswer.String,
|
||||
Tips: row.Tips.String,
|
||||
Type: row.Type,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeletePracticeQuestion(ctx context.Context, id int64) error {
|
||||
return s.queries.DeletePracticeQuestion(ctx, id)
|
||||
}
|
||||
|
||||
// Level (program level) methods
|
||||
func (s *Store) CreateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
||||
row, err := s.queries.CreateLevel(ctx, dbgen.CreateLevelParams{
|
||||
ProgramID: l.ProgramID,
|
||||
Title: l.Title,
|
||||
Description: pgtype.Text{String: l.Description, Valid: l.Description != ""},
|
||||
LevelIndex: int32(l.LevelIndex),
|
||||
NumberOfModules: int32(l.NumberOfModules),
|
||||
NumberOfPractices: int32(l.NumberOfPractices),
|
||||
NumberOfVideos: int32(l.NumberOfVideos),
|
||||
IsActive: l.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Level{}, err
|
||||
}
|
||||
return domain.Level{
|
||||
ID: row.ID,
|
||||
ProgramID: row.ProgramID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
LevelIndex: int(row.LevelIndex),
|
||||
NumberOfModules: int(row.NumberOfModules),
|
||||
NumberOfPractices: int(row.NumberOfPractices),
|
||||
NumberOfVideos: int(row.NumberOfVideos),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetLevelByID(ctx context.Context, id int64) (domain.Level, error) {
|
||||
row, err := s.queries.GetLevelByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Level{}, err
|
||||
}
|
||||
return domain.Level{
|
||||
ID: row.ID,
|
||||
ProgramID: row.ProgramID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
LevelIndex: int(row.LevelIndex),
|
||||
NumberOfModules: int(row.NumberOfModules),
|
||||
NumberOfPractices: int(row.NumberOfPractices),
|
||||
NumberOfVideos: int(row.NumberOfVideos),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListLevelsByProgram(ctx context.Context, programID int64) ([]domain.Level, error) {
|
||||
rows, err := s.queries.ListLevelsByProgram(ctx, programID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := make([]domain.Level, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
res = append(res, domain.Level{
|
||||
ID: r.ID,
|
||||
ProgramID: r.ProgramID,
|
||||
Title: r.Title,
|
||||
Description: r.Description.String,
|
||||
LevelIndex: int(r.LevelIndex),
|
||||
NumberOfModules: int(r.NumberOfModules),
|
||||
NumberOfPractices: int(r.NumberOfPractices),
|
||||
NumberOfVideos: int(r.NumberOfVideos),
|
||||
IsActive: r.IsActive,
|
||||
})
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
||||
row, err := s.queries.UpdateLevel(ctx, dbgen.UpdateLevelParams{
|
||||
ID: l.ID,
|
||||
Title: l.Title,
|
||||
Description: pgtype.Text{String: l.Description, Valid: l.Description != ""},
|
||||
LevelIndex: int32(l.LevelIndex),
|
||||
NumberOfModules: int32(l.NumberOfModules),
|
||||
NumberOfPractices: int32(l.NumberOfPractices),
|
||||
NumberOfVideos: int32(l.NumberOfVideos),
|
||||
IsActive: l.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Level{}, err
|
||||
}
|
||||
return domain.Level{
|
||||
ID: row.ID,
|
||||
ProgramID: row.ProgramID,
|
||||
Title: row.Title,
|
||||
Description: row.Description.String,
|
||||
LevelIndex: int(row.LevelIndex),
|
||||
NumberOfModules: int(row.NumberOfModules),
|
||||
NumberOfPractices: int(row.NumberOfPractices),
|
||||
NumberOfVideos: int(row.NumberOfVideos),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivateLevel(ctx context.Context, id int64) error {
|
||||
return s.queries.DeactivateLevel(ctx, id)
|
||||
return s.queries.DeleteCourseCategory(ctx, id)
|
||||
}
|
||||
|
|
|
|||
240
internal/repository/course_programs.go
Normal file
240
internal/repository/course_programs.go
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) CreateProgram(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
title string,
|
||||
description *string,
|
||||
thumbnail *string,
|
||||
displayOrder *int32,
|
||||
) (domain.Program, error) {
|
||||
|
||||
row, err := s.queries.CreateProgram(ctx, dbgen.CreateProgramParams{
|
||||
CourseID: courseID,
|
||||
Title: title,
|
||||
Description: pgtype.Text{String: *description},
|
||||
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||
Column5: displayOrder,
|
||||
Column6: true,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Program{}, err
|
||||
}
|
||||
|
||||
return domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetProgramByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Program, error) {
|
||||
|
||||
row, err := s.queries.GetProgramByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Program{}, err
|
||||
}
|
||||
|
||||
return domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetProgramsByCourse(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
) ([]domain.Program, int64, error) {
|
||||
|
||||
rows, err := s.queries.GetProgramsByCourse(ctx, courseID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var (
|
||||
programs []domain.Program
|
||||
totalCount int64
|
||||
)
|
||||
|
||||
for i, row := range rows {
|
||||
if i == 0 {
|
||||
totalCount = row.TotalCount
|
||||
}
|
||||
|
||||
programs = append(programs, domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return programs, totalCount, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListProgramsByCourse(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
) ([]domain.Program, error) {
|
||||
|
||||
rows, err := s.queries.ListProgramsByCourse(ctx, courseID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
programs := make([]domain.Program, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
programs = append(programs, domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return programs, nil
|
||||
}
|
||||
|
||||
func (s *Store) ListActivePrograms(
|
||||
ctx context.Context,
|
||||
) ([]domain.Program, error) {
|
||||
|
||||
rows, err := s.queries.ListActivePrograms(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
programs := make([]domain.Program, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
programs = append(programs, domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return programs, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateProgramPartial(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
thumbnail *string,
|
||||
displayOrder *int32,
|
||||
isActive *bool,
|
||||
) error {
|
||||
|
||||
return s.queries.UpdateProgramPartial(ctx, dbgen.UpdateProgramPartialParams{
|
||||
Title: func() string {
|
||||
if title != nil {
|
||||
return *title
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
Description: pgtype.Text{String: *description},
|
||||
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||
DisplayOrder: func() int32 {
|
||||
if displayOrder != nil {
|
||||
return *displayOrder
|
||||
}
|
||||
return 0
|
||||
}(),
|
||||
IsActive: func() bool {
|
||||
if isActive != nil {
|
||||
return *isActive
|
||||
}
|
||||
return false
|
||||
}(),
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) UpdateProgramFull(
|
||||
ctx context.Context,
|
||||
program domain.Program,
|
||||
) (domain.Program, error) {
|
||||
|
||||
row, err := s.queries.UpdateProgramFull(ctx, dbgen.UpdateProgramFullParams{
|
||||
ID: program.ID,
|
||||
CourseID: program.CourseID,
|
||||
Title: program.Title,
|
||||
Description: pgtype.Text{String: *program.Description},
|
||||
Thumbnail: pgtype.Text{String: *program.Thumbnail},
|
||||
DisplayOrder: program.DisplayOrder,
|
||||
IsActive: program.IsActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Program{}, err
|
||||
}
|
||||
|
||||
return domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeactivateProgram(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
|
||||
return s.queries.DeactivateProgram(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Store) DeleteProgram(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Program, error) {
|
||||
|
||||
row, err := s.queries.DeleteProgram(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Program{}, err
|
||||
}
|
||||
|
||||
return domain.Program{
|
||||
ID: row.ID,
|
||||
CourseID: row.CourseID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
132
internal/repository/courses.go
Normal file
132
internal/repository/courses.go
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) CreateCourse(
|
||||
ctx context.Context,
|
||||
categoryID int64,
|
||||
title string,
|
||||
description *string,
|
||||
) (domain.Course, error) {
|
||||
|
||||
row, err := s.queries.CreateCourse(ctx, dbgen.CreateCourseParams{
|
||||
CategoryID: categoryID,
|
||||
Title: title,
|
||||
Description: pgtype.Text{String: *description},
|
||||
Column4: true,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Course{}, err
|
||||
}
|
||||
|
||||
return domain.Course{
|
||||
ID: row.ID,
|
||||
CategoryID: row.CategoryID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetCourseByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Course, error) {
|
||||
|
||||
row, err := s.queries.GetCourseByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.Course{}, err
|
||||
}
|
||||
|
||||
return domain.Course{
|
||||
ID: row.ID,
|
||||
CategoryID: row.CategoryID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetCoursesByCategory(
|
||||
ctx context.Context,
|
||||
categoryID int64,
|
||||
limit int32,
|
||||
offset int32,
|
||||
) ([]domain.Course, int64, error) {
|
||||
|
||||
rows, err := s.queries.GetCoursesByCategory(ctx, dbgen.GetCoursesByCategoryParams{
|
||||
CategoryID: categoryID,
|
||||
Limit: pgtype.Int4{Int32: limit},
|
||||
Offset: pgtype.Int4{Int32: offset},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var (
|
||||
courses []domain.Course
|
||||
totalCount int64
|
||||
)
|
||||
|
||||
for i, row := range rows {
|
||||
if i == 0 {
|
||||
totalCount = row.TotalCount
|
||||
}
|
||||
|
||||
courses = append(courses, domain.Course{
|
||||
ID: row.ID,
|
||||
CategoryID: row.CategoryID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return courses, totalCount, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateCourse(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
|
||||
var (
|
||||
titleVal string
|
||||
descriptionVal string
|
||||
isActiveVal bool
|
||||
)
|
||||
|
||||
if title != nil {
|
||||
titleVal = *title
|
||||
}
|
||||
if description != nil {
|
||||
descriptionVal = *description
|
||||
}
|
||||
if isActive != nil {
|
||||
isActiveVal = *isActive
|
||||
}
|
||||
|
||||
return s.queries.UpdateCourse(ctx, dbgen.UpdateCourseParams{
|
||||
Title: titleVal,
|
||||
Description: pgtype.Text{String: descriptionVal},
|
||||
IsActive: isActiveVal,
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) DeleteCourse(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
|
||||
return s.queries.DeleteCourse(ctx, id)
|
||||
}
|
||||
90
internal/repository/learning_tree.go
Normal file
90
internal/repository/learning_tree.go
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Store) GetFullLearningTree(ctx context.Context) ([]domain.TreeCourse, error) {
|
||||
rows, err := s.queries.GetFullLearningTree(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
coursesMap := make(map[int64]*domain.TreeCourse)
|
||||
programsMap := make(map[int64]*domain.TreeProgram)
|
||||
levelsMap := make(map[int64]*domain.TreeLevel)
|
||||
|
||||
for _, row := range rows {
|
||||
// COURSE
|
||||
course, ok := coursesMap[row.CourseID]
|
||||
if !ok {
|
||||
course = &domain.TreeCourse{
|
||||
ID: row.CourseID,
|
||||
Title: row.CourseTitle,
|
||||
Programs: []domain.TreeProgram{},
|
||||
}
|
||||
coursesMap[row.CourseID] = course
|
||||
}
|
||||
|
||||
// PROGRAM
|
||||
program, ok := programsMap[row.ProgramID]
|
||||
if !ok {
|
||||
program = &domain.TreeProgram{
|
||||
ID: row.ProgramID,
|
||||
Title: row.ProgramTitle,
|
||||
Levels: []domain.TreeLevel{},
|
||||
}
|
||||
programsMap[row.ProgramID] = program
|
||||
course.Programs = append(course.Programs, *program)
|
||||
}
|
||||
|
||||
// LEVEL
|
||||
level, ok := levelsMap[row.LevelID]
|
||||
if !ok {
|
||||
level = &domain.TreeLevel{
|
||||
ID: row.LevelID,
|
||||
Title: row.LevelTitle,
|
||||
Modules: []domain.TreeModule{},
|
||||
}
|
||||
levelsMap[row.LevelID] = level
|
||||
|
||||
// Append level to its program
|
||||
for i := range course.Programs {
|
||||
if course.Programs[i].ID == row.ProgramID {
|
||||
course.Programs[i].Levels = append(course.Programs[i].Levels, *level)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MODULE (may be nil)
|
||||
if row.ModuleID.Valid {
|
||||
module := domain.TreeModule{
|
||||
ID: row.ModuleID.Int64,
|
||||
Title: row.ModuleTitle.String,
|
||||
}
|
||||
|
||||
// Append module to its level
|
||||
for i := range course.Programs {
|
||||
if course.Programs[i].ID == row.ProgramID {
|
||||
for j := range course.Programs[i].Levels {
|
||||
if course.Programs[i].Levels[j].ID == row.LevelID {
|
||||
course.Programs[i].Levels[j].Modules = append(course.Programs[i].Levels[j].Modules, module)
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flatten map to slice
|
||||
courses := make([]domain.TreeCourse, 0, len(coursesMap))
|
||||
for _, course := range coursesMap {
|
||||
courses = append(courses, *course)
|
||||
}
|
||||
|
||||
return courses, nil
|
||||
}
|
||||
112
internal/repository/level_modules.go
Normal file
112
internal/repository/level_modules.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) CreateModule(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
title string,
|
||||
content *string,
|
||||
displayOrder *int32,
|
||||
) (domain.Module, error) {
|
||||
|
||||
row, err := s.queries.CreateModule(ctx, dbgen.CreateModuleParams{
|
||||
LevelID: levelID,
|
||||
Title: title,
|
||||
Content: pgtype.Text{String: *content},
|
||||
Column4: displayOrder,
|
||||
Column5: true,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Module{}, err
|
||||
}
|
||||
|
||||
return domain.Module{
|
||||
ID: row.ID,
|
||||
LevelID: row.LevelID,
|
||||
Title: row.Title,
|
||||
Content: &row.Content.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetModulesByLevel(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) ([]domain.Module, int64, error) {
|
||||
|
||||
rows, err := s.queries.GetModulesByLevel(ctx, levelID)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var (
|
||||
modules []domain.Module
|
||||
totalCount int64
|
||||
)
|
||||
|
||||
for i, row := range rows {
|
||||
if i == 0 {
|
||||
totalCount = row.TotalCount
|
||||
}
|
||||
|
||||
modules = append(modules, domain.Module{
|
||||
ID: row.ID,
|
||||
LevelID: row.LevelID,
|
||||
Title: row.Title,
|
||||
Content: &row.Content.String,
|
||||
DisplayOrder: row.DisplayOrder,
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return modules, totalCount, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateModule(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
content *string,
|
||||
displayOrder *int32,
|
||||
isActive *bool,
|
||||
) error {
|
||||
|
||||
titleVal := ""
|
||||
if title != nil {
|
||||
titleVal = *title
|
||||
}
|
||||
|
||||
var displayOrderVal int32
|
||||
if displayOrder != nil {
|
||||
displayOrderVal = *displayOrder
|
||||
}
|
||||
|
||||
var isActiveVal bool
|
||||
if isActive != nil {
|
||||
isActiveVal = *isActive
|
||||
}
|
||||
|
||||
return s.queries.UpdateModule(ctx, dbgen.UpdateModuleParams{
|
||||
Title: titleVal,
|
||||
Content: pgtype.Text{String: *content},
|
||||
DisplayOrder: displayOrderVal,
|
||||
IsActive: isActiveVal,
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) DeleteModule(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
|
||||
return s.queries.DeleteModule(ctx, id)
|
||||
}
|
||||
161
internal/repository/module_videos.go
Normal file
161
internal/repository/module_videos.go
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) CreateModuleVideo(
|
||||
ctx context.Context,
|
||||
moduleID int64,
|
||||
title string,
|
||||
description *string,
|
||||
videoURL string,
|
||||
duration int32,
|
||||
resolution *string,
|
||||
instructorID *string,
|
||||
thumbnail *string,
|
||||
visibility *string,
|
||||
) (domain.ModuleVideo, error) {
|
||||
|
||||
row, err := s.queries.CreateModuleVideo(ctx, dbgen.CreateModuleVideoParams{
|
||||
ModuleID: moduleID,
|
||||
Title: title,
|
||||
Description: pgtype.Text{String: *description},
|
||||
VideoUrl: videoURL,
|
||||
Duration: duration,
|
||||
Resolution: pgtype.Text{String: *resolution},
|
||||
InstructorID: pgtype.Text{String: *instructorID},
|
||||
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||
Visibility: pgtype.Text{String: *visibility},
|
||||
Column10: true,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.ModuleVideo{}, err
|
||||
}
|
||||
|
||||
var publishDate *time.Time
|
||||
if row.PublishDate.Valid {
|
||||
publishDate = &row.PublishDate.Time
|
||||
}
|
||||
|
||||
return domain.ModuleVideo{
|
||||
ID: row.ID,
|
||||
ModuleID: row.ModuleID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
VideoURL: row.VideoUrl,
|
||||
Duration: row.Duration,
|
||||
Resolution: &row.Resolution.String,
|
||||
InstructorID: &row.InstructorID.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
Visibility: &row.Visibility.String,
|
||||
IsPublished: row.IsPublished,
|
||||
PublishDate: publishDate,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) PublishModuleVideo(
|
||||
ctx context.Context,
|
||||
videoID int64,
|
||||
) error {
|
||||
|
||||
return s.queries.PublishModuleVideo(ctx, videoID)
|
||||
}
|
||||
|
||||
func (s *Store) GetPublishedVideosByModule(
|
||||
ctx context.Context,
|
||||
moduleID int64,
|
||||
) ([]domain.ModuleVideo, error) {
|
||||
|
||||
rows, err := s.queries.GetPublishedVideosByModule(ctx, moduleID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
videos := make([]domain.ModuleVideo, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
|
||||
var publishDate *time.Time
|
||||
if row.PublishDate.Valid {
|
||||
publishDate = &row.PublishDate.Time
|
||||
}
|
||||
|
||||
videos = append(videos, domain.ModuleVideo{
|
||||
ID: row.ID,
|
||||
ModuleID: row.ModuleID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
VideoURL: row.VideoUrl,
|
||||
Duration: row.Duration,
|
||||
Resolution: &row.Resolution.String,
|
||||
InstructorID: &row.InstructorID.String,
|
||||
Thumbnail: &row.Thumbnail.String,
|
||||
Visibility: &row.Visibility.String,
|
||||
IsPublished: row.IsPublished,
|
||||
PublishDate: publishDate,
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return videos, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateModuleVideo(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
videoURL *string,
|
||||
duration *int32,
|
||||
resolution *string,
|
||||
visibility *string,
|
||||
thumbnail *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
|
||||
return s.queries.UpdateModuleVideo(ctx, dbgen.UpdateModuleVideoParams{
|
||||
Title: func() string {
|
||||
if title != nil {
|
||||
return *title
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
Description: pgtype.Text{String: *description},
|
||||
VideoUrl: func() string {
|
||||
if videoURL != nil {
|
||||
return *videoURL
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
Duration: func() int32 {
|
||||
if duration != nil {
|
||||
return *duration
|
||||
}
|
||||
return 0
|
||||
}(),
|
||||
Resolution: pgtype.Text{String: *resolution},
|
||||
Visibility: pgtype.Text{String: *visibility},
|
||||
Thumbnail: pgtype.Text{String: *thumbnail},
|
||||
IsActive: func() bool {
|
||||
if isActive != nil {
|
||||
return *isActive
|
||||
}
|
||||
return false
|
||||
}(),
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) DeleteModuleVideo(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
|
||||
return s.queries.DeleteModuleVideo(ctx, id)
|
||||
}
|
||||
108
internal/repository/practice_questions.go
Normal file
108
internal/repository/practice_questions.go
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) CreatePracticeQuestion(
|
||||
ctx context.Context,
|
||||
practiceID int64,
|
||||
question string,
|
||||
questionVoicePrompt *string,
|
||||
sampleAnswerVoicePrompt *string,
|
||||
sampleAnswer *string,
|
||||
tips *string,
|
||||
qType string,
|
||||
) (domain.PracticeQuestion, error) {
|
||||
|
||||
row, err := s.queries.CreatePracticeQuestion(ctx, dbgen.CreatePracticeQuestionParams{
|
||||
PracticeID: practiceID,
|
||||
Question: question,
|
||||
QuestionVoicePrompt: pgtype.Text{String: *questionVoicePrompt},
|
||||
SampleAnswerVoicePrompt: pgtype.Text{String: *sampleAnswerVoicePrompt},
|
||||
SampleAnswer: pgtype.Text{String: *sampleAnswer},
|
||||
Tips: pgtype.Text{String: *tips},
|
||||
Type: qType,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.PracticeQuestion{}, err
|
||||
}
|
||||
|
||||
return domain.PracticeQuestion{
|
||||
ID: row.ID,
|
||||
PracticeID: row.PracticeID,
|
||||
Question: row.Question,
|
||||
QuestionVoicePrompt: &row.QuestionVoicePrompt.String,
|
||||
SampleAnswerVoicePrompt: &row.SampleAnswerVoicePrompt.String,
|
||||
SampleAnswer: &row.SampleAnswer.String,
|
||||
Tips: &row.Tips.String,
|
||||
Type: row.Type,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetQuestionsByPractice(
|
||||
ctx context.Context,
|
||||
practiceID int64,
|
||||
) ([]domain.PracticeQuestion, error) {
|
||||
|
||||
rows, err := s.queries.GetQuestionsByPractice(ctx, practiceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
questions := make([]domain.PracticeQuestion, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
questions = append(questions, domain.PracticeQuestion{
|
||||
ID: row.ID,
|
||||
PracticeID: row.PracticeID,
|
||||
Question: row.Question,
|
||||
QuestionVoicePrompt: &row.QuestionVoicePrompt.String,
|
||||
SampleAnswerVoicePrompt: &row.SampleAnswerVoicePrompt.String,
|
||||
SampleAnswer: &row.SampleAnswer.String,
|
||||
Tips: &row.Tips.String,
|
||||
Type: row.Type,
|
||||
})
|
||||
}
|
||||
|
||||
return questions, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdatePracticeQuestion(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
question *string,
|
||||
sampleAnswer *string,
|
||||
tips *string,
|
||||
qType *string,
|
||||
) error {
|
||||
|
||||
return s.queries.UpdatePracticeQuestion(ctx, dbgen.UpdatePracticeQuestionParams{
|
||||
Question: func() string {
|
||||
if question != nil {
|
||||
return *question
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
SampleAnswer: pgtype.Text{String: *sampleAnswer},
|
||||
Tips: pgtype.Text{String: *tips},
|
||||
Type: func() string {
|
||||
if qType != nil {
|
||||
return *qType
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) DeletePracticeQuestion(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
|
||||
return s.queries.DeletePracticeQuestion(ctx, id)
|
||||
}
|
||||
114
internal/repository/practices.go
Normal file
114
internal/repository/practices.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) CreatePractice(
|
||||
ctx context.Context,
|
||||
ownerType string,
|
||||
ownerID int64,
|
||||
title string,
|
||||
description *string,
|
||||
bannerImage *string,
|
||||
persona *string,
|
||||
isActive *bool,
|
||||
) (domain.Practice, error) {
|
||||
|
||||
row, err := s.queries.CreatePractice(ctx, dbgen.CreatePracticeParams{
|
||||
OwnerType: ownerType,
|
||||
OwnerID: ownerID,
|
||||
Title: title,
|
||||
Description: pgtype.Text{String: *description},
|
||||
BannerImage: pgtype.Text{String: *bannerImage},
|
||||
Persona: pgtype.Text{String: *persona},
|
||||
Column7: isActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Practice{}, err
|
||||
}
|
||||
|
||||
return domain.Practice{
|
||||
ID: row.ID,
|
||||
OwnerType: row.OwnerType,
|
||||
OwnerID: row.OwnerID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
BannerImage: &row.BannerImage.String,
|
||||
Persona: &row.Persona.String,
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetPracticesByOwner(
|
||||
ctx context.Context,
|
||||
ownerType string,
|
||||
ownerID int64,
|
||||
) ([]domain.Practice, error) {
|
||||
|
||||
rows, err := s.queries.GetPracticesByOwner(ctx, dbgen.GetPracticesByOwnerParams{
|
||||
OwnerType: ownerType,
|
||||
OwnerID: ownerID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
practices := make([]domain.Practice, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
practices = append(practices, domain.Practice{
|
||||
ID: row.ID,
|
||||
OwnerType: row.OwnerType,
|
||||
OwnerID: row.OwnerID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
BannerImage: &row.BannerImage.String,
|
||||
Persona: &row.Persona.String,
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return practices, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdatePractice(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
bannerImage *string,
|
||||
persona *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
|
||||
return s.queries.UpdatePractice(ctx, dbgen.UpdatePracticeParams{
|
||||
Title: func() string {
|
||||
if title != nil {
|
||||
return *title
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
Description: pgtype.Text{String: *description},
|
||||
BannerImage: pgtype.Text{String: *bannerImage},
|
||||
Persona: pgtype.Text{String: *persona},
|
||||
IsActive: func() bool {
|
||||
if isActive != nil {
|
||||
return *isActive
|
||||
}
|
||||
return false
|
||||
}(),
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) DeletePractice(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
|
||||
return s.queries.DeletePractice(ctx, id)
|
||||
}
|
||||
125
internal/repository/program_levels.go
Normal file
125
internal/repository/program_levels.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
dbgen "Yimaru-Backend/gen/db"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func (s *Store) CreateLevel(
|
||||
ctx context.Context,
|
||||
programID int64,
|
||||
title string,
|
||||
description *string,
|
||||
levelIndex int,
|
||||
isActive *bool,
|
||||
) (domain.Level, error) {
|
||||
|
||||
row, err := s.queries.CreateLevel(ctx, dbgen.CreateLevelParams{
|
||||
ProgramID: programID,
|
||||
Title: title,
|
||||
Description: pgtype.Text{String: *description},
|
||||
LevelIndex: int32(levelIndex),
|
||||
Column5: isActive,
|
||||
})
|
||||
if err != nil {
|
||||
return domain.Level{}, err
|
||||
}
|
||||
|
||||
return domain.Level{
|
||||
ID: row.ID,
|
||||
ProgramID: row.ProgramID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
LevelIndex: int(row.LevelIndex),
|
||||
NumberOfModules: int(row.NumberOfModules),
|
||||
NumberOfPractices: int(row.NumberOfPractices),
|
||||
NumberOfVideos: int(row.NumberOfVideos),
|
||||
IsActive: row.IsActive,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetLevelsByProgram(
|
||||
ctx context.Context,
|
||||
programID int64,
|
||||
) ([]domain.Level, error) {
|
||||
|
||||
rows, err := s.queries.GetLevelsByProgram(ctx, programID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
levels := make([]domain.Level, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
levels = append(levels, domain.Level{
|
||||
ID: row.ID,
|
||||
ProgramID: row.ProgramID,
|
||||
Title: row.Title,
|
||||
Description: &row.Description.String,
|
||||
LevelIndex: int(row.LevelIndex),
|
||||
NumberOfModules: int(row.NumberOfModules),
|
||||
NumberOfPractices: int(row.NumberOfPractices),
|
||||
NumberOfVideos: int(row.NumberOfVideos),
|
||||
IsActive: row.IsActive,
|
||||
})
|
||||
}
|
||||
|
||||
return levels, nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateLevel(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
levelIndex *int,
|
||||
isActive *bool,
|
||||
) error {
|
||||
|
||||
return s.queries.UpdateLevel(ctx, dbgen.UpdateLevelParams{
|
||||
Title: func() string {
|
||||
if title != nil {
|
||||
return *title
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
Description: pgtype.Text{String: *description},
|
||||
LevelIndex: int32(*levelIndex),
|
||||
IsActive: *isActive,
|
||||
ID: id,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) IncrementLevelModuleCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
|
||||
return s.queries.IncrementLevelModuleCount(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Store) IncrementLevelPracticeCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
|
||||
return s.queries.IncrementLevelPracticeCount(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Store) IncrementLevelVideoCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
|
||||
return s.queries.IncrementLevelVideoCount(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Store) DeleteLevel(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
|
||||
return s.queries.DeleteLevel(ctx, levelID)
|
||||
}
|
||||
44
internal/services/course_management/course_catagories.go
Normal file
44
internal/services/course_management/course_catagories.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreateCourseCategory(
|
||||
ctx context.Context,
|
||||
name string,
|
||||
) (domain.CourseCategory, error) {
|
||||
return s.courseStore.CreateCourseCategory(ctx, name)
|
||||
}
|
||||
|
||||
func (s *Service) GetCourseCategoryByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.CourseCategory, error) {
|
||||
return s.courseStore.GetCourseCategoryByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) GetAllCourseCategories(
|
||||
ctx context.Context,
|
||||
limit int32,
|
||||
offset int32,
|
||||
) ([]domain.CourseCategory, int64, error) {
|
||||
return s.courseStore.GetAllCourseCategories(ctx, limit, offset)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateCourseCategory(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
name *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
return s.courseStore.UpdateCourseCategory(ctx, id, name, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteCourseCategory(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
return s.courseStore.DeleteCourseCategory(ctx, id)
|
||||
}
|
||||
77
internal/services/course_management/course_programs.go
Normal file
77
internal/services/course_management/course_programs.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreateProgram(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
title string,
|
||||
description *string,
|
||||
thumbnail *string,
|
||||
displayOrder *int32,
|
||||
) (domain.Program, error) {
|
||||
return s.courseStore.CreateProgram(ctx, courseID, title, description, thumbnail, displayOrder)
|
||||
}
|
||||
|
||||
func (s *Service) GetProgramByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Program, error) {
|
||||
return s.courseStore.GetProgramByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) GetProgramsByCourse(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
) ([]domain.Program, int64, error) {
|
||||
return s.courseStore.GetProgramsByCourse(ctx, courseID)
|
||||
}
|
||||
|
||||
func (s *Service) ListProgramsByCourse(
|
||||
ctx context.Context,
|
||||
courseID int64,
|
||||
) ([]domain.Program, error) {
|
||||
return s.courseStore.ListProgramsByCourse(ctx, courseID)
|
||||
}
|
||||
|
||||
func (s *Service) ListActivePrograms(
|
||||
ctx context.Context,
|
||||
) ([]domain.Program, error) {
|
||||
return s.courseStore.ListActivePrograms(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateProgramPartial(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
thumbnail *string,
|
||||
displayOrder *int32,
|
||||
isActive *bool,
|
||||
) error {
|
||||
return s.courseStore.UpdateProgramPartial(ctx, id, title, description, thumbnail, displayOrder, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateProgramFull(
|
||||
ctx context.Context,
|
||||
program domain.Program,
|
||||
) (domain.Program, error) {
|
||||
return s.courseStore.UpdateProgramFull(ctx, program)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivateProgram(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
return s.courseStore.DeactivateProgram(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteProgram(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Program, error) {
|
||||
return s.courseStore.DeleteProgram(ctx, id)
|
||||
}
|
||||
48
internal/services/course_management/courses.go
Normal file
48
internal/services/course_management/courses.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreateCourse(
|
||||
ctx context.Context,
|
||||
categoryID int64,
|
||||
title string,
|
||||
description *string,
|
||||
) (domain.Course, error) {
|
||||
return s.courseStore.CreateCourse(ctx, categoryID, title, description)
|
||||
}
|
||||
|
||||
func (s *Service) GetCourseByID(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) (domain.Course, error) {
|
||||
return s.courseStore.GetCourseByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) GetCoursesByCategory(
|
||||
ctx context.Context,
|
||||
categoryID int64,
|
||||
limit int32,
|
||||
offset int32,
|
||||
) ([]domain.Course, int64, error) {
|
||||
return s.courseStore.GetCoursesByCategory(ctx, categoryID, limit, offset)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateCourse(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
return s.courseStore.UpdateCourse(ctx, id, title, description, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteCourse(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
return s.courseStore.DeleteCourse(ctx, id)
|
||||
}
|
||||
10
internal/services/course_management/learning_tree.go
Normal file
10
internal/services/course_management/learning_tree.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) GetFullLearningTree(ctx context.Context) ([]domain.TreeCourse, error) {
|
||||
return s.courseStore.GetFullLearningTree(ctx)
|
||||
}
|
||||
41
internal/services/course_management/level_modules.go
Normal file
41
internal/services/course_management/level_modules.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreateModule(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
title string,
|
||||
content *string,
|
||||
displayOrder *int32,
|
||||
) (domain.Module, error) {
|
||||
return s.courseStore.CreateModule(ctx, levelID, title, content, displayOrder)
|
||||
}
|
||||
|
||||
func (s *Service) GetModulesByLevel(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) ([]domain.Module, int64, error) {
|
||||
return s.courseStore.GetModulesByLevel(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateModule(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
content *string,
|
||||
displayOrder *int32,
|
||||
isActive *bool,
|
||||
) error {
|
||||
return s.courseStore.UpdateModule(ctx, id, title, content, displayOrder, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteModule(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
return s.courseStore.DeleteModule(ctx, id)
|
||||
}
|
||||
57
internal/services/course_management/module_videos.go
Normal file
57
internal/services/course_management/module_videos.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreateModuleVideo(
|
||||
ctx context.Context,
|
||||
moduleID int64,
|
||||
title string,
|
||||
description *string,
|
||||
videoURL string,
|
||||
duration int32,
|
||||
resolution *string,
|
||||
instructorID *string,
|
||||
thumbnail *string,
|
||||
visibility *string,
|
||||
) (domain.ModuleVideo, error) {
|
||||
return s.courseStore.CreateModuleVideo(ctx, moduleID, title, description, videoURL, duration, resolution, instructorID, thumbnail, visibility)
|
||||
}
|
||||
|
||||
func (s *Service) PublishModuleVideo(
|
||||
ctx context.Context,
|
||||
videoID int64,
|
||||
) error {
|
||||
return s.courseStore.PublishModuleVideo(ctx, videoID)
|
||||
}
|
||||
|
||||
func (s *Service) GetPublishedVideosByModule(
|
||||
ctx context.Context,
|
||||
moduleID int64,
|
||||
) ([]domain.ModuleVideo, error) {
|
||||
return s.courseStore.GetPublishedVideosByModule(ctx, moduleID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateModuleVideo(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
videoURL *string,
|
||||
duration *int32,
|
||||
resolution *string,
|
||||
visibility *string,
|
||||
thumbnail *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
return s.courseStore.UpdateModuleVideo(ctx, id, title, description, videoURL, duration, resolution, visibility, thumbnail, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteModuleVideo(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
return s.courseStore.DeleteModuleVideo(ctx, id)
|
||||
}
|
||||
44
internal/services/course_management/practice_questions.go
Normal file
44
internal/services/course_management/practice_questions.go
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreatePracticeQuestion(
|
||||
ctx context.Context,
|
||||
practiceID int64,
|
||||
question string,
|
||||
questionVoicePrompt *string,
|
||||
sampleAnswerVoicePrompt *string,
|
||||
sampleAnswer *string,
|
||||
tips *string,
|
||||
qType string,
|
||||
) (domain.PracticeQuestion, error) {
|
||||
return s.courseStore.CreatePracticeQuestion(ctx, practiceID, question, questionVoicePrompt, sampleAnswerVoicePrompt, sampleAnswer, tips, qType)
|
||||
}
|
||||
|
||||
func (s *Service) GetQuestionsByPractice(
|
||||
ctx context.Context,
|
||||
practiceID int64,
|
||||
) ([]domain.PracticeQuestion, error) {
|
||||
return s.courseStore.GetQuestionsByPractice(ctx, practiceID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdatePracticeQuestion(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
question *string,
|
||||
sampleAnswer *string,
|
||||
tips *string,
|
||||
qType *string,
|
||||
) error {
|
||||
return s.courseStore.UpdatePracticeQuestion(ctx, id, question, sampleAnswer, tips, qType)
|
||||
}
|
||||
|
||||
func (s *Service) DeletePracticeQuestion(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
return s.courseStore.DeletePracticeQuestion(ctx, id)
|
||||
}
|
||||
46
internal/services/course_management/practices.go
Normal file
46
internal/services/course_management/practices.go
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreatePractice(
|
||||
ctx context.Context,
|
||||
ownerType string,
|
||||
ownerID int64,
|
||||
title string,
|
||||
description *string,
|
||||
bannerImage *string,
|
||||
persona *string,
|
||||
isActive *bool,
|
||||
) (domain.Practice, error) {
|
||||
return s.courseStore.CreatePractice(ctx, ownerType, ownerID, title, description, bannerImage, persona, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) GetPracticesByOwner(
|
||||
ctx context.Context,
|
||||
ownerType string,
|
||||
ownerID int64,
|
||||
) ([]domain.Practice, error) {
|
||||
return s.courseStore.GetPracticesByOwner(ctx, ownerType, ownerID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdatePractice(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
bannerImage *string,
|
||||
persona *string,
|
||||
isActive *bool,
|
||||
) error {
|
||||
return s.courseStore.UpdatePractice(ctx, id, title, description, bannerImage, persona, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) DeletePractice(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
) error {
|
||||
return s.courseStore.DeletePractice(ctx, id)
|
||||
}
|
||||
63
internal/services/course_management/program_levels.go
Normal file
63
internal/services/course_management/program_levels.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"context"
|
||||
)
|
||||
|
||||
func (s *Service) CreateLevel(
|
||||
ctx context.Context,
|
||||
programID int64,
|
||||
title string,
|
||||
description *string,
|
||||
levelIndex int,
|
||||
isActive *bool,
|
||||
) (domain.Level, error) {
|
||||
return s.courseStore.CreateLevel(ctx, programID, title, description, levelIndex, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) GetLevelsByProgram(
|
||||
ctx context.Context,
|
||||
programID int64,
|
||||
) ([]domain.Level, error) {
|
||||
return s.courseStore.GetLevelsByProgram(ctx, programID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateLevel(
|
||||
ctx context.Context,
|
||||
id int64,
|
||||
title *string,
|
||||
description *string,
|
||||
levelIndex *int,
|
||||
isActive *bool,
|
||||
) error {
|
||||
return s.courseStore.UpdateLevel(ctx, id, title, description, levelIndex, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) IncrementLevelModuleCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
return s.courseStore.IncrementLevelModuleCount(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Service) IncrementLevelPracticeCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
return s.courseStore.IncrementLevelPracticeCount(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Service) IncrementLevelVideoCount(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
return s.courseStore.IncrementLevelVideoCount(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteLevel(
|
||||
ctx context.Context,
|
||||
levelID int64,
|
||||
) error {
|
||||
return s.courseStore.DeleteLevel(ctx, levelID)
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
package course_management
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"Yimaru-Backend/internal/config"
|
||||
"Yimaru-Backend/internal/domain"
|
||||
"Yimaru-Backend/internal/ports"
|
||||
notificationservice "Yimaru-Backend/internal/services/notification"
|
||||
)
|
||||
|
|
@ -32,183 +29,3 @@ func NewService(
|
|||
config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// Course category methods
|
||||
func (s *Service) CreateCourseCategory(ctx context.Context, name string) (domain.CourseCategory, error) {
|
||||
return s.courseStore.CreateCourseCategory(ctx, name)
|
||||
}
|
||||
|
||||
func (s *Service) GetCourseCategoryByID(ctx context.Context, id int64) (domain.CourseCategory, error) {
|
||||
return s.courseStore.GetCourseCategoryByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListActiveCourseCategories(ctx context.Context) ([]domain.CourseCategory, error) {
|
||||
return s.courseStore.ListActiveCourseCategories(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateCourseCategory(ctx context.Context, id int64, name string, isActive bool) (domain.CourseCategory, error) {
|
||||
return s.courseStore.UpdateCourseCategory(ctx, id, name, isActive)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivateCourseCategory(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeactivateCourseCategory(ctx, id)
|
||||
}
|
||||
|
||||
// Courses
|
||||
func (s *Service) CreateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
||||
return s.courseStore.CreateCourse(ctx, c)
|
||||
}
|
||||
|
||||
func (s *Service) GetCourseByID(ctx context.Context, id int64) (domain.Course, error) {
|
||||
return s.courseStore.GetCourseByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListCoursesByCategory(ctx context.Context, categoryID int64) ([]domain.Course, error) {
|
||||
return s.courseStore.ListCoursesByCategory(ctx, categoryID)
|
||||
}
|
||||
|
||||
func (s *Service) ListActiveCourses(ctx context.Context) ([]domain.Course, error) {
|
||||
return s.courseStore.ListActiveCourses(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateCourse(ctx context.Context, c domain.Course) (domain.Course, error) {
|
||||
return s.courseStore.UpdateCourse(ctx, c)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivateCourse(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeactivateCourse(ctx, id)
|
||||
}
|
||||
|
||||
// Programs
|
||||
func (s *Service) CreateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
||||
return s.courseStore.CreateProgram(ctx, p)
|
||||
}
|
||||
|
||||
func (s *Service) GetProgramByID(ctx context.Context, id int64) (domain.Program, error) {
|
||||
return s.courseStore.GetProgramByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListProgramsByCourse(ctx context.Context, courseID int64) ([]domain.Program, error) {
|
||||
return s.courseStore.ListProgramsByCourse(ctx, courseID)
|
||||
}
|
||||
|
||||
func (s *Service) ListActivePrograms(ctx context.Context) ([]domain.Program, error) {
|
||||
return s.courseStore.ListActivePrograms(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateProgram(ctx context.Context, p domain.Program) (domain.Program, error) {
|
||||
return s.courseStore.UpdateProgram(ctx, p)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivateProgram(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeactivateProgram(ctx, id)
|
||||
}
|
||||
|
||||
// Modules
|
||||
func (s *Service) CreateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
||||
return s.courseStore.CreateModule(ctx, m)
|
||||
}
|
||||
|
||||
func (s *Service) GetModuleByID(ctx context.Context, id int64) (domain.Module, error) {
|
||||
return s.courseStore.GetModuleByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListModulesByLevel(ctx context.Context, levelID int64) ([]domain.Module, error) {
|
||||
return s.courseStore.ListModulesByLevel(ctx, levelID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateModule(ctx context.Context, m domain.Module) (domain.Module, error) {
|
||||
return s.courseStore.UpdateModule(ctx, m)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivateModule(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeactivateModule(ctx, id)
|
||||
}
|
||||
|
||||
// Module videos
|
||||
func (s *Service) CreateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
||||
return s.courseStore.CreateModuleVideo(ctx, v)
|
||||
}
|
||||
|
||||
func (s *Service) GetModuleVideoByID(ctx context.Context, id int64) (domain.ModuleVideo, error) {
|
||||
return s.courseStore.GetModuleVideoByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListAllVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
||||
return s.courseStore.ListAllVideosByModule(ctx, moduleID)
|
||||
}
|
||||
|
||||
func (s *Service) ListPublishedVideosByModule(ctx context.Context, moduleID int64) ([]domain.ModuleVideo, error) {
|
||||
return s.courseStore.ListPublishedVideosByModule(ctx, moduleID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateModuleVideo(ctx context.Context, v domain.ModuleVideo) (domain.ModuleVideo, error) {
|
||||
return s.courseStore.UpdateModuleVideo(ctx, v)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivateModuleVideo(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeactivateModuleVideo(ctx, id)
|
||||
}
|
||||
|
||||
// Practices
|
||||
func (s *Service) CreatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
||||
return s.courseStore.CreatePractice(ctx, p)
|
||||
}
|
||||
|
||||
func (s *Service) GetPracticeByID(ctx context.Context, id int64) (domain.Practice, error) {
|
||||
return s.courseStore.GetPracticeByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListPracticesByOwner(ctx context.Context, ownerType string, ownerID int64) ([]domain.Practice, error) {
|
||||
return s.courseStore.ListPracticesByOwner(ctx, ownerType, ownerID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdatePractice(ctx context.Context, p domain.Practice) (domain.Practice, error) {
|
||||
return s.courseStore.UpdatePractice(ctx, p)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivatePractice(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeactivatePractice(ctx, id)
|
||||
}
|
||||
|
||||
// Practice questions
|
||||
func (s *Service) CreatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
||||
return s.courseStore.CreatePracticeQuestion(ctx, qn)
|
||||
}
|
||||
|
||||
func (s *Service) GetPracticeQuestionByID(ctx context.Context, id int64) (domain.PracticeQuestion, error) {
|
||||
return s.courseStore.GetPracticeQuestionByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListPracticeQuestions(ctx context.Context, practiceID int64) ([]domain.PracticeQuestion, error) {
|
||||
return s.courseStore.ListPracticeQuestions(ctx, practiceID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdatePracticeQuestion(ctx context.Context, qn domain.PracticeQuestion) (domain.PracticeQuestion, error) {
|
||||
return s.courseStore.UpdatePracticeQuestion(ctx, qn)
|
||||
}
|
||||
|
||||
func (s *Service) DeletePracticeQuestion(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeletePracticeQuestion(ctx, id)
|
||||
}
|
||||
|
||||
// Levels
|
||||
func (s *Service) CreateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
||||
return s.courseStore.CreateLevel(ctx, l)
|
||||
}
|
||||
|
||||
func (s *Service) GetLevelByID(ctx context.Context, id int64) (domain.Level, error) {
|
||||
return s.courseStore.GetLevelByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListLevelsByProgram(ctx context.Context, programID int64) ([]domain.Level, error) {
|
||||
return s.courseStore.ListLevelsByProgram(ctx, programID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateLevel(ctx context.Context, l domain.Level) (domain.Level, error) {
|
||||
return s.courseStore.UpdateLevel(ctx, l)
|
||||
}
|
||||
|
||||
func (s *Service) DeactivateLevel(ctx context.Context, id int64) error {
|
||||
return s.courseStore.DeactivateLevel(ctx, id)
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -125,31 +125,68 @@ func (a *App) initAppRoutes() {
|
|||
// )
|
||||
|
||||
// Course Management Routes
|
||||
groupV1.Post("/course-categories", h.CreateCourseCategory)
|
||||
groupV1.Get("/course-categories", h.ListActiveCourseCategories)
|
||||
groupV1.Get("/course-categories/:id", h.GetCourseCategoryByID)
|
||||
groupV1.Put("/course-categories/:id", h.UpdateCourseCategory)
|
||||
groupV1.Post("/course-categories/:id/deactivate", h.DeactivateCourseCategory)
|
||||
|
||||
groupV1.Post("/courses", h.CreateCourse)
|
||||
groupV1.Get("/courses", h.ListActiveCourses)
|
||||
groupV1.Get("/courses/:id", h.GetCourseByID)
|
||||
groupV1.Put("/courses/:id", h.UpdateCourse)
|
||||
groupV1.Post("/courses/:id/deactivate", h.DeactivateCourse)
|
||||
groupV1.Get("/course-categories/:category_id/courses", h.ListCoursesByCategory)
|
||||
// Course Categories
|
||||
groupV1.Post("/course-management/categories", a.authMiddleware, h.CreateCourseCategory)
|
||||
groupV1.Get("/course-management/categories", a.authMiddleware, h.GetAllCourseCategories)
|
||||
groupV1.Get("/course-management/categories/:id", a.authMiddleware, h.GetCourseCategoryByID)
|
||||
groupV1.Put("/course-management/categories/:id", a.authMiddleware, h.UpdateCourseCategory)
|
||||
groupV1.Delete("/course-management/categories/:id", a.authMiddleware, h.DeleteCourseCategory)
|
||||
|
||||
groupV1.Post("/courses/:course_id/programs", h.CreateProgram)
|
||||
groupV1.Get("/courses/:course_id/programs", h.ListProgramsByCourse)
|
||||
// Courses
|
||||
groupV1.Post("/course-management/courses", a.authMiddleware, h.CreateCourse)
|
||||
groupV1.Get("/course-management/courses/:id", a.authMiddleware, h.GetCourseByID)
|
||||
groupV1.Get("/course-management/categories/:categoryId/courses", a.authMiddleware, h.GetCoursesByCategory)
|
||||
groupV1.Put("/course-management/courses/:id", a.authMiddleware, h.UpdateCourse)
|
||||
groupV1.Delete("/course-management/courses/:id", a.authMiddleware, h.DeleteCourse)
|
||||
|
||||
groupV1.Post("/modules", h.CreateModule)
|
||||
groupV1.Get("/levels/:level_id/modules", h.ListModulesByLevel)
|
||||
// Programs
|
||||
groupV1.Post("/course-management/programs", a.authMiddleware, h.CreateProgram)
|
||||
groupV1.Get("/course-management/programs/:id", a.authMiddleware, h.GetProgramByID)
|
||||
groupV1.Get("/course-management/courses/:courseId/programs", a.authMiddleware, h.GetProgramsByCourse)
|
||||
groupV1.Get("/course-management/courses/:courseId/programs/list", a.authMiddleware, h.ListProgramsByCourse)
|
||||
groupV1.Get("/course-management/programs/active", a.authMiddleware, h.ListActivePrograms)
|
||||
groupV1.Patch("/course-management/programs/:id", a.authMiddleware, h.UpdateProgramPartial)
|
||||
groupV1.Put("/course-management/programs/:id/full", a.authMiddleware, h.UpdateProgramFull)
|
||||
groupV1.Put("/course-management/programs/:id/deactivate", a.authMiddleware, h.DeactivateProgram)
|
||||
groupV1.Delete("/course-management/programs/:id", a.authMiddleware, h.DeleteProgram)
|
||||
|
||||
groupV1.Post("/module-videos", h.CreateModuleVideo)
|
||||
// Levels
|
||||
groupV1.Post("/course-management/levels", a.authMiddleware, h.CreateLevel)
|
||||
groupV1.Get("/course-management/programs/:programId/levels", a.authMiddleware, h.GetLevelsByProgram)
|
||||
groupV1.Put("/course-management/levels/:id", a.authMiddleware, h.UpdateLevel)
|
||||
groupV1.Put("/course-management/levels/:levelId/increment-module", a.authMiddleware, h.IncrementLevelModuleCount)
|
||||
groupV1.Put("/course-management/levels/:levelId/increment-practice", a.authMiddleware, h.IncrementLevelPracticeCount)
|
||||
groupV1.Put("/course-management/levels/:levelId/increment-video", a.authMiddleware, h.IncrementLevelVideoCount)
|
||||
groupV1.Delete("/course-management/levels/:levelId", a.authMiddleware, h.DeleteLevel)
|
||||
|
||||
groupV1.Post("/practices", h.CreatePractice)
|
||||
groupV1.Post("/practice-questions", h.CreatePracticeQuestion)
|
||||
// Modules
|
||||
groupV1.Post("/course-management/modules", a.authMiddleware, h.CreateModule)
|
||||
groupV1.Get("/course-management/levels/:levelId/modules", a.authMiddleware, h.GetModulesByLevel)
|
||||
groupV1.Put("/course-management/modules/:id", a.authMiddleware, h.UpdateModule)
|
||||
groupV1.Delete("/course-management/modules/:id", a.authMiddleware, h.DeleteModule)
|
||||
|
||||
groupV1.Post("/levels", h.CreateLevel)
|
||||
// Module Videos
|
||||
groupV1.Post("/course-management/videos", a.authMiddleware, h.CreateModuleVideo)
|
||||
groupV1.Put("/course-management/videos/:videoId/publish", a.authMiddleware, h.PublishModuleVideo)
|
||||
groupV1.Get("/course-management/modules/:moduleId/videos/published", a.authMiddleware, h.GetPublishedVideosByModule)
|
||||
groupV1.Put("/course-management/videos/:id", a.authMiddleware, h.UpdateModuleVideo)
|
||||
groupV1.Delete("/course-management/videos/:id", a.authMiddleware, h.DeleteModuleVideo)
|
||||
|
||||
// Practices
|
||||
groupV1.Post("/course-management/practices", a.authMiddleware, h.CreatePractice)
|
||||
groupV1.Get("/course-management/owners/:ownerType/:ownerId/practices", a.authMiddleware, h.GetPracticesByOwner)
|
||||
groupV1.Put("/course-management/practices/:id", a.authMiddleware, h.UpdatePractice)
|
||||
groupV1.Delete("/course-management/practices/:id", a.authMiddleware, h.DeletePractice)
|
||||
|
||||
// Practice Questions
|
||||
groupV1.Post("/course-management/questions", a.authMiddleware, h.CreatePracticeQuestion)
|
||||
groupV1.Get("/course-management/practices/:practiceId/questions", a.authMiddleware, h.GetQuestionsByPractice)
|
||||
groupV1.Put("/course-management/questions/:id", a.authMiddleware, h.UpdatePracticeQuestion)
|
||||
groupV1.Delete("/course-management/questions/:id", a.authMiddleware, h.DeletePracticeQuestion)
|
||||
|
||||
// Learning Tree
|
||||
groupV1.Get("/course-management/learning-tree", a.authMiddleware, h.GetFullLearningTree)
|
||||
|
||||
// Auth Routes
|
||||
groupV1.Post("/auth/google/android", h.GoogleAndroidLogin)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user