diff --git a/src/db/migrations/0000_abnormal_spyke.sql b/src/db/migrations/0000_abnormal_spyke.sql new file mode 100644 index 0000000000000000000000000000000000000000..411b9933fb89a5534c0c451061bc613616f26793 --- /dev/null +++ b/src/db/migrations/0000_abnormal_spyke.sql @@ -0,0 +1,115 @@ +CREATE TABLE IF NOT EXISTS "collection_stats" ( + "id" serial PRIMARY KEY NOT NULL, + "collection_id" bigint NOT NULL, + "views" bigint DEFAULT 0, + "downloads" bigint DEFAULT 0, + "likes" bigint DEFAULT 0, + "shares" bigint DEFAULT 0, + "score" bigint DEFAULT 0, + "follows" bigint DEFAULT 0, + CONSTRAINT "collection_stats_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "collection" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar(255), + "description" text, + "is_private" boolean, + "is_active" boolean DEFAULT true, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp, + "deleted_at" timestamp, + "thumbnail" varchar(255), + CONSTRAINT "collection_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "resource" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar(256) NOT NULL, + "author" varchar(256) NOT NULL, + "description" varchar(256), + "bucket_key" varchar(256), + "link" varchar(256), + "thumbnail" varchar(256) NOT NULL, + "active" boolean DEFAULT false NOT NULL, + "published_at" timestamp, + "submited_at" timestamp, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp, + "deleted_at" timestamp, + CONSTRAINT "resource_id_unique" UNIQUE("id"), + CONSTRAINT "resource_bucket_key_unique" UNIQUE("bucket_key") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "stats_resources" ( + "id" serial PRIMARY KEY NOT NULL, + "resource_id" bigint NOT NULL, + "views" bigint DEFAULT 0 NOT NULL, + "downloads" bigint DEFAULT 0 NOT NULL, + "shares" bigint DEFAULT 0 NOT NULL, + "score" bigint DEFAULT 0 NOT NULL, + CONSTRAINT "stats_resources_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "subjects" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar NOT NULL, + CONSTRAINT "subjects_id_unique" UNIQUE("id"), + CONSTRAINT "subjects_name_unique" UNIQUE("name") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user_stats" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" integer NOT NULL, + "score" integer DEFAULT 0 NOT NULL, + "likes" integer DEFAULT 0, + "likes_received" integer DEFAULT 0, + "follows" integer DEFAULT 0, + "followers" integer DEFAULT 0, + "collections" integer DEFAULT 0, + "submitted_resources" integer DEFAULT 0, + "approved_resources" integer DEFAULT 0, + "reviewed_resources" integer DEFAULT 0, + "comments" integer DEFAULT 0, + CONSTRAINT "user_stats_id_unique" UNIQUE("id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar(255) NOT NULL, + "username" varchar(255) NOT NULL, + "password" varchar(255) NOT NULL, + "email" varchar(255) NOT NULL, + "description" text, + "institution" text, + "birthday" timestamp NOT NULL, + "cpf" varchar(255) NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + "confirmed_at" timestamp, + "confirmation_sent_at" timestamp, + "deleted_at" timestamp, + "reactivated_at" timestamp, + "active" boolean, + CONSTRAINT "user_id_unique" UNIQUE("id"), + CONSTRAINT "user_username_unique" UNIQUE("username"), + CONSTRAINT "user_email_unique" UNIQUE("email") +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "collection_stats" ADD CONSTRAINT "collection_stats_collection_id_collection_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collection"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "stats_resources" ADD CONSTRAINT "stats_resources_resource_id_resource_id_fk" FOREIGN KEY ("resource_id") REFERENCES "public"."resource"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "user_stats" ADD CONSTRAINT "user_stats_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/src/db/migrations/meta/0000_snapshot.json b/src/db/migrations/meta/0000_snapshot.json new file mode 100644 index 0000000000000000000000000000000000000000..04d2b88c8a96d953ce6327f02eca1550c149d2cf --- /dev/null +++ b/src/db/migrations/meta/0000_snapshot.json @@ -0,0 +1,633 @@ +{ + "id": "63132df0-078f-4e91-a6fa-a6a7717c996a", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.collection_stats": { + "name": "collection_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "collection_id": { + "name": "collection_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "views": { + "name": "views", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "downloads": { + "name": "downloads", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "likes": { + "name": "likes", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "shares": { + "name": "shares", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "score": { + "name": "score", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "follows": { + "name": "follows", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "collection_stats_collection_id_collection_id_fk": { + "name": "collection_stats_collection_id_collection_id_fk", + "tableFrom": "collection_stats", + "tableTo": "collection", + "columnsFrom": [ + "collection_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "collection_stats_id_unique": { + "name": "collection_stats_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "public.collection": { + "name": "collection", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_private": { + "name": "is_private", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "thumbnail": { + "name": "thumbnail", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "collection_id_unique": { + "name": "collection_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "public.resource": { + "name": "resource", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "author": { + "name": "author", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "bucket_key": { + "name": "bucket_key", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "thumbnail": { + "name": "thumbnail", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "submited_at": { + "name": "submited_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "resource_id_unique": { + "name": "resource_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + }, + "resource_bucket_key_unique": { + "name": "resource_bucket_key_unique", + "nullsNotDistinct": false, + "columns": [ + "bucket_key" + ] + } + } + }, + "public.stats_resources": { + "name": "stats_resources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "views": { + "name": "views", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "downloads": { + "name": "downloads", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "shares": { + "name": "shares", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "score": { + "name": "score", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "stats_resources_resource_id_resource_id_fk": { + "name": "stats_resources_resource_id_resource_id_fk", + "tableFrom": "stats_resources", + "tableTo": "resource", + "columnsFrom": [ + "resource_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "stats_resources_id_unique": { + "name": "stats_resources_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "public.subjects": { + "name": "subjects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "subjects_id_unique": { + "name": "subjects_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + }, + "subjects_name_unique": { + "name": "subjects_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "public.user_stats": { + "name": "user_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "likes": { + "name": "likes", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "likes_received": { + "name": "likes_received", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "follows": { + "name": "follows", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "followers": { + "name": "followers", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "collections": { + "name": "collections", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "submitted_resources": { + "name": "submitted_resources", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "approved_resources": { + "name": "approved_resources", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "reviewed_resources": { + "name": "reviewed_resources", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "comments": { + "name": "comments", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "user_stats_user_id_user_id_fk": { + "name": "user_stats_user_id_user_id_fk", + "tableFrom": "user_stats", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_stats_id_unique": { + "name": "user_stats_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + } + } + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "institution": { + "name": "institution", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "birthday": { + "name": "birthday", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "cpf": { + "name": "cpf", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "confirmed_at": { + "name": "confirmed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "confirmation_sent_at": { + "name": "confirmation_sent_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "reactivated_at": { + "name": "reactivated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_id_unique": { + "name": "user_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id" + ] + }, + "user_username_unique": { + "name": "user_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + }, + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json new file mode 100644 index 0000000000000000000000000000000000000000..2578d6f20185432ea970925e879b491514ce1927 --- /dev/null +++ b/src/db/migrations/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1727355232127, + "tag": "0000_abnormal_spyke", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/src/db/repo/subjects.repo.ts b/src/db/repo/subjects.repo.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ad4087786656ad17ade079df451f53eed7585dc --- /dev/null +++ b/src/db/repo/subjects.repo.ts @@ -0,0 +1,50 @@ +import { Service } from "typedi"; +import {type SubjectInput, type SubjectModel, type SubjectUpdate} from "../schema/subjects.schema"; +import db from ".."; +import subjectsTable, { subjectSchema } from "../schema/subjects.schema"; +import { eq } from "drizzle-orm"; + +@Service() +export class subjectsRepo { + async create(subject: SubjectInput): Promise<SubjectModel> { + const [ret] = await db + .insert(subjectsTable) + .values(subject) + .returning() + + return subjectSchema.model.parse(ret) + } + + async update(subject: SubjectUpdate): Promise<SubjectModel> { + const [ret] = await db + .update(subjectsTable) + .set(subject) + .where(eq(subjectsTable.id, subject.id)) + .returning() + + return subjectSchema.model.parse(ret) + } + + async delete(id: SubjectModel['id']): Promise<SubjectModel> { + const [ret] = await db + .delete(subjectsTable) + .where(eq(subjectsTable.id, id)) + .returning() + + return subjectSchema.model.parse(ret) + } + + async find(id: SubjectModel['id']): Promise<SubjectModel | undefined> { + const subject = await db.query.subjectsTable.findFirst({ + where: eq(subjectsTable.id, id), + }) + + return subjectSchema.model.parse(subject) + } + + async findMany(): Promise<SubjectModel[]> { + const subjects = await db.query.subjectsTable.findMany() + // o codigo fica mais legivel com map, apesar disso estamos usando outra forma em stats-resources.repo.ts + return subjects.map((subject) => subjectSchema.model.parse(subject)) + } +} \ No newline at end of file diff --git a/src/db/schema/index.ts b/src/db/schema/index.ts index 0fb247f075958b3e25297bb7e0e22a478b4df09a..5a397c112ec21eaf4c76fecb8b428b42191cc128 100644 --- a/src/db/schema/index.ts +++ b/src/db/schema/index.ts @@ -5,6 +5,7 @@ import statsResourcesTable from './stats-resources.schema' import collectionStatsTable from './collection-stats.model' import collectionTable from './collections.model' +import subjectsTable from './subjects.schema' @@ -14,7 +15,8 @@ export { resourceTable, collectionTable, statsResourcesTable, - collectionStatsTable + collectionStatsTable, + subjectsTable } export const tables = [ @@ -23,8 +25,8 @@ export const tables = [ resourceTable, statsResourcesTable, collectionTable, - collectionStatsTable - + collectionStatsTable, + subjectsTable ] diff --git a/src/db/schema/resource.schema.ts b/src/db/schema/resource.schema.ts index 3bded7fbfb4819c318a2cd2322ccafa59f5fbe8c..f625aa7717ee0a18fee1bdb88f233927e60b0f9b 100644 --- a/src/db/schema/resource.schema.ts +++ b/src/db/schema/resource.schema.ts @@ -17,7 +17,7 @@ const resourceTable = pgTable('resource', { description: varchar('description', { length: 256 }), bucket_key: varchar('bucket_key', { length: 256 }).unique(), link: varchar('link', { length: 256 }), - thumbnail: varchar('thumbnail', { length: 256 }), + thumbnail: varchar('thumbnail', { length: 256 }).notNull(), active: boolean('active').notNull().default(false), published_at: timestamp('published_at', { mode: 'string' }), submited_at: timestamp('submited_at', { mode: 'string' }), diff --git a/src/db/schema/subjects.schema.ts b/src/db/schema/subjects.schema.ts new file mode 100644 index 0000000000000000000000000000000000000000..593bb37706a0b9c02e92191f037b9929938d33e5 --- /dev/null +++ b/src/db/schema/subjects.schema.ts @@ -0,0 +1,36 @@ +import { + pgTable, + serial, + varchar, +} from 'drizzle-orm/pg-core' +import { createInsertSchema, createSelectSchema } from 'drizzle-zod' +import type { z } from 'zod' + + + + +const subjectsTable = pgTable('subjects', { + id: serial('id').primaryKey().unique(), + name: varchar('name').notNull().unique(), +}) + +const subjectModelSchema = createSelectSchema(subjectsTable) +const subjectDtoSchema = subjectModelSchema.omit({}) +const subjectInputSchema = createInsertSchema(subjectsTable) +const subjectUpdateSchema = subjectInputSchema + .partial() + .required({ id: true }) + +export type SubjectModel = z.infer<typeof subjectModelSchema> +export type SubjectDto = z.infer<typeof subjectDtoSchema> +export type SubjectInput = z.infer<typeof subjectInputSchema> +export type SubjectUpdate = z.infer<typeof subjectUpdateSchema> + +export const subjectSchema = { + model: subjectModelSchema, + dto: subjectDtoSchema, + input: subjectInputSchema, + update: subjectUpdateSchema, +} + +export default subjectsTable \ No newline at end of file diff --git a/src/db/seed.ts b/src/db/seed.ts index e49fbd4efd170fbccb19ee8ed9bb457f6e1e325f..026a3b7ce9f44a65cf5656b24de1cc0870d76758 100644 --- a/src/db/seed.ts +++ b/src/db/seed.ts @@ -27,5 +27,6 @@ await seeds.resourceSeed(db) await seeds.statsResourcesSeed(db) await seeds.collectionSeed(db) await seeds.collectionStatsSeed(db) +await seeds.subjectsData(db) await connection.end() diff --git a/src/db/seeds/index.ts b/src/db/seeds/index.ts index 1f52fb3d507c1068e9e75178aa081815097cad69..020b761fab6a5a5578113d9ac5328d3a44bb989e 100644 --- a/src/db/seeds/index.ts +++ b/src/db/seeds/index.ts @@ -4,3 +4,4 @@ export {default as resourceSeed} from './resource.seed' export {default as statsResourcesSeed} from './statsResources.seed' export { default as collectionSeed } from './collections.seed' export { default as collectionStatsSeed } from './collection-stats.seed' +export { default as subjectsData } from './subjects.seed' \ No newline at end of file diff --git a/src/db/seeds/subjects.seed.ts b/src/db/seeds/subjects.seed.ts new file mode 100644 index 0000000000000000000000000000000000000000..80a1ffd235ce3a81f006fed6117ae032d429ce45 --- /dev/null +++ b/src/db/seeds/subjects.seed.ts @@ -0,0 +1,50 @@ +import type db from ".."; +import type { SubjectInput } from "../schema/subjects.schema"; +import subjectsTable from "../schema/subjects.schema"; + +export default async function seed(db:db) { + await db.insert(subjectsTable).values(subjectsData) +} + +const subjectsData: SubjectInput[] = [ + { + name: 'Matemática' + }, + { + name: 'Português' + }, + { + name: 'História' + }, + { + name: 'Geografia' + }, + { + name: 'Biologia' + }, + { + name: 'Física' + }, + { + name: 'Química' + }, + { + name: 'Inglês' + }, + { + name: 'Espanhol' + }, + { + name: 'Artes' + }, + { + name: 'Educação Física' + }, + { + name: 'Filosofia' + }, + { + name: 'Sociologia' + }, +] + diff --git a/src/index.ts b/src/index.ts index 077dc63d35fd9b42ada864816dd4b267c212cd53..06c893cfb79f3887727dd9eacac5641baca41357 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,7 @@ import { collectionsRouter, getCollections } from './routes/collections.route' import { signUpRouter, userRouter } from './routes/user.route' import { uploaderRouter } from './routes/uploader.route' import { collectionsStatsRouter, getCollectionsStats } from './routes/collection-stats.route' +import { publicSubjectsRouter, subjectsRouter } from './routes/subjects.route' const app = new Hono() @@ -56,6 +57,7 @@ app .basePath('/public') .route('/resource', publicResourceRouter) .route('/statsResource', publicStatsResourceRouter) + .route('/subjects', publicSubjectsRouter) //rotas que precisam de token app @@ -65,6 +67,7 @@ app .route('/user-stats', userStatsRouter) .route('/resource', resourceRouter) .route('/statsResource', statsResourceRouter) + .route('/subjects', subjectsRouter) app.route('/getCollections', getCollections) app.route('/get-collections', getCollections) diff --git a/src/routes/subjects.route.ts b/src/routes/subjects.route.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff981a963e3bd7088bec7b3e44f3ae172f8f2267 --- /dev/null +++ b/src/routes/subjects.route.ts @@ -0,0 +1,127 @@ +import { SubjectsService } from "@/services/subjects.service"; +import { createApexError, HttpStatus } from "@/services/error.service"; +import Container from "typedi"; +import { honoWithJwt } from ".."; +import { subjectSchema } from "@/db/schema/subjects.schema"; +import { Hono } from "hono"; +import { zValidator } from "@hono/zod-validator"; + + +const service = Container.get(SubjectsService) + +export const subjectsRouter = honoWithJwt() + //rota com token + + .post('/create', + zValidator('json', subjectSchema.input), + async (c) => { + try { + const input = await c.req.valid('json') + const subject = await subjectSchema.dto.parse(await service.create(input)) + + return c.json({ subject }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not create the subject', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the json input and try again', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + + .post('/update', + zValidator('json', subjectSchema.update), + async (c) => { + + try { + const input = await c.req.valid('json') + const subject = await subjectSchema.dto.parse(await service.update(input)) + + return c.json({ subject }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not update the subject', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the json input and try again', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + + .post('delete/:id', + async (c) => { + try { + const id = +c.req.param('id') + const subject = await service.delete(id) + + return c.json({ subject }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not delete the subject', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the id and try again', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + +export const publicSubjectsRouter = new Hono() + + .get('/all', + async (c) => { + try { + const subjects = await service.findMany() + return c.json({ subjects }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not find the subjects', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'are you sure there are subjects?', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + + .get('/:id', + async (c) => { + try { + const id = +c.req.param('id') + const subject = await service.find(id) + return c.json({ subject }) + } catch (e) { + return c.json( + createApexError({ + status: 'error', + message: 'could not find the subject', + code: HttpStatus.BAD_REQUEST, + path: c.req.routePath, + suggestion: 'check the id and try again', + }), + HttpStatus.BAD_REQUEST + ) + } + } + ) + + diff --git a/src/services/subjects.service.ts b/src/services/subjects.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8b2f0c6e1821d87c0b9a988f1b4029fbcdc1b29 --- /dev/null +++ b/src/services/subjects.service.ts @@ -0,0 +1,31 @@ +import { subjectsRepo } from "@/db/repo/subjects.repo"; +import type { SubjectInput, SubjectModel, SubjectUpdate } from "@/db/schema/subjects.schema"; +import { Inject, Service } from "typedi"; + + + +@Service() +export class SubjectsService { + @Inject() + private readonly repo: subjectsRepo + + async create(subject: SubjectInput): Promise<SubjectModel> { + return this.repo.create(subject) + } + + async update(subject: SubjectUpdate): Promise<SubjectModel> { + return this.repo.update(subject) + } + + async delete(id: SubjectModel['id']): Promise<SubjectModel> { + return this.repo.delete(id) + } + + async find(id: SubjectModel['id']): Promise<SubjectModel | undefined> { + return this.repo.find(id) + } + + async findMany(): Promise<SubjectModel[]> { + return this.repo.findMany() + } +} \ No newline at end of file