diff --git a/drizzle/0021_salty_cammi.sql b/drizzle/0021_salty_cammi.sql new file mode 100644 index 0000000..ad1f878 --- /dev/null +++ b/drizzle/0021_salty_cammi.sql @@ -0,0 +1,39 @@ +CREATE TABLE IF NOT EXISTS "co_working_space_reviews" ( + "coWorkingSpace_id" text NOT NULL, + "user_id" text NOT NULL, + "rating" integer NOT NULL, + "review" text NOT NULL, + CONSTRAINT "co_working_space_reviews_coWorkingSpace_id_user_id_pk" PRIMARY KEY("coWorkingSpace_id","user_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "voucher_reviews" ( + "user_id" text NOT NULL, + "voucher_id" text NOT NULL, + "rating" integer NOT NULL, + "review" text NOT NULL, + CONSTRAINT "voucher_reviews_voucher_id_user_id_pk" PRIMARY KEY("voucher_id","user_id") +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "co_working_space_reviews" ADD CONSTRAINT "co_working_space_reviews_coWorkingSpace_id_co_working_space_recommendations_id_fk" FOREIGN KEY ("coWorkingSpace_id") REFERENCES "public"."co_working_space_recommendations"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "co_working_space_reviews" ADD CONSTRAINT "co_working_space_reviews_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "voucher_reviews" ADD CONSTRAINT "voucher_reviews_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "voucher_reviews" ADD CONSTRAINT "voucher_reviews_voucher_id_voucher_recommendations_id_fk" FOREIGN KEY ("voucher_id") REFERENCES "public"."voucher_recommendations"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/drizzle/meta/0021_snapshot.json b/drizzle/meta/0021_snapshot.json new file mode 100644 index 0000000..893a0ed --- /dev/null +++ b/drizzle/meta/0021_snapshot.json @@ -0,0 +1,2490 @@ +{ + "id": "803c7978-ac52-4725-8eb6-cfae0e0b2aae", + "prevId": "1a6f2efb-9665-46e4-a321-e2e28ebc940c", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.angkatan": { + "name": "angkatan", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "year": { + "name": "year", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "angkatan_year_unique": { + "name": "angkatan_year_unique", + "nullsNotDistinct": false, + "columns": [ + "year" + ] + }, + "angkatan_name_unique": { + "name": "angkatan_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "public.calendar_event": { + "name": "calendar_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "calendar_group_id": { + "name": "calendar_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "courses_id": { + "name": "courses_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "academic_year": { + "name": "academic_year", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "academic_semester_code": { + "name": "academic_semester_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "end": { + "name": "end", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "google_calendar_url": { + "name": "google_calendar_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "google_calendar_id": { + "name": "google_calendar_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "title_search_idx": { + "name": "title_search_idx", + "columns": [ + { + "expression": "(\n setweight(to_tsvector('indonesian', \"title\"), 'A') ||\n setweight(to_tsvector('indonesian', \"description\"), 'B')\n )", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "calendar_event_calendar_group_id_calendar_group_id_fk": { + "name": "calendar_event_calendar_group_id_calendar_group_id_fk", + "tableFrom": "calendar_event", + "tableTo": "calendar_group", + "columnsFrom": [ + "calendar_group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "calendar_event_courses_id_courses_id_fk": { + "name": "calendar_event_courses_id_courses_id_fk", + "tableFrom": "calendar_event", + "tableTo": "courses", + "columnsFrom": [ + "courses_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.calendar_group": { + "name": "calendar_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "google_calendar_url": { + "name": "google_calendar_url", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.categories": { + "name": "categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "roles_allowed": { + "name": "roles_allowed", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "required_push": { + "name": "required_push", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_for_info": { + "name": "is_for_info", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "categories_name_unique": { + "name": "categories_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "public.chatroom_labels": { + "name": "chatroom_labels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.chatroom_labels_many_to_many": { + "name": "chatroom_labels_many_to_many", + "schema": "", + "columns": { + "chatroom_id": { + "name": "chatroom_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label_id": { + "name": "label_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "chatroom_labels_many_to_many_chatroom_id_chatrooms_id_fk": { + "name": "chatroom_labels_many_to_many_chatroom_id_chatrooms_id_fk", + "tableFrom": "chatroom_labels_many_to_many", + "tableTo": "chatrooms", + "columnsFrom": [ + "chatroom_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chatroom_labels_many_to_many_label_id_chatroom_labels_id_fk": { + "name": "chatroom_labels_many_to_many_label_id_chatroom_labels_id_fk", + "tableFrom": "chatroom_labels_many_to_many", + "tableTo": "chatroom_labels", + "columnsFrom": [ + "label_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "chatroom_labels_many_to_many_chatroom_id_label_id_pk": { + "name": "chatroom_labels_many_to_many_chatroom_id_label_id_pk", + "columns": [ + "chatroom_id", + "label_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.chatroom_message_reads": { + "name": "chatroom_message_reads", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatroom_message_id": { + "name": "chatroom_message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "read_at": { + "name": "read_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "chatroom_message_reads_user_id_users_id_fk": { + "name": "chatroom_message_reads_user_id_users_id_fk", + "tableFrom": "chatroom_message_reads", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chatroom_message_reads_chatroom_message_id_chatroom_messages_id_fk": { + "name": "chatroom_message_reads_chatroom_message_id_chatroom_messages_id_fk", + "tableFrom": "chatroom_message_reads", + "tableTo": "chatroom_messages", + "columnsFrom": [ + "chatroom_message_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "chatroom_message_reads_user_id_chatroom_message_id_pk": { + "name": "chatroom_message_reads_user_id_chatroom_message_id_pk", + "columns": [ + "user_id", + "chatroom_message_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.chatroom_messages": { + "name": "chatroom_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "chatroom_id": { + "name": "chatroom_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reply_id": { + "name": "reply_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "chatroom_messages_chatroom_id_chatrooms_id_fk": { + "name": "chatroom_messages_chatroom_id_chatrooms_id_fk", + "tableFrom": "chatroom_messages", + "tableTo": "chatrooms", + "columnsFrom": [ + "chatroom_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chatroom_messages_user_id_users_id_fk": { + "name": "chatroom_messages_user_id_users_id_fk", + "tableFrom": "chatroom_messages", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chatroom_messages_reply_id_chatroom_messages_id_fk": { + "name": "chatroom_messages_reply_id_chatroom_messages_id_fk", + "tableFrom": "chatroom_messages", + "tableTo": "chatroom_messages", + "columnsFrom": [ + "reply_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.chatrooms": { + "name": "chatrooms", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "chatrooms_user_id_users_id_fk": { + "name": "chatrooms_user_id_users_id_fk", + "tableFrom": "chatrooms", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.co_working_space_recommendations": { + "name": "co_working_space_recommendations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "maps_url": { + "name": "maps_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "co_working_space_recommendations_creator_id_users_id_fk": { + "name": "co_working_space_recommendations_creator_id_users_id_fk", + "tableFrom": "co_working_space_recommendations", + "tableTo": "users", + "columnsFrom": [ + "creator_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.co_working_space_reviews": { + "name": "co_working_space_reviews", + "schema": "", + "columns": { + "coWorkingSpace_id": { + "name": "coWorkingSpace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rating": { + "name": "rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "review": { + "name": "review", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "co_working_space_reviews_coWorkingSpace_id_co_working_space_recommendations_id_fk": { + "name": "co_working_space_reviews_coWorkingSpace_id_co_working_space_recommendations_id_fk", + "tableFrom": "co_working_space_reviews", + "tableTo": "co_working_space_recommendations", + "columnsFrom": [ + "coWorkingSpace_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "co_working_space_reviews_user_id_users_id_fk": { + "name": "co_working_space_reviews_user_id_users_id_fk", + "tableFrom": "co_working_space_reviews", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "co_working_space_reviews_coWorkingSpace_id_user_id_pk": { + "name": "co_working_space_reviews_coWorkingSpace_id_user_id_pk", + "columns": [ + "coWorkingSpace_id", + "user_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "replied_info_id": { + "name": "replied_info_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "comments_replied_info_id_index": { + "name": "comments_replied_info_id_index", + "columns": [ + { + "expression": "replied_info_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "comments_creator_id_index": { + "name": "comments_creator_id_index", + "columns": [ + { + "expression": "creator_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "comments_replied_info_id_infos_id_fk": { + "name": "comments_replied_info_id_infos_id_fk", + "tableFrom": "comments", + "tableTo": "infos", + "columnsFrom": [ + "replied_info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "comments_creator_id_users_id_fk": { + "name": "comments_creator_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "creator_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.competition_medias": { + "name": "competition_medias", + "schema": "", + "columns": { + "competition_id": { + "name": "competition_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "media_id": { + "name": "media_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "competition_medias_competition_id_competitions_id_fk": { + "name": "competition_medias_competition_id_competitions_id_fk", + "tableFrom": "competition_medias", + "tableTo": "competitions", + "columnsFrom": [ + "competition_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "competition_medias_media_id_medias_id_fk": { + "name": "competition_medias_media_id_medias_id_fk", + "tableFrom": "competition_medias", + "tableTo": "medias", + "columnsFrom": [ + "media_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "competition_medias_competition_id_media_id_pk": { + "name": "competition_medias_competition_id_media_id_pk", + "columns": [ + "competition_id", + "media_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.competitions": { + "name": "competitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organizer": { + "name": "organizer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registration_start_date": { + "name": "registration_start_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "registration_deadline_date": { + "name": "registration_deadline_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "price": { + "name": "price", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registration_url": { + "name": "registration_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categories": { + "name": "categories", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'[]'::json" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.courses": { + "name": "courses", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "curriculum_year": { + "name": "curriculum_year", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "jurusan": { + "name": "jurusan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'Elective'" + }, + "semester": { + "name": "semester", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "semester_code": { + "name": "semester_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sks": { + "name": "sks", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "dingdong_url": { + "name": "dingdong_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "courses_code_index": { + "name": "courses_code_index", + "columns": [ + { + "expression": "code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "search_idx": { + "name": "search_idx", + "columns": [ + { + "expression": "(\n setweight(to_tsvector('indonesian', \"name\"), 'A') ||\n setweight(to_tsvector('indonesian', \"code\"), 'B')\n )", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "courses_code_unique": { + "name": "courses_code_unique", + "nullsNotDistinct": false, + "columns": [ + "code" + ] + } + } + }, + "public.google_subscriptions": { + "name": "google_subscriptions", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_in": { + "name": "expires_in", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "google_subscriptions_user_id_users_id_fk": { + "name": "google_subscriptions_user_id_users_id_fk", + "tableFrom": "google_subscriptions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.info_angkatan": { + "name": "info_angkatan", + "schema": "", + "columns": { + "info_id": { + "name": "info_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "angkatan_id": { + "name": "angkatan_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "info_angkatan_info_id_infos_id_fk": { + "name": "info_angkatan_info_id_infos_id_fk", + "tableFrom": "info_angkatan", + "tableTo": "infos", + "columnsFrom": [ + "info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "info_angkatan_angkatan_id_angkatan_id_fk": { + "name": "info_angkatan_angkatan_id_angkatan_id_fk", + "tableFrom": "info_angkatan", + "tableTo": "angkatan", + "columnsFrom": [ + "angkatan_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "info_angkatan_info_id_angkatan_id_pk": { + "name": "info_angkatan_info_id_angkatan_id_pk", + "columns": [ + "info_id", + "angkatan_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.info_categories": { + "name": "info_categories", + "schema": "", + "columns": { + "info_id": { + "name": "info_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category_id": { + "name": "category_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "info_categories_info_id_infos_id_fk": { + "name": "info_categories_info_id_infos_id_fk", + "tableFrom": "info_categories", + "tableTo": "infos", + "columnsFrom": [ + "info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "info_categories_category_id_categories_id_fk": { + "name": "info_categories_category_id_categories_id_fk", + "tableFrom": "info_categories", + "tableTo": "categories", + "columnsFrom": [ + "category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "info_categories_info_id_category_id_pk": { + "name": "info_categories_info_id_category_id_pk", + "columns": [ + "info_id", + "category_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.info_courses": { + "name": "info_courses", + "schema": "", + "columns": { + "info_id": { + "name": "info_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "course_id": { + "name": "course_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "class": { + "name": "class", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "info_courses_info_id_infos_id_fk": { + "name": "info_courses_info_id_infos_id_fk", + "tableFrom": "info_courses", + "tableTo": "infos", + "columnsFrom": [ + "info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "info_courses_course_id_courses_id_fk": { + "name": "info_courses_course_id_courses_id_fk", + "tableFrom": "info_courses", + "tableTo": "courses", + "columnsFrom": [ + "course_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "info_courses_info_id_course_id_pk": { + "name": "info_courses_info_id_course_id_pk", + "columns": [ + "info_id", + "course_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.info_groups": { + "name": "info_groups", + "schema": "", + "columns": { + "info_id": { + "name": "info_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "info_groups_info_id_infos_id_fk": { + "name": "info_groups_info_id_infos_id_fk", + "tableFrom": "info_groups", + "tableTo": "infos", + "columnsFrom": [ + "info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "info_groups_info_id_role_pk": { + "name": "info_groups_info_id_role_pk", + "columns": [ + "info_id", + "role" + ] + } + }, + "uniqueConstraints": {} + }, + "public.info_medias": { + "name": "info_medias", + "schema": "", + "columns": { + "info_id": { + "name": "info_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "media_id": { + "name": "media_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "info_medias_info_id_infos_id_fk": { + "name": "info_medias_info_id_infos_id_fk", + "tableFrom": "info_medias", + "tableTo": "infos", + "columnsFrom": [ + "info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "info_medias_media_id_medias_id_fk": { + "name": "info_medias_media_id_medias_id_fk", + "tableFrom": "info_medias", + "tableTo": "medias", + "columnsFrom": [ + "media_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "info_medias_info_id_media_id_pk": { + "name": "info_medias_info_id_media_id_pk", + "columns": [ + "info_id", + "media_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.infos": { + "name": "infos", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_for_angkatan": { + "name": "is_for_angkatan", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "is_for_groups": { + "name": "is_for_groups", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "last_notified_at": { + "name": "last_notified_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "content_search_idx": { + "name": "content_search_idx", + "columns": [ + { + "expression": "(\n setweight(to_tsvector('indonesian', \"title\"), 'A') ||\n setweight(to_tsvector('indonesian', \"content\"), 'B')\n )", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "infos_creator_id_users_id_fk": { + "name": "infos_creator_id_users_id_fk", + "tableFrom": "infos", + "tableTo": "users", + "columnsFrom": [ + "creator_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.markdowns": { + "name": "markdowns", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.medias": { + "name": "medias", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "medias_creator_id_users_id_fk": { + "name": "medias_creator_id_users_id_fk", + "tableFrom": "medias", + "tableTo": "users", + "columnsFrom": [ + "creator_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "medias_name_unique": { + "name": "medias_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "public.push_subscriptions": { + "name": "push_subscriptions", + "schema": "", + "columns": { + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "keys": { + "name": "keys", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "push_subscriptions_user_id_index": { + "name": "push_subscriptions_user_id_index", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "push_subscriptions_user_id_users_id_fk": { + "name": "push_subscriptions_user_id_users_id_fk", + "tableFrom": "push_subscriptions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.reactions": { + "name": "reactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "info_id": { + "name": "info_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "comment_id": { + "name": "comment_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reaction": { + "name": "reaction", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "reactions_info_id_index": { + "name": "reactions_info_id_index", + "columns": [ + { + "expression": "info_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "reactions_comment_id_index": { + "name": "reactions_comment_id_index", + "columns": [ + { + "expression": "comment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "reactions_creator_id_users_id_fk": { + "name": "reactions_creator_id_users_id_fk", + "tableFrom": "reactions", + "tableTo": "users", + "columnsFrom": [ + "creator_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "reactions_info_id_infos_id_fk": { + "name": "reactions_info_id_infos_id_fk", + "tableFrom": "reactions", + "tableTo": "infos", + "columnsFrom": [ + "info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "reactions_comment_id_comments_id_fk": { + "name": "reactions_comment_id_comments_id_fk", + "tableFrom": "reactions", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "reactions_creator_id_info_id_comment_id_unique": { + "name": "reactions_creator_id_info_id_comment_id_unique", + "nullsNotDistinct": true, + "columns": [ + "creator_id", + "info_id", + "comment_id" + ] + } + } + }, + "public.testimonies": { + "name": "testimonies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "course_id": { + "name": "course_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_name": { + "name": "user_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "impressions": { + "name": "impressions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "challenges": { + "name": "challenges", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "advice": { + "name": "advice", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "overview": { + "name": "overview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assignments": { + "name": "assignments", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lecturer_review": { + "name": "lecturer_review", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lecturer": { + "name": "lecturer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "testimonies_user_id_index": { + "name": "testimonies_user_id_index", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "testimonies_course_id_index": { + "name": "testimonies_course_id_index", + "columns": [ + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "testimonies_user_id_users_id_fk": { + "name": "testimonies_user_id_users_id_fk", + "tableFrom": "testimonies", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "testimonies_course_id_courses_id_fk": { + "name": "testimonies_course_id_courses_id_fk", + "tableFrom": "testimonies", + "tableTo": "courses", + "columnsFrom": [ + "course_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.user_courses": { + "name": "user_courses", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "course_id": { + "name": "course_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "class": { + "name": "class", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "semester_code_taken": { + "name": "semester_code_taken", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "semester_year_taken": { + "name": "semester_year_taken", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_courses_user_id_users_id_fk": { + "name": "user_courses_user_id_users_id_fk", + "tableFrom": "user_courses", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_courses_course_id_courses_id_fk": { + "name": "user_courses_course_id_courses_id_fk", + "tableFrom": "user_courses", + "tableTo": "courses", + "columnsFrom": [ + "course_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_courses_user_id_course_id_pk": { + "name": "user_courses_user_id_course_id_pk", + "columns": [ + "user_id", + "course_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.user_pinned_chatrooms": { + "name": "user_pinned_chatrooms", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chatroom_id": { + "name": "chatroom_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_pinned_chatrooms_user_id_users_id_fk": { + "name": "user_pinned_chatrooms_user_id_users_id_fk", + "tableFrom": "user_pinned_chatrooms", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_pinned_chatrooms_chatroom_id_chatrooms_id_fk": { + "name": "user_pinned_chatrooms_chatroom_id_chatrooms_id_fk", + "tableFrom": "user_pinned_chatrooms", + "tableTo": "chatrooms", + "columnsFrom": [ + "chatroom_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_pinned_chatrooms_user_id_chatroom_id_pk": { + "name": "user_pinned_chatrooms_user_id_chatroom_id_pk", + "columns": [ + "user_id", + "chatroom_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.user_read_infos": { + "name": "user_read_infos", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "info_id": { + "name": "info_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_read_infos_user_id_users_id_fk": { + "name": "user_read_infos_user_id_users_id_fk", + "tableFrom": "user_read_infos", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_read_infos_info_id_infos_id_fk": { + "name": "user_read_infos_info_id_infos_id_fk", + "tableFrom": "user_read_infos", + "tableTo": "infos", + "columnsFrom": [ + "info_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_read_infos_user_id_info_id_pk": { + "name": "user_read_infos_user_id_info_id_pk", + "columns": [ + "user_id", + "info_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_roles_user_id_role_pk": { + "name": "user_roles_user_id_role_pk", + "columns": [ + "user_id", + "role" + ] + } + }, + "uniqueConstraints": {} + }, + "public.user_unsubscribe_categories": { + "name": "user_unsubscribe_categories", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category_id": { + "name": "category_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "user_unsubscribe_categories_user_id_users_id_fk": { + "name": "user_unsubscribe_categories_user_id_users_id_fk", + "tableFrom": "user_unsubscribe_categories", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_unsubscribe_categories_category_id_categories_id_fk": { + "name": "user_unsubscribe_categories_category_id_categories_id_fk", + "tableFrom": "user_unsubscribe_categories", + "tableTo": "categories", + "columnsFrom": [ + "category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_unsubscribe_categories_user_id_category_id_pk": { + "name": "user_unsubscribe_categories_user_id_category_id_pk", + "columns": [ + "user_id", + "category_id" + ] + } + }, + "uniqueConstraints": {} + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "nim": { + "name": "nim", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "full_name": { + "name": "full_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "jurusan": { + "name": "jurusan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "picture": { + "name": "picture", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "asal_kampus": { + "name": "asal_kampus", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "angkatan": { + "name": "angkatan", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "jenis_kelamin": { + "name": "jenis_kelamin", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status_keanggotaan": { + "name": "status_keanggotaan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_login_at": { + "name": "last_login_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "users_nim_index": { + "name": "users_nim_index", + "columns": [ + { + "expression": "nim", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "users_email_index": { + "name": "users_email_index", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "users_angkatan_angkatan_year_fk": { + "name": "users_angkatan_angkatan_year_fk", + "tableFrom": "users", + "tableTo": "angkatan", + "columnsFrom": [ + "angkatan" + ], + "columnsTo": [ + "year" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_nim_unique": { + "name": "users_nim_unique", + "nullsNotDistinct": false, + "columns": [ + "nim" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "public.voucher_recommendations": { + "name": "voucher_recommendations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_period": { + "name": "start_period", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "end_period": { + "name": "end_period", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "voucher_recommendations_creator_id_users_id_fk": { + "name": "voucher_recommendations_creator_id_users_id_fk", + "tableFrom": "voucher_recommendations", + "tableTo": "users", + "columnsFrom": [ + "creator_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.voucher_reviews": { + "name": "voucher_reviews", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "voucher_id": { + "name": "voucher_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rating": { + "name": "rating", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "review": { + "name": "review", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "voucher_reviews_user_id_users_id_fk": { + "name": "voucher_reviews_user_id_users_id_fk", + "tableFrom": "voucher_reviews", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "voucher_reviews_voucher_id_voucher_recommendations_id_fk": { + "name": "voucher_reviews_voucher_id_voucher_recommendations_id_fk", + "tableFrom": "voucher_reviews", + "tableTo": "voucher_recommendations", + "columnsFrom": [ + "voucher_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "voucher_reviews_voucher_id_user_id_pk": { + "name": "voucher_reviews_voucher_id_user_id_pk", + "columns": [ + "voucher_id", + "user_id" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 2e4d952..b56b2c5 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -148,6 +148,13 @@ "when": 1731917458503, "tag": "0020_wise_red_skull", "breakpoints": true + }, + { + "idx": 21, + "version": "7", + "when": 1732838399487, + "tag": "0021_salty_cammi", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index ca1e9ab..787a958 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "nodemailer": "^6.9.16", "open-graph-scraper": "^6.5.1", "pg": "^8.11.3", + "pg-error": "^1.1.0", "postgres": "^3.4.4", "socket.io": "^4.8.0", "unique-names-generator": "^4.7.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 76490e7..2defdbe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -89,6 +89,9 @@ importers: pg: specifier: ^8.11.3 version: 8.11.5 + pg-error: + specifier: ^1.1.0 + version: 1.1.0 postgres: specifier: ^3.4.4 version: 3.4.4 @@ -2409,6 +2412,9 @@ packages: pg-connection-string@2.6.4: resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + pg-error@1.1.0: + resolution: {integrity: sha512-l+8naVC0ePgaljX0+XomFonCde9ENWRETWEb3ueBA53phD8izgrGKHsgWslNM/Tgf9vCtKbu3OgV3yKxUfUHXw==} + pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} @@ -2648,6 +2654,9 @@ packages: stack-trace@0.0.10: resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + standard-error@1.1.0: + resolution: {integrity: sha512-4v7qzU7oLJfMI5EltUSHCaaOd65J6S4BqKRWgzMi4EYaE5fvNabPxmAPGdxpGXqrcWjhDGI/H09CIdEuUOUeXg==} + string.prototype.trim@1.2.9: resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} engines: {node: '>= 0.4'} @@ -5764,6 +5773,10 @@ snapshots: pg-connection-string@2.6.4: {} + pg-error@1.1.0: + dependencies: + standard-error: 1.1.0 + pg-int8@1.0.1: {} pg-numeric@1.0.2: {} @@ -6002,6 +6015,8 @@ snapshots: stack-trace@0.0.10: {} + standard-error@1.1.0: {} + string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 diff --git a/src/controllers/recommendation.controller.ts b/src/controllers/recommendation.controller.ts index 8a66459..3b12d50 100644 --- a/src/controllers/recommendation.controller.ts +++ b/src/controllers/recommendation.controller.ts @@ -3,12 +3,22 @@ import { createAuthRouter } from './router-factory'; import { createCoWorkingSpaceRecommendation, createVoucherRecommendation, + getVoucherReviewById, + getCoWorkingSpaceReviewById, + postVoucherReview, + deleteVoucherReview, + postCoWorkingSpaceReview, + deleteCoWorkingSpaceReview, } from '~/repositories/recommendation.repo'; import { postRecommendationCoWorkingSpaceRoute, postRecommendationVoucherRoute, + postVoucherReviewRoute, + postCoWorkingSpaceReviewRoute, + deleteVoucherReviewRoute, + deleteCoWorkingSpaceReviewRoute, } from '~/routes/recommendation.route'; - +import { PostgresError } from 'postgres'; export const recommendationRoute = createAuthRouter(); recommendationRoute.openapi(postRecommendationVoucherRoute, async (c) => { @@ -35,3 +45,203 @@ recommendationRoute.openapi( return c.json(recommendation, 201); }, ); + +recommendationRoute.openapi(postVoucherReviewRoute, async (c) => { + const { id } = c.var.user; + const { voucherId } = c.req.valid('param'); + const { rating, review } = c.req.valid('json'); + + const data = { + userId: id, + voucherId, + rating, + review, + }; + + try { + const voucher = await postVoucherReview(db, data); + // console.log('Created voucher review:', voucher); + return c.json(voucher, 201); + } catch (error) { + if (error instanceof PostgresError) { + // console.log('Postgres error:', error); + return c.json( + { + error: 'failed to create voucher review', + formErrors: [], + fieldErrors: { error: ['failed to create voucher review'] }, + }, + 400, + ); + } else { + return c.json( + { + error: 'Something went wrong', + formErrors: [], + fieldErrors: { error: ['Something went wrong'] }, + }, + 500, + ); + } + } +}); + +recommendationRoute.openapi(postCoWorkingSpaceReviewRoute, async (c) => { + const { id } = c.var.user; + const { coWorkingSpaceId } = c.req.valid('param'); + const { rating, review } = c.req.valid('json'); + + const data = { + coWorkingSpaceId, + userId: id, + rating, + review, + }; + + try { + const coWorkingSpaceReview = await postCoWorkingSpaceReview(db, data); + // console.log('Created co-working space review:', coWorkingSpaceReview); + return c.json(coWorkingSpaceReview, 201); + } catch (error) { + if (error instanceof PostgresError) { + return c.json( + { + error: 'failed to create co-working space review', + formErrors: [], + fieldErrors: { error: ['failed to create co-working space review'] }, + }, + 400, + ); + } else { + return c.json( + { + error: 'Something went wrong', + formErrors: [], + fieldErrors: { error: ['Something went wrong'] }, + }, + 500, + ); + } + } +}); + +recommendationRoute.openapi(deleteVoucherReviewRoute, async (c) => { + const { id } = c.var.user; + const { userId, voucherId } = c.req.valid('param'); + + const voucherDB = await getVoucherReviewById(db, { voucherId, userId }); + if (!voucherDB?.voucherId) { + return c.json( + { + error: 'Voucher review not found', + formErrors: [], + fieldErrors: { error: ['Voucher review not found'] }, + }, + 404, + ); + } + + try { + if (id === userId) { + await deleteVoucherReview(db, voucherId, userId); + + const response = { + success: true, + error: '', + }; + + return c.json(response, 201); + } else { + return c.json( + { + error: 'failed to delete voucher', + formErrors: [], + fieldErrors: { error: ['Unauthorized'] }, + }, + 400, + ); + } + } catch (error) { + if (error instanceof PostgresError) { + return c.json( + { + error: 'failed to delete voucher', + formErrors: [], + fieldErrors: { error: ['failed to delete voucher'] }, + }, + 400, + ); + } else { + return c.json( + { + error: 'Something went wrong', + formErrors: [], + fieldErrors: { error: ['Something went wrong'] }, + }, + 500, + ); + } + } +}); + +recommendationRoute.openapi(deleteCoWorkingSpaceReviewRoute, async (c) => { + const { id } = c.var.user; + const { coWorkingSpaceId, userId } = c.req.valid('param'); + + const coworkingDB = await getCoWorkingSpaceReviewById(db, { + coWorkingSpaceId, + userId, + }); + if (!coworkingDB?.coWorkingSpaceId) { + return c.json( + { + error: 'Co-working space review not found', + formErrors: [], + fieldErrors: { error: ['Co-working space review not found'] }, + }, + 404, + ); + } + + try { + if (id === userId) { + await deleteCoWorkingSpaceReview(db, coWorkingSpaceId, userId); + + const response = { + success: true, + error: '', + }; + + return c.json(response, 201); + } else { + return c.json( + { + error: 'failed to delete voucher', + formErrors: [], + fieldErrors: { error: ['failed to delete voucher'] }, + }, + 400, + ); + } + } catch (error) { + if (error instanceof PostgresError) { + return c.json( + { + error: 'failed to delete co-working space review', + formErrors: [], + fieldErrors: { error: ['failed to delete co-working space review'] }, + }, + 400, + ); + } else { + return c.json( + { + error: 'Something went wrong', + formErrors: [], + fieldErrors: { error: ['Something went wrong'] }, + }, + 500, + ); + } + } +}); diff --git a/src/db/schema.ts b/src/db/schema.ts index 3eb4b7b..0a9bee9 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -934,3 +934,60 @@ export const coWorkingSpaceRecommendationsRelation = relations( }), }), ); + +export const voucherReviews = pgTable( + 'voucher_reviews', + { + userId: text('user_id') + .references(() => users.id, { onDelete: 'cascade' }) + .notNull(), + voucherId: text('voucher_id') + .references(() => voucherRecommendations.id, { onDelete: 'cascade' }) + .notNull(), + rating: integer('rating').notNull(), + review: text('review').notNull(), + }, + (t) => ({ pk: primaryKey({ columns: [t.voucherId, t.userId] }) }), +); + +export const coWorkingSpaceReviews = pgTable( + 'co_working_space_reviews', + { + coWorkingSpaceId: text('coWorkingSpace_id') + .references(() => coWorkingSpaceRecommendations.id, { + onDelete: 'cascade', + }) + .notNull(), + userId: text('user_id') + .references(() => users.id, { onDelete: 'cascade' }) + .notNull(), + rating: integer('rating').notNull(), + review: text('review').notNull(), + }, + (t) => ({ pk: primaryKey({ columns: [t.coWorkingSpaceId, t.userId] }) }), +); + +export const voucherReviewsRelation = relations(voucherReviews, ({ one }) => ({ + recommendation: one(voucherRecommendations, { + fields: [voucherReviews.voucherId], + references: [voucherRecommendations.id], + }), + user: one(users, { + fields: [voucherReviews.userId], + references: [users.id], + }), +})); + +export const coWorkingSpaceReviewsRelation = relations( + coWorkingSpaceReviews, + ({ one }) => ({ + recommendation: one(coWorkingSpaceRecommendations, { + fields: [coWorkingSpaceReviews.coWorkingSpaceId], + references: [coWorkingSpaceRecommendations.id], + }), + user: one(users, { + fields: [coWorkingSpaceReviews.userId], + references: [users.id], + }), + }), +); diff --git a/src/repositories/recommendation.repo.ts b/src/repositories/recommendation.repo.ts index 748bdee..0e97037 100644 --- a/src/repositories/recommendation.repo.ts +++ b/src/repositories/recommendation.repo.ts @@ -1,14 +1,18 @@ import type { z } from 'zod'; import type { Database } from '~/db/drizzle'; import { firstSure } from '~/db/helper'; +import { InferInsertModel, and, eq } from 'drizzle-orm'; import { coWorkingSpaceRecommendations, voucherRecommendations, + voucherReviews, + coWorkingSpaceReviews, } from '~/db/schema'; import type { JWTPayloadSchema } from '~/types/login.types'; import type { CoWorkingSpaceRecommendationSchema, VoucherRecommendationSchema, + VoucherReviewSchema, } from '~/types/recommendations.types'; export const createVoucherRecommendation = async ( @@ -46,3 +50,110 @@ export const createCoWorkingSpaceRecommendation = async ( return recommendation; }; + +export const getVoucherReviewById = async ( + db: Database, + q: { userId: string; voucherId: string }, +) => { + const { userId, voucherId } = q; + return await db.query.voucherReviews.findFirst({ + where: and( + eq(voucherReviews.voucherId, voucherId), + eq(voucherReviews.userId, userId), + ), + }); +}; + +export const postVoucherReview = async ( + db: Database, + data: z.infer, +) => { + const review = await db + .insert(voucherReviews) + .values({ + ...data, + }) + .returning() + .then(firstSure); + + return review; +}; + +export const getCoWorkingSpaceReviewById = async ( + db: Database, + q: { userId: string; coWorkingSpaceId: string }, +) => { + const { userId, coWorkingSpaceId } = q; + return await db.query.coWorkingSpaceReviews.findFirst({ + where: and( + eq(coWorkingSpaceReviews.coWorkingSpaceId, coWorkingSpaceId), + eq(coWorkingSpaceReviews.userId, userId), + ), + }); +}; + +/** + * Insert a new coworking space review + * @param db Database instance + * @param review Review object to insert + * @returns Inserted review or undefined if insertion fails + */ +export async function postCoWorkingSpaceReview( + db: Database, + data: InferInsertModel, +) { + return await db + .insert(coWorkingSpaceReviews) + .values(data) + .onConflictDoNothing() + .returning() + .then(firstSure); +} + +/** + * Delete a voucher review + * @param db Database instance + * @param voucherId ID of the voucher recommendation + * @param userId ID of the user who made the review + * @returns Deleted review or undefined if no review was deleted + */ +export async function deleteVoucherReview( + db: Database, + voucherId: string, + userId: string, +) { + return await db + .delete(voucherReviews) + .where( + and( + eq(voucherReviews.voucherId, voucherId), + eq(voucherReviews.userId, userId), + ), + ) + .returning() + .then(firstSure); +} + +/** + * Delete a coworking space review + * @param db Database instance + * @param coWorkingSpaceId ID of the coworking space recommendation + * @param userId ID of the user who made the review + * @returns Deleted review or undefined if no review was deleted + */ +export async function deleteCoWorkingSpaceReview( + db: Database, + coWorkingSpaceId: string, + userId: string, +) { + return await db + .delete(coWorkingSpaceReviews) + .where( + and( + eq(coWorkingSpaceReviews.coWorkingSpaceId, coWorkingSpaceId), + eq(coWorkingSpaceReviews.userId, userId), + ), + ) + .returning() + .then(firstSure); +} diff --git a/src/routes/recommendation.route.ts b/src/routes/recommendation.route.ts index 61eb8d2..e917690 100644 --- a/src/routes/recommendation.route.ts +++ b/src/routes/recommendation.route.ts @@ -1,13 +1,23 @@ -import { createRoute } from '@hono/zod-openapi'; +import { createRoute, z } from '@hono/zod-openapi'; import { CoWorkingSpaceRecommendationResponseSchema, CoWorkingSpaceRecommendationSchema, VoucherRecommendationResponseSchema, VoucherRecommendationSchema, + PostVoucherReviewParamsSchema, + PostVoucherReviewResponseSchema, + PostVoucherReviewBodySchema, + PostCoWorkingSpaceReviewParamsSchema, + PostCoWorkingSpaceReviewResponseSchema, + DeleteVoucherReviewResponseSchema, + DeleteVoucherReviewParamsSchema, + DeleteCoWorkingSpaceReviewParamsSchema, + DeleteCoWorkingSpaceReviewResponseSchema, } from '~/types/recommendations.types'; import { validationErrorResponse, serverErrorResponse, + errorResponse, } from '~/types/responses.type'; export const postRecommendationVoucherRoute = createRoute({ @@ -68,3 +78,119 @@ export const postRecommendationCoWorkingSpaceRoute = createRoute({ 500: serverErrorResponse, }, }); + +export const postVoucherReviewRoute = createRoute({ + operationId: 'postVoucherReview', + tags: ['recommendation'], + method: 'post', + path: '/recommendation/voucher/{voucherId}/review', + description: 'Create a new review for a voucher recommendation', + request: { + params: PostVoucherReviewParamsSchema, + body: { + content: { + 'application/json': { + schema: PostVoucherReviewBodySchema, + }, + }, + }, + }, + responses: { + 201: { + description: 'Voucher review created', + content: { + 'application/json': { + schema: PostVoucherReviewResponseSchema, + }, + }, + }, + 400: validationErrorResponse, + 500: serverErrorResponse, + }, +}); + +export const postCoWorkingSpaceReviewRoute = createRoute({ + operationId: 'createCoWorkingSpaceReview', + tags: ['recommendation'], + method: 'post', + path: '/recommendation/co-working-space/{coWorkingSpaceId}/review', + request: { + params: PostCoWorkingSpaceReviewParamsSchema, + body: { + content: { + 'application/json': { + schema: z.object({ + rating: z.number().int().min(1).max(5).openapi({ + example: 4, + description: 'Rating for the voucher (1-5)', + }), + review: z.string().openapi({ + example: 'Good value for money!', + description: 'Detailed review about the voucher', + }), + }), + }, + }, + }, + }, + responses: { + 201: { + description: 'Co-working space review created', + content: { + 'application/json': { + schema: PostCoWorkingSpaceReviewResponseSchema, + }, + }, + }, + 400: validationErrorResponse, + 500: serverErrorResponse, + }, +}); + +export const deleteVoucherReviewRoute = createRoute({ + operationId: 'deleteVoucherReview', + tags: ['recommendation'], + method: 'delete', + path: '/recommendation/voucher/{voucherId}/review/{userId}', + description: 'Delete a review for a voucher recommendation', + request: { + params: DeleteVoucherReviewParamsSchema, + }, + responses: { + 201: { + description: 'Review deleted successfully', + content: { + 'application/json': { + schema: DeleteVoucherReviewResponseSchema, + }, + }, + }, + 400: validationErrorResponse, + 404: errorResponse, + 500: serverErrorResponse, + }, +}); + +export const deleteCoWorkingSpaceReviewRoute = createRoute({ + operationId: 'deleteCoWorkingSpaceReview', + tags: ['recommendation'], + method: 'delete', + path: '/recommendation/co-working-space/{coWorkingSpaceId}/review/{userId}', + description: 'Delete a review for a co-working space recommendation', + request: { + params: DeleteCoWorkingSpaceReviewParamsSchema, + }, + responses: { + 201: { + description: 'Review deleted successfully', + content: { + 'application/json': { + schema: DeleteCoWorkingSpaceReviewResponseSchema, + }, + }, + }, + 400: validationErrorResponse, + 404: errorResponse, + 500: serverErrorResponse, + }, +}); diff --git a/src/types/recommendations.types.ts b/src/types/recommendations.types.ts index e5507a1..3a6e17e 100644 --- a/src/types/recommendations.types.ts +++ b/src/types/recommendations.types.ts @@ -1,5 +1,7 @@ import { z } from '@hono/zod-openapi'; import { addHours } from './calendar.types'; +import { createSelectSchema } from 'drizzle-zod'; +import { coWorkingSpaceReviews, voucherReviews } from '~/db/schema'; export const VoucherRecommendationSchema = z.object({ title: z.string().openapi({ example: 'Voucher Recommendation Title' }), @@ -42,3 +44,116 @@ export const CoWorkingSpaceRecommendationResponseSchema = CoWorkingSpaceRecommendationSchema.extend({ id: z.string().openapi({ example: 'string' }), }); + +export const VoucherReviewSchema = z.object({ + userId: z.string().openapi({ + example: 'user-id', + description: 'ID of the user who reviewed the voucher', + }), + voucherId: z.string().uuid().openapi({ + example: '123e4567-e89b-12d3-a456-426614174000', + description: 'UUID of the voucher recommendation', + }), + rating: z.number().int().min(1).max(5).openapi({ + example: 4, + description: 'Rating for the voucher (1-5)', + }), + review: z.string().openapi({ + example: 'Good value for money!', + description: 'Detailed review about the voucher', + }), +}); + +export const PostVoucherReviewParamsSchema = z.object({ + voucherId: z.string().openapi({ + example: 'example-voucher-id', + description: 'CUID2 of the voucher recommendation', + }), +}); + +export const PostVoucherReviewBodySchema = z.object({ + rating: z.number().int().min(1).max(5).openapi({ + example: 4, + description: 'Rating for the voucher (1-5)', + }), + review: z.string().openapi({ + example: 'Good value for money!', + description: 'Detailed review about the voucher', + }), +}); + +export const PostVoucherReviewResponseSchema = createSelectSchema( + voucherReviews, + { + voucherId: z.string().openapi({ example: 'recommendation-id' }), + userId: z.string().openapi({ example: 'user-id' }), + rating: z.number().int().min(1).max(5).openapi({ example: 4 }), + review: z.string().openapi({ example: 'Good value for money!' }), + }, +); + +export const PostCoWorkingSpaceReviewParamsSchema = z.object({ + coWorkingSpaceId: z.string().openapi({ + example: 'example-coWorkingSpace-id', + description: 'ID of the co-working space recommendation', + }), +}); + +export const PostCoWorkingSpaceReviewResponseSchema = createSelectSchema( + coWorkingSpaceReviews, + { + coWorkingSpaceId: z.string().openapi({ example: 'recommendation-id' }), + userId: z.string().openapi({ example: 'user-id' }), + rating: z.number().int().min(1).max(5).openapi({ example: 5 }), + review: z + .string() + .openapi({ example: 'Great place with excellent Wi-Fi!' }), + }, +); + +export const GetVoucherReviewParamsSchema = z.object({ + voucherId: z.string().openapi({ + example: 'voucher-id', + description: 'ID of the voucher being reviewed', + }), + userId: z.string().openapi({ + example: 'user-id', + description: 'ID of the review to delete', + }), +}); + +export const DeleteVoucherReviewParamsSchema = z.object({ + voucherId: z.string().openapi({ + example: 'voucher-id', + description: 'ID of the voucher being reviewed', + }), + userId: z.string().openapi({ + example: 'user-id', + description: 'ID of the review to delete', + }), +}); + +export const DeleteVoucherReviewResponseSchema = z.object({ + success: z.boolean().openapi({ + example: true, + description: 'Indicates whether the review was deleted successfully', + }), +}); + +export const DeleteCoWorkingSpaceReviewParamsSchema = z.object({ + coWorkingSpaceId: z.string().openapi({ + example: 'coWorkingSpace-id', + description: 'ID of the co-working space recommendation', + }), + userId: z.string().openapi({ + example: 'user-id', + description: 'ID of the review to delete', + }), +}); + +export const DeleteCoWorkingSpaceReviewResponseSchema = z.object({ + success: z.boolean().openapi({ + example: true, + description: 'Indicates whether the review was deleted successfully', + }), +});