diff --git a/apps/backend/drizzle/mysql/0000_numerous_stepford_cuckoos.sql b/apps/backend/drizzle/mysql/0000_numerous_stepford_cuckoos.sql new file mode 100644 index 000000000..4ff63b55b --- /dev/null +++ b/apps/backend/drizzle/mysql/0000_numerous_stepford_cuckoos.sql @@ -0,0 +1,293 @@ +CREATE TABLE `undb_api_token` ( + `id` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `user_id` varchar(36) NOT NULL, + `space_id` varchar(36) NOT NULL, + `token` varchar(36) NOT NULL, + CONSTRAINT `undb_api_token_id` PRIMARY KEY(`id`), + CONSTRAINT `undb_api_token_token_unique` UNIQUE(`token`) +); +--> statement-breakpoint +CREATE TABLE `undb_attachment_mapping` ( + `attachment_id` varchar(36) NOT NULL, + `table_id` varchar(36) NOT NULL, + `record_id` varchar(36) NOT NULL, + `field_id` varchar(36) NOT NULL, + CONSTRAINT `pk` PRIMARY KEY(`attachment_id`,`table_id`,`record_id`,`field_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_attachment` ( + `id` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `size` int NOT NULL, + `mime_type` varchar(255) NOT NULL, + `url` varchar(255) NOT NULL, + `token` varchar(36), + `created_at` bigint NOT NULL, + `created_by` varchar(36) NOT NULL, + `space_id` varchar(36) NOT NULL, + CONSTRAINT `undb_attachment_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `undb_audit` ( + `id` varchar(36) NOT NULL, + `timestamp` bigint NOT NULL, + `detail` json, + `meta` json, + `op` text NOT NULL, + `table_id` varchar(36) NOT NULL, + `record_id` varchar(36) NOT NULL, + `operator_id` varchar(36) NOT NULL, + `space_id` varchar(36) NOT NULL, + CONSTRAINT `undb_audit_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `undb_base` ( + `id` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `space_id` varchar(36) NOT NULL, + `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP), + `created_by` varchar(36) NOT NULL, + `updated_at` text NOT NULL, + `updated_by` varchar(36) NOT NULL, + CONSTRAINT `undb_base_id` PRIMARY KEY(`id`), + CONSTRAINT `base_name_unique_idx` UNIQUE(`name`,`space_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_dashboard_table_id_mapping` ( + `dashboard_id` varchar(36) NOT NULL, + `table_id` varchar(36) NOT NULL, + CONSTRAINT `pk` PRIMARY KEY(`dashboard_id`,`table_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_dashboard` ( + `id` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `description` text, + `base_id` varchar(36) NOT NULL, + `space_id` varchar(36) NOT NULL, + `widgets` json, + `layout` json, + `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP), + `created_by` varchar(36) NOT NULL, + `updated_at` text NOT NULL, + `updated_by` varchar(36) NOT NULL, + CONSTRAINT `undb_dashboard_id` PRIMARY KEY(`id`), + CONSTRAINT `dashboard_name_unique_idx` UNIQUE(`name`,`base_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_email_verification_code` ( + `id` int AUTO_INCREMENT NOT NULL, + `code` text NOT NULL, + `user_id` varchar(36), + `email` text NOT NULL, + `expires_at` bigint NOT NULL, + CONSTRAINT `undb_email_verification_code_id` PRIMARY KEY(`id`), + CONSTRAINT `undb_email_verification_code_user_id_unique` UNIQUE(`user_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_invitation` ( + `id` varchar(36) NOT NULL, + `email` varchar(255) NOT NULL, + `role` text NOT NULL, + `status` text NOT NULL, + `space_id` varchar(36) NOT NULL, + `invited_at` bigint NOT NULL, + `inviter_id` varchar(36) NOT NULL, + CONSTRAINT `undb_invitation_id` PRIMARY KEY(`id`), + CONSTRAINT `invitation_unique_idx` UNIQUE(`email`,`space_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_oauth_account` ( + `provider_id` varchar(36) NOT NULL, + `provider_user_id` varchar(36) NOT NULL, + `user_id` varchar(36) NOT NULL, + CONSTRAINT `undb_oauth_account_provider_id_provider_user_id_pk` PRIMARY KEY(`provider_id`,`provider_user_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_outbox` ( + `id` varchar(36) NOT NULL, + `payload` json NOT NULL, + `meta` json, + `timestamp` bigint NOT NULL, + `user_id` varchar(36), + `name` text NOT NULL, + `space_id` varchar(36) NOT NULL, + CONSTRAINT `undb_outbox_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `undb_password_reset_token` ( + `id` int AUTO_INCREMENT NOT NULL, + `token` varchar(36) NOT NULL, + `user_id` varchar(36) NOT NULL, + `expires_at` bigint NOT NULL, + CONSTRAINT `undb_password_reset_token_id` PRIMARY KEY(`id`), + CONSTRAINT `undb_password_reset_token_token_unique` UNIQUE(`token`) +); +--> statement-breakpoint +CREATE TABLE `undb_reference_id_mapping` ( + `field_id` varchar(36) NOT NULL, + `table_id` varchar(36) NOT NULL, + `symmetric_field_id` varchar(36), + `foreign_table_id` varchar(36) NOT NULL, + CONSTRAINT `reference_id_mapping_unique_idx` UNIQUE(`field_id`,`table_id`,`symmetric_field_id`,`foreign_table_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_rollup_id_mapping` ( + `field_id` varchar(36) NOT NULL, + `table_id` varchar(36) NOT NULL, + `rollup_id` varchar(36) NOT NULL, + `rollup_table_id` varchar(36) NOT NULL, + CONSTRAINT `undb_rollup_id_mapping_field_id_rollup_id_pk` PRIMARY KEY(`field_id`,`rollup_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_session` ( + `id` varchar(36) NOT NULL, + `user_id` varchar(36) NOT NULL, + `expires_at` timestamp NOT NULL, + `space_id` varchar(36) NOT NULL, + CONSTRAINT `undb_session_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `undb_share` ( + `id` varchar(36) NOT NULL, + `target_type` varchar(255) NOT NULL, + `target_id` varchar(36) NOT NULL, + `enabled` boolean NOT NULL, + `space_id` varchar(36) NOT NULL, + CONSTRAINT `undb_share_id` PRIMARY KEY(`id`), + CONSTRAINT `share_unique_idx` UNIQUE(`target_type`,`target_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_space` ( + `id` varchar(36) NOT NULL, + `name` varchar(255), + `is_personal` boolean NOT NULL, + `avatar` text, + `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP), + `created_by` varchar(36) NOT NULL, + `updated_at` text NOT NULL, + `updated_by` varchar(36) NOT NULL, + `deleted_at` bigint, + `deleted_by` varchar(36), + CONSTRAINT `undb_space_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +CREATE TABLE `undb_space_member` ( + `id` varchar(36) NOT NULL, + `user_id` varchar(36) NOT NULL, + `role` text NOT NULL, + `space_id` varchar(36) NOT NULL, + CONSTRAINT `undb_space_member_id` PRIMARY KEY(`id`), + CONSTRAINT `space_member_unique_idx` UNIQUE(`user_id`,`space_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_table_id_mapping` ( + `table_id` varchar(36) NOT NULL, + `subject_id` varchar(36) NOT NULL, + CONSTRAINT `undb_table_id_mapping_table_id_subject_id_pk` PRIMARY KEY(`table_id`,`subject_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_table` ( + `id` varchar(36) NOT NULL, + `name` varchar(255) NOT NULL, + `base_id` varchar(36) NOT NULL, + `space_id` varchar(36) NOT NULL, + `schema` json NOT NULL, + `views` json NOT NULL, + `forms` json, + `rls` json, + `widgets` json, + `created_at` text NOT NULL DEFAULT (CURRENT_TIMESTAMP), + `created_by` varchar(36) NOT NULL, + `updated_at` text NOT NULL, + `updated_by` varchar(36) NOT NULL, + CONSTRAINT `undb_table_id` PRIMARY KEY(`id`), + CONSTRAINT `table_name_unique_idx` UNIQUE(`name`,`base_id`) +); +--> statement-breakpoint +CREATE TABLE `undb_user` ( + `id` varchar(36) NOT NULL, + `username` varchar(255) NOT NULL, + `email` varchar(255) NOT NULL, + `email_verified` boolean NOT NULL DEFAULT false, + `password` text NOT NULL, + `avatar` text, + `otp_secret` text, + CONSTRAINT `undb_user_id` PRIMARY KEY(`id`), + CONSTRAINT `undb_user_email_unique` UNIQUE(`email`) +); +--> statement-breakpoint +CREATE TABLE `undb_webhook` ( + `id` varchar(36) NOT NULL, + `name` text NOT NULL, + `url` varchar(255) NOT NULL, + `method` text NOT NULL, + `enabled` boolean NOT NULL, + `table_id` varchar(36) NOT NULL, + `headers` json NOT NULL, + `condition` json, + `event` text NOT NULL, + `space_id` varchar(36) NOT NULL, + CONSTRAINT `undb_webhook_id` PRIMARY KEY(`id`) +); +--> statement-breakpoint +ALTER TABLE `undb_api_token` ADD CONSTRAINT `undb_api_token_user_id_undb_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_api_token` ADD CONSTRAINT `undb_api_token_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_attachment_mapping` ADD CONSTRAINT `undb_attachment_mapping_attachment_id_undb_attachment_id_fk` FOREIGN KEY (`attachment_id`) REFERENCES `undb_attachment`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_attachment_mapping` ADD CONSTRAINT `undb_attachment_mapping_table_id_undb_table_id_fk` FOREIGN KEY (`table_id`) REFERENCES `undb_table`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_attachment` ADD CONSTRAINT `undb_attachment_created_by_undb_user_id_fk` FOREIGN KEY (`created_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_attachment` ADD CONSTRAINT `undb_attachment_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_audit` ADD CONSTRAINT `undb_audit_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_base` ADD CONSTRAINT `undb_base_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_base` ADD CONSTRAINT `undb_base_created_by_undb_user_id_fk` FOREIGN KEY (`created_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_base` ADD CONSTRAINT `undb_base_updated_by_undb_user_id_fk` FOREIGN KEY (`updated_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_dashboard_table_id_mapping` ADD CONSTRAINT `dashboard_table_id_mapping_dashboard_id_fk` FOREIGN KEY (`dashboard_id`) REFERENCES `undb_dashboard`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_dashboard_table_id_mapping` ADD CONSTRAINT `dashboard_table_id_mapping_table_id_fk` FOREIGN KEY (`table_id`) REFERENCES `undb_table`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_dashboard` ADD CONSTRAINT `undb_dashboard_base_id_undb_base_id_fk` FOREIGN KEY (`base_id`) REFERENCES `undb_base`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_dashboard` ADD CONSTRAINT `undb_dashboard_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_dashboard` ADD CONSTRAINT `undb_dashboard_created_by_undb_user_id_fk` FOREIGN KEY (`created_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_dashboard` ADD CONSTRAINT `undb_dashboard_updated_by_undb_user_id_fk` FOREIGN KEY (`updated_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_email_verification_code` ADD CONSTRAINT `undb_email_verification_code_user_id_undb_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_invitation` ADD CONSTRAINT `undb_invitation_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_invitation` ADD CONSTRAINT `undb_invitation_inviter_id_undb_user_id_fk` FOREIGN KEY (`inviter_id`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_oauth_account` ADD CONSTRAINT `undb_oauth_account_user_id_undb_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_outbox` ADD CONSTRAINT `undb_outbox_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_password_reset_token` ADD CONSTRAINT `undb_password_reset_token_user_id_undb_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_session` ADD CONSTRAINT `undb_session_user_id_undb_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_session` ADD CONSTRAINT `undb_session_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_share` ADD CONSTRAINT `undb_share_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_space` ADD CONSTRAINT `undb_space_created_by_undb_user_id_fk` FOREIGN KEY (`created_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_space` ADD CONSTRAINT `undb_space_updated_by_undb_user_id_fk` FOREIGN KEY (`updated_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_space` ADD CONSTRAINT `undb_space_deleted_by_undb_user_id_fk` FOREIGN KEY (`deleted_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_space_member` ADD CONSTRAINT `undb_space_member_user_id_undb_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_space_member` ADD CONSTRAINT `undb_space_member_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_table_id_mapping` ADD CONSTRAINT `table_id_mapping_table_id_fk` FOREIGN KEY (`table_id`) REFERENCES `undb_table`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_table` ADD CONSTRAINT `undb_table_base_id_undb_base_id_fk` FOREIGN KEY (`base_id`) REFERENCES `undb_base`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_table` ADD CONSTRAINT `undb_table_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_table` ADD CONSTRAINT `undb_table_created_by_undb_user_id_fk` FOREIGN KEY (`created_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_table` ADD CONSTRAINT `undb_table_updated_by_undb_user_id_fk` FOREIGN KEY (`updated_by`) REFERENCES `undb_user`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_webhook` ADD CONSTRAINT `undb_webhook_table_id_undb_table_id_fk` FOREIGN KEY (`table_id`) REFERENCES `undb_table`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE `undb_webhook` ADD CONSTRAINT `undb_webhook_space_id_undb_space_id_fk` FOREIGN KEY (`space_id`) REFERENCES `undb_space`(`id`) ON DELETE no action ON UPDATE no action;--> statement-breakpoint +CREATE INDEX `api_token_space_id_idx` ON `undb_api_token` (`space_id`);--> statement-breakpoint +CREATE INDEX `api_token_user_id_idx` ON `undb_api_token` (`user_id`);--> statement-breakpoint +CREATE INDEX `attachment_size_idx` ON `undb_attachment` (`size`);--> statement-breakpoint +CREATE INDEX `attachment_space_id_idx` ON `undb_attachment` (`space_id`);--> statement-breakpoint +CREATE INDEX `audit_table_id_idx` ON `undb_audit` (`table_id`);--> statement-breakpoint +CREATE INDEX `audit_space_id_idx` ON `undb_audit` (`space_id`);--> statement-breakpoint +CREATE INDEX `audit_record_id_idx` ON `undb_audit` (`record_id`);--> statement-breakpoint +CREATE INDEX `base_space_id_idx` ON `undb_base` (`space_id`);--> statement-breakpoint +CREATE INDEX `dashboard_base_id_idx` ON `undb_dashboard` (`base_id`);--> statement-breakpoint +CREATE INDEX `dashboard_space_id_idx` ON `undb_dashboard` (`space_id`);--> statement-breakpoint +CREATE INDEX `invitation_space_id_idx` ON `undb_invitation` (`space_id`);--> statement-breakpoint +CREATE INDEX `outbox_space_id_idx` ON `undb_outbox` (`space_id`);--> statement-breakpoint +CREATE INDEX `password_reset_token_user_id_idx` ON `undb_password_reset_token` (`user_id`);--> statement-breakpoint +CREATE INDEX `share_space_id_idx` ON `undb_share` (`space_id`);--> statement-breakpoint +CREATE INDEX `space_name_idx` ON `undb_space` (`name`);--> statement-breakpoint +CREATE INDEX `table_base_id_idx` ON `undb_table` (`base_id`);--> statement-breakpoint +CREATE INDEX `table_space_id_idx` ON `undb_table` (`space_id`);--> statement-breakpoint +CREATE INDEX `user_username_idx` ON `undb_user` (`username`);--> statement-breakpoint +CREATE INDEX `user_email_idx` ON `undb_user` (`email`);--> statement-breakpoint +CREATE INDEX `webhook_table_id_idx` ON `undb_webhook` (`table_id`);--> statement-breakpoint +CREATE INDEX `webhook_space_id_idx` ON `undb_webhook` (`space_id`);--> statement-breakpoint +CREATE INDEX `webhook_url_idx` ON `undb_webhook` (`url`); \ No newline at end of file diff --git a/apps/backend/drizzle/mysql/meta/0000_snapshot.json b/apps/backend/drizzle/mysql/meta/0000_snapshot.json new file mode 100644 index 000000000..a793e94b9 --- /dev/null +++ b/apps/backend/drizzle/mysql/meta/0000_snapshot.json @@ -0,0 +1,2102 @@ +{ + "version": "5", + "dialect": "mysql", + "id": "8470ec10-c745-4420-920f-ce5ba9600c78", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "undb_api_token": { + "name": "undb_api_token", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "api_token_space_id_idx": { + "name": "api_token_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + }, + "api_token_user_id_idx": { + "name": "api_token_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_api_token_user_id_undb_user_id_fk": { + "name": "undb_api_token_user_id_undb_user_id_fk", + "tableFrom": "undb_api_token", + "tableTo": "undb_user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_api_token_space_id_undb_space_id_fk": { + "name": "undb_api_token_space_id_undb_space_id_fk", + "tableFrom": "undb_api_token", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_api_token_id": { + "name": "undb_api_token_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "undb_api_token_token_unique": { + "name": "undb_api_token_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "undb_attachment_mapping": { + "name": "undb_attachment_mapping", + "columns": { + "attachment_id": { + "name": "attachment_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "table_id": { + "name": "table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "record_id": { + "name": "record_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "field_id": { + "name": "field_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "undb_attachment_mapping_attachment_id_undb_attachment_id_fk": { + "name": "undb_attachment_mapping_attachment_id_undb_attachment_id_fk", + "tableFrom": "undb_attachment_mapping", + "tableTo": "undb_attachment", + "columnsFrom": [ + "attachment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_attachment_mapping_table_id_undb_table_id_fk": { + "name": "undb_attachment_mapping_table_id_undb_table_id_fk", + "tableFrom": "undb_attachment_mapping", + "tableTo": "undb_table", + "columnsFrom": [ + "table_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "pk": { + "name": "pk", + "columns": [ + "attachment_id", + "table_id", + "record_id", + "field_id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_attachment": { + "name": "undb_attachment", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mime_type": { + "name": "mime_type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "varchar(36)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "attachment_size_idx": { + "name": "attachment_size_idx", + "columns": [ + "size" + ], + "isUnique": false + }, + "attachment_space_id_idx": { + "name": "attachment_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_attachment_created_by_undb_user_id_fk": { + "name": "undb_attachment_created_by_undb_user_id_fk", + "tableFrom": "undb_attachment", + "tableTo": "undb_user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_attachment_space_id_undb_space_id_fk": { + "name": "undb_attachment_space_id_undb_space_id_fk", + "tableFrom": "undb_attachment", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_attachment_id": { + "name": "undb_attachment_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_audit": { + "name": "undb_audit", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "timestamp": { + "name": "timestamp", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "detail": { + "name": "detail", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "op": { + "name": "op", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "table_id": { + "name": "table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "record_id": { + "name": "record_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "operator_id": { + "name": "operator_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "audit_table_id_idx": { + "name": "audit_table_id_idx", + "columns": [ + "table_id" + ], + "isUnique": false + }, + "audit_space_id_idx": { + "name": "audit_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + }, + "audit_record_id_idx": { + "name": "audit_record_id_idx", + "columns": [ + "record_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_audit_space_id_undb_space_id_fk": { + "name": "undb_audit_space_id_undb_space_id_fk", + "tableFrom": "undb_audit", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_audit_id": { + "name": "undb_audit_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_base": { + "name": "undb_base", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "created_by": { + "name": "created_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "base_space_id_idx": { + "name": "base_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_base_space_id_undb_space_id_fk": { + "name": "undb_base_space_id_undb_space_id_fk", + "tableFrom": "undb_base", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_base_created_by_undb_user_id_fk": { + "name": "undb_base_created_by_undb_user_id_fk", + "tableFrom": "undb_base", + "tableTo": "undb_user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_base_updated_by_undb_user_id_fk": { + "name": "undb_base_updated_by_undb_user_id_fk", + "tableFrom": "undb_base", + "tableTo": "undb_user", + "columnsFrom": [ + "updated_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_base_id": { + "name": "undb_base_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "base_name_unique_idx": { + "name": "base_name_unique_idx", + "columns": [ + "name", + "space_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_dashboard_table_id_mapping": { + "name": "undb_dashboard_table_id_mapping", + "columns": { + "dashboard_id": { + "name": "dashboard_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "table_id": { + "name": "table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "dashboard_table_id_mapping_dashboard_id_fk": { + "name": "dashboard_table_id_mapping_dashboard_id_fk", + "tableFrom": "undb_dashboard_table_id_mapping", + "tableTo": "undb_dashboard", + "columnsFrom": [ + "dashboard_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "dashboard_table_id_mapping_table_id_fk": { + "name": "dashboard_table_id_mapping_table_id_fk", + "tableFrom": "undb_dashboard_table_id_mapping", + "tableTo": "undb_table", + "columnsFrom": [ + "table_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "pk": { + "name": "pk", + "columns": [ + "dashboard_id", + "table_id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_dashboard": { + "name": "undb_dashboard", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "base_id": { + "name": "base_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "widgets": { + "name": "widgets", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "layout": { + "name": "layout", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "created_by": { + "name": "created_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "dashboard_base_id_idx": { + "name": "dashboard_base_id_idx", + "columns": [ + "base_id" + ], + "isUnique": false + }, + "dashboard_space_id_idx": { + "name": "dashboard_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_dashboard_base_id_undb_base_id_fk": { + "name": "undb_dashboard_base_id_undb_base_id_fk", + "tableFrom": "undb_dashboard", + "tableTo": "undb_base", + "columnsFrom": [ + "base_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_dashboard_space_id_undb_space_id_fk": { + "name": "undb_dashboard_space_id_undb_space_id_fk", + "tableFrom": "undb_dashboard", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_dashboard_created_by_undb_user_id_fk": { + "name": "undb_dashboard_created_by_undb_user_id_fk", + "tableFrom": "undb_dashboard", + "tableTo": "undb_user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_dashboard_updated_by_undb_user_id_fk": { + "name": "undb_dashboard_updated_by_undb_user_id_fk", + "tableFrom": "undb_dashboard", + "tableTo": "undb_user", + "columnsFrom": [ + "updated_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_dashboard_id": { + "name": "undb_dashboard_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "dashboard_name_unique_idx": { + "name": "dashboard_name_unique_idx", + "columns": [ + "name", + "base_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_email_verification_code": { + "name": "undb_email_verification_code", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "undb_email_verification_code_user_id_undb_user_id_fk": { + "name": "undb_email_verification_code_user_id_undb_user_id_fk", + "tableFrom": "undb_email_verification_code", + "tableTo": "undb_user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_email_verification_code_id": { + "name": "undb_email_verification_code_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "undb_email_verification_code_user_id_unique": { + "name": "undb_email_verification_code_user_id_unique", + "columns": [ + "user_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_invitation": { + "name": "undb_invitation", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "invited_at": { + "name": "invited_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "inviter_id": { + "name": "inviter_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "invitation_space_id_idx": { + "name": "invitation_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_invitation_space_id_undb_space_id_fk": { + "name": "undb_invitation_space_id_undb_space_id_fk", + "tableFrom": "undb_invitation", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_invitation_inviter_id_undb_user_id_fk": { + "name": "undb_invitation_inviter_id_undb_user_id_fk", + "tableFrom": "undb_invitation", + "tableTo": "undb_user", + "columnsFrom": [ + "inviter_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_invitation_id": { + "name": "undb_invitation_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "invitation_unique_idx": { + "name": "invitation_unique_idx", + "columns": [ + "email", + "space_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_oauth_account": { + "name": "undb_oauth_account", + "columns": { + "provider_id": { + "name": "provider_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_user_id": { + "name": "provider_user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "undb_oauth_account_user_id_undb_user_id_fk": { + "name": "undb_oauth_account_user_id_undb_user_id_fk", + "tableFrom": "undb_oauth_account", + "tableTo": "undb_user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_oauth_account_provider_id_provider_user_id_pk": { + "name": "undb_oauth_account_provider_id_provider_user_id_pk", + "columns": [ + "provider_id", + "provider_user_id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_outbox": { + "name": "undb_outbox", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "json", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "meta": { + "name": "meta", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "timestamp": { + "name": "timestamp", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "outbox_space_id_idx": { + "name": "outbox_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_outbox_space_id_undb_space_id_fk": { + "name": "undb_outbox_space_id_undb_space_id_fk", + "tableFrom": "undb_outbox", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_outbox_id": { + "name": "undb_outbox_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_password_reset_token": { + "name": "undb_password_reset_token", + "columns": { + "id": { + "name": "id", + "type": "int", + "primaryKey": false, + "notNull": true, + "autoincrement": true + }, + "token": { + "name": "token", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "password_reset_token_user_id_idx": { + "name": "password_reset_token_user_id_idx", + "columns": [ + "user_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_password_reset_token_user_id_undb_user_id_fk": { + "name": "undb_password_reset_token_user_id_undb_user_id_fk", + "tableFrom": "undb_password_reset_token", + "tableTo": "undb_user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_password_reset_token_id": { + "name": "undb_password_reset_token_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "undb_password_reset_token_token_unique": { + "name": "undb_password_reset_token_token_unique", + "columns": [ + "token" + ] + } + }, + "checkConstraint": {} + }, + "undb_reference_id_mapping": { + "name": "undb_reference_id_mapping", + "columns": { + "field_id": { + "name": "field_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "table_id": { + "name": "table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "symmetric_field_id": { + "name": "symmetric_field_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "foreign_table_id": { + "name": "foreign_table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "reference_id_mapping_unique_idx": { + "name": "reference_id_mapping_unique_idx", + "columns": [ + "field_id", + "table_id", + "symmetric_field_id", + "foreign_table_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_rollup_id_mapping": { + "name": "undb_rollup_id_mapping", + "columns": { + "field_id": { + "name": "field_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "table_id": { + "name": "table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rollup_id": { + "name": "rollup_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rollup_table_id": { + "name": "rollup_table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "undb_rollup_id_mapping_field_id_rollup_id_pk": { + "name": "undb_rollup_id_mapping_field_id_rollup_id_pk", + "columns": [ + "field_id", + "rollup_id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_session": { + "name": "undb_session", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "undb_session_user_id_undb_user_id_fk": { + "name": "undb_session_user_id_undb_user_id_fk", + "tableFrom": "undb_session", + "tableTo": "undb_user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_session_space_id_undb_space_id_fk": { + "name": "undb_session_space_id_undb_space_id_fk", + "tableFrom": "undb_session", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_session_id": { + "name": "undb_session_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_share": { + "name": "undb_share", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_type": { + "name": "target_type", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "target_id": { + "name": "target_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "share_space_id_idx": { + "name": "share_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_share_space_id_undb_space_id_fk": { + "name": "undb_share_space_id_undb_space_id_fk", + "tableFrom": "undb_share", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_share_id": { + "name": "undb_share_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "share_unique_idx": { + "name": "share_unique_idx", + "columns": [ + "target_type", + "target_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_space": { + "name": "undb_space", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_personal": { + "name": "is_personal", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "created_by": { + "name": "created_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "deleted_by": { + "name": "deleted_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "space_name_idx": { + "name": "space_name_idx", + "columns": [ + "name" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_space_created_by_undb_user_id_fk": { + "name": "undb_space_created_by_undb_user_id_fk", + "tableFrom": "undb_space", + "tableTo": "undb_user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_space_updated_by_undb_user_id_fk": { + "name": "undb_space_updated_by_undb_user_id_fk", + "tableFrom": "undb_space", + "tableTo": "undb_user", + "columnsFrom": [ + "updated_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_space_deleted_by_undb_user_id_fk": { + "name": "undb_space_deleted_by_undb_user_id_fk", + "tableFrom": "undb_space", + "tableTo": "undb_user", + "columnsFrom": [ + "deleted_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_space_id": { + "name": "undb_space_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_space_member": { + "name": "undb_space_member", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "undb_space_member_user_id_undb_user_id_fk": { + "name": "undb_space_member_user_id_undb_user_id_fk", + "tableFrom": "undb_space_member", + "tableTo": "undb_user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_space_member_space_id_undb_space_id_fk": { + "name": "undb_space_member_space_id_undb_space_id_fk", + "tableFrom": "undb_space_member", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_space_member_id": { + "name": "undb_space_member_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "space_member_unique_idx": { + "name": "space_member_unique_idx", + "columns": [ + "user_id", + "space_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_table_id_mapping": { + "name": "undb_table_id_mapping", + "columns": { + "table_id": { + "name": "table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "table_id_mapping_table_id_fk": { + "name": "table_id_mapping_table_id_fk", + "tableFrom": "undb_table_id_mapping", + "tableTo": "undb_table", + "columnsFrom": [ + "table_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_table_id_mapping_table_id_subject_id_pk": { + "name": "undb_table_id_mapping_table_id_subject_id_pk", + "columns": [ + "table_id", + "subject_id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + }, + "undb_table": { + "name": "undb_table", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "base_id": { + "name": "base_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schema": { + "name": "schema", + "type": "json", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "views": { + "name": "views", + "type": "json", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "forms": { + "name": "forms", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rls": { + "name": "rls", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "widgets": { + "name": "widgets", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "created_by": { + "name": "created_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "table_base_id_idx": { + "name": "table_base_id_idx", + "columns": [ + "base_id" + ], + "isUnique": false + }, + "table_space_id_idx": { + "name": "table_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_table_base_id_undb_base_id_fk": { + "name": "undb_table_base_id_undb_base_id_fk", + "tableFrom": "undb_table", + "tableTo": "undb_base", + "columnsFrom": [ + "base_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_table_space_id_undb_space_id_fk": { + "name": "undb_table_space_id_undb_space_id_fk", + "tableFrom": "undb_table", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_table_created_by_undb_user_id_fk": { + "name": "undb_table_created_by_undb_user_id_fk", + "tableFrom": "undb_table", + "tableTo": "undb_user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_table_updated_by_undb_user_id_fk": { + "name": "undb_table_updated_by_undb_user_id_fk", + "tableFrom": "undb_table", + "tableTo": "undb_user", + "columnsFrom": [ + "updated_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_table_id": { + "name": "undb_table_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "table_name_unique_idx": { + "name": "table_name_unique_idx", + "columns": [ + "name", + "base_id" + ] + } + }, + "checkConstraint": {} + }, + "undb_user": { + "name": "undb_user", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "otp_secret": { + "name": "otp_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "user_username_idx": { + "name": "user_username_idx", + "columns": [ + "username" + ], + "isUnique": false + }, + "user_email_idx": { + "name": "user_email_idx", + "columns": [ + "email" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "undb_user_id": { + "name": "undb_user_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": { + "undb_user_email_unique": { + "name": "undb_user_email_unique", + "columns": [ + "email" + ] + } + }, + "checkConstraint": {} + }, + "undb_webhook": { + "name": "undb_webhook", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "table_id": { + "name": "table_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "headers": { + "name": "headers", + "type": "json", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "condition": { + "name": "condition", + "type": "json", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "event": { + "name": "event", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "space_id": { + "name": "space_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "webhook_table_id_idx": { + "name": "webhook_table_id_idx", + "columns": [ + "table_id" + ], + "isUnique": false + }, + "webhook_space_id_idx": { + "name": "webhook_space_id_idx", + "columns": [ + "space_id" + ], + "isUnique": false + }, + "webhook_url_idx": { + "name": "webhook_url_idx", + "columns": [ + "url" + ], + "isUnique": false + } + }, + "foreignKeys": { + "undb_webhook_table_id_undb_table_id_fk": { + "name": "undb_webhook_table_id_undb_table_id_fk", + "tableFrom": "undb_webhook", + "tableTo": "undb_table", + "columnsFrom": [ + "table_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "undb_webhook_space_id_undb_space_id_fk": { + "name": "undb_webhook_space_id_undb_space_id_fk", + "tableFrom": "undb_webhook", + "tableTo": "undb_space", + "columnsFrom": [ + "space_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "undb_webhook_id": { + "name": "undb_webhook_id", + "columns": [ + "id" + ] + } + }, + "uniqueConstraints": {}, + "checkConstraint": {} + } + }, + "views": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "tables": {}, + "indexes": {} + } +} \ No newline at end of file diff --git a/apps/backend/drizzle/mysql/meta/_journal.json b/apps/backend/drizzle/mysql/meta/_journal.json new file mode 100644 index 000000000..589d6ace4 --- /dev/null +++ b/apps/backend/drizzle/mysql/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "mysql", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1737522284940, + "tag": "0000_numerous_stepford_cuckoos", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/apps/backend/migrations/deployment.json b/apps/backend/migrations/deployment.json index dc2b11c7a..3a4c7884c 100644 --- a/apps/backend/migrations/deployment.json +++ b/apps/backend/migrations/deployment.json @@ -107,7 +107,7 @@ "idx": 6, "when": 1728358607342, "tag": "0006_mature_madame_web", - "hash": "51995ae2bf0f8a52b57786978a421040330fb22121753aa6fbb0a51cb013ebde", + "hash": "2d3c434e963ac561d037554aabde467e4a514dc2f015d938cf0001da7f673bcf", "sql": [ "ALTER TABLE `undb_outbox` ADD `user_id` text;", "ALTER TABLE `undb_outbox` DROP COLUMN `operator_id`;" @@ -148,9 +148,9 @@ "idx": 10, "when": 1729306799169, "tag": "0010_nostalgic_nehzno", - "hash": "c0ffe9e7e3b0523d65603d7cd4ee444fbc8bae9b4f1959741b4c01085c345d44", + "hash": "5ae829af899a7374b61092468af12258938a7f1bcc92b55cb481042dcb59837c", "sql": [ - "CREATE TABLE `undb_dashboard_table_id_mapping` (`dashboard_id` text NOT NULL,`table_id` text NOT NULL,PRIMARY KEY(`dashboard_id`, `table_id`),FOREIGN KEY (`dashboard_id`) REFERENCES `undb_dashboard`(`id`) ON UPDATE no action ON DELETE no action,FOREIGN KEY (`table_id`) REFERENCES `undb_table`(`id`) ON UPDATE no action ON DELETE no action);" + "CREATE TABLE `undb_dashboard_table_id_mapping` (\r`dashboard_id` text NOT NULL,\r`table_id` text NOT NULL,\rPRIMARY KEY(`dashboard_id`, `table_id`),\rFOREIGN KEY (`dashboard_id`) REFERENCES `undb_dashboard`(`id`) ON UPDATE no action ON DELETE no action,\rFOREIGN KEY (`table_id`) REFERENCES `undb_table`(`id`) ON UPDATE no action ON DELETE no action\r);" ] }, { @@ -181,16 +181,16 @@ "idx": 13, "when": 1730979840099, "tag": "0013_lovely_mordo", - "hash": "59f5936ab2e03fbff473d3d56883ecce0832b71521b02bfa2ad2907d242dc00b", + "hash": "6a36e0da06793be22662a86e1ff42b9414a8723753addae312cf00de52703f79", "sql": [ "PRAGMA foreign_keys=OFF;", - "CREATE TABLE `__new_undb_reference_id_mapping` (`field_id` text NOT NULL,`table_id` text NOT NULL,`symmetric_field_id` text,`foreign_table_id` text NOT NULL);", + "CREATE TABLE `__new_undb_reference_id_mapping` (\r`field_id` text NOT NULL,\r`table_id` text NOT NULL,\r`symmetric_field_id` text,\r`foreign_table_id` text NOT NULL\r);", "INSERT INTO `__new_undb_reference_id_mapping`(\"field_id\", \"table_id\", \"symmetric_field_id\", \"foreign_table_id\") SELECT \"field_id\", \"table_id\", \"symmetric_field_id\", \"foreign_table_id\" FROM `undb_reference_id_mapping`;", "DROP TABLE `undb_reference_id_mapping`;", "ALTER TABLE `__new_undb_reference_id_mapping` RENAME TO `undb_reference_id_mapping`;", "PRAGMA foreign_keys=ON;", "CREATE UNIQUE INDEX `reference_id_mapping_unique_idx` ON `undb_reference_id_mapping` (`field_id`,`table_id`,`symmetric_field_id`,`foreign_table_id`);", - "CREATE TABLE `__new_undb_rollup_id_mapping` (`field_id` text NOT NULL,`table_id` text NOT NULL,`rollup_id` text NOT NULL,`rollup_table_id` text NOT NULL,PRIMARY KEY(`field_id`, `rollup_id`));", + "CREATE TABLE `__new_undb_rollup_id_mapping` (\r`field_id` text NOT NULL,\r`table_id` text NOT NULL,\r`rollup_id` text NOT NULL,\r`rollup_table_id` text NOT NULL,\rPRIMARY KEY(`field_id`, `rollup_id`)\r);", "INSERT INTO `__new_undb_rollup_id_mapping`(\"field_id\", \"table_id\", \"rollup_id\", \"rollup_table_id\") SELECT \"field_id\", \"table_id\", \"rollup_id\", \"rollup_table_id\" FROM `undb_rollup_id_mapping`;", "DROP TABLE `undb_rollup_id_mapping`;", "ALTER TABLE `__new_undb_rollup_id_mapping` RENAME TO `undb_rollup_id_mapping`;" @@ -204,5 +204,19 @@ "sql": [ "ALTER TABLE `undb_user` ADD `otp_secret` text;" ] + }, + { + "idx": 15, + "when": 1737446284193, + "tag": "0015_greedy_ben_grimm", + "hash": "f6b79d1c1531adfe3201428645ee289f7854c8bda01d19cd6bae95b025280ed6", + "sql": [ + "PRAGMA foreign_keys=OFF;", + "CREATE TABLE `__new_undb_session` (\r`id` text PRIMARY KEY NOT NULL,\r`user_id` text NOT NULL,\r`expires_at` integer NOT NULL,\r`spaceId` text NOT NULL,\rFOREIGN KEY (`user_id`) REFERENCES `undb_user`(`id`) ON UPDATE no action ON DELETE no action,\rFOREIGN KEY (`spaceId`) REFERENCES `undb_space`(`id`) ON UPDATE no action ON DELETE no action\r);", + "INSERT INTO `__new_undb_session`(\"id\", \"user_id\", \"expires_at\", \"spaceId\") SELECT \"id\", \"user_id\", \"expires_at\", \"spaceId\" FROM `undb_session`;", + "DROP TABLE `undb_session`;", + "ALTER TABLE `__new_undb_session` RENAME TO `undb_session`;", + "PRAGMA foreign_keys=ON;" + ] } ] \ No newline at end of file diff --git a/apps/backend/package.json b/apps/backend/package.json index 1ed297999..02a1148c4 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -21,6 +21,7 @@ "@json2csv/plainjs": "^7.0.6", "@kitajs/ts-html-plugin": "latest", "@lucia-auth/adapter-drizzle": "^1.1.0", + "@lucia-auth/adapter-mysql": "^3.0.2", "@lucia-auth/adapter-postgresql": "^3.1.2", "@lucia-auth/adapter-sqlite": "^3.0.2", "@oslojs/otp": "^1.1.0", @@ -53,6 +54,7 @@ "lucia": "^3.2.2", "mailgun-nodemailer-transport": "^3.0.2", "minio": "^8.0.3", + "mysql2": "^3.12.0", "nanoid": "^5.0.9", "nodemailer": "^6.9.16", "oslo": "^1.2.1", diff --git a/apps/backend/src/app.ts b/apps/backend/src/app.ts index 575a3b279..e91014fb4 100644 --- a/apps/backend/src/app.ts +++ b/apps/backend/src/app.ts @@ -43,32 +43,7 @@ export const app = new Elysia() await dbMigrate() logger.info("db migrate done") await auth.onStart() - }) - .use(opentelemetry.plugin()) - .use(loggerPlugin()) - .onError((ctx) => { - if (ctx.code === "NOT_FOUND") { - ctx.set.status = 404 - ctx.logger.error( - { - error: ctx.error, - path: ctx.path, - headers: ctx.headers, - }, - "Not Found", - ) - - return "Not Found :(" - } - - return new Response(ctx.error.toString()) - }) - .trace(async ({ set, onHandle }) => { - const { begin, end } = await onHandle() - set.headers["Server-Timing"] = `handle;dur=${(await end) - begin}` - }) - .onStart(async () => { const pubsub = container.resolve(PubSubContext) const webhookEventHandler = container.resolve(WebhookEventsHandler) // const auditEventHandler = container.resolve(AuditEventHandler) @@ -95,6 +70,30 @@ export const app = new Elysia() } } }) + .use(opentelemetry.plugin()) + .use(loggerPlugin()) + .onError((ctx) => { + if (ctx.code === "NOT_FOUND") { + ctx.set.status = 404 + ctx.logger.error( + { + error: ctx.error, + path: ctx.path, + headers: ctx.headers, + }, + "Not Found", + ) + + return "Not Found :(" + } + + return new Response(ctx.error.toString()) + }) + .trace(async ({ set, onHandle }) => { + const { begin, end } = await onHandle() + + set.headers["Server-Timing"] = `handle;dur=${(await end) - begin}` + }) .use( staticPlugin({ assets: "./.undb/storage", diff --git a/apps/backend/src/modules/auth/auth.provider.ts b/apps/backend/src/modules/auth/auth.provider.ts index 122c2773f..36cff9721 100644 --- a/apps/backend/src/modules/auth/auth.provider.ts +++ b/apps/backend/src/modules/auth/auth.provider.ts @@ -1,10 +1,12 @@ import { DrizzlePostgreSQLAdapter } from "@lucia-auth/adapter-drizzle" +import { Mysql2Adapter } from "@lucia-auth/adapter-mysql" import { BunSQLiteAdapter, LibSQLAdapter } from "@lucia-auth/adapter-sqlite" import { container, inject, instanceCachingFactory } from "@undb/di" import { Client, DATABASE_CLIENT, DB_PROVIDER, pgSessionTable, pgUsers } from "@undb/persistence/server" import Database from "bun:sqlite" -import { drizzle } from "drizzle-orm/node-postgres" +import { drizzle as drizzlePg } from "drizzle-orm/node-postgres" import { Adapter, Lucia } from "lucia" +import mysql from "mysql2/promise" import pg from "pg" export const LUCIA_PROVIDER = Symbol.for("LUCIA_PROVIDER") @@ -56,13 +58,22 @@ const createSqliteLucia = (sqlite: Database) => { } const createPostgresLucia = (pool: pg.Pool) => { - const db = drizzle(pool) + const db = drizzlePg(pool) const adapter = new DrizzlePostgreSQLAdapter(db, pgSessionTable, pgUsers) return createLuciaWithAdapter(adapter) } +const createMysqlLucia = (connection: mysql.Pool) => { + const adapter = new Mysql2Adapter(connection, { + user: "undb_user", + session: "undb_session", + }) + + return createLuciaWithAdapter(adapter) +} + declare module "lucia" { interface Register { Lucia: ReturnType @@ -89,6 +100,9 @@ container.register(LUCIA_PROVIDER, { } else if (dbProvider === "postgres") { const pool = c.resolve(DATABASE_CLIENT) return createPostgresLucia(pool) + } else if (dbProvider === "mysql") { + const connection = c.resolve(DATABASE_CLIENT) + return createMysqlLucia(connection) } const sqlite = c.resolve(DATABASE_CLIENT) diff --git a/apps/backend/src/registry/db.registry.ts b/apps/backend/src/registry/db.registry.ts index c794431db..fc12b9b4c 100644 --- a/apps/backend/src/registry/db.registry.ts +++ b/apps/backend/src/registry/db.registry.ts @@ -23,6 +23,8 @@ import { BaseQueryRepository, BaseRepository, Client, + createMysqlClient, + createMysqlQueryBuilder, createPostgresClient, createPostgresQueryBuilder, createSqliteClient, @@ -73,6 +75,7 @@ import { TEMPLATE_QUERY_REPOSITORY } from "@undb/template" import { USER_QUERY_REPOSITORY, USER_REPOSITORY, USER_SERVICE, UserService } from "@undb/user" import { WEBHOOK_QUERY_REPOSITORY, WEBHOOK_REPOSITORY } from "@undb/webhook" import Database from "bun:sqlite" +import mysql from "mysql2/promise" import { AsyncLocalStorage } from "node:async_hooks" import pg from "pg" @@ -90,6 +93,9 @@ export const registerDb = () => { if (dbProvider === "postgres") { return createPostgresClient(env.UNDB_DB_POSTGRES_URL!) } + if (dbProvider === "mysql") { + return createMysqlClient(env.UNDB_DB_MYSQL_URL!) + } return createTursoClient(env.UNDB_DB_TURSO_URL!, env.UNDB_DB_TURSO_AUTH_TOKEN) }), }) @@ -102,6 +108,9 @@ export const registerDb = () => { } else if (dbProvider === "postgres") { const pg = c.resolve(DATABASE_CLIENT) return createPostgresQueryBuilder(pg) + } else if (dbProvider === "mysql") { + const mysql = c.resolve(DATABASE_CLIENT) + return createMysqlQueryBuilder(mysql) } const sqlite = c.resolve(DATABASE_CLIENT) diff --git a/bun.lock b/bun.lock index b4ac0fdf0..bc858b960 100644 --- a/bun.lock +++ b/bun.lock @@ -29,6 +29,7 @@ "@json2csv/plainjs": "^7.0.6", "@kitajs/ts-html-plugin": "latest", "@lucia-auth/adapter-drizzle": "^1.1.0", + "@lucia-auth/adapter-mysql": "^3.0.2", "@lucia-auth/adapter-postgresql": "^3.1.2", "@lucia-auth/adapter-sqlite": "^3.0.2", "@oslojs/otp": "^1.1.0", @@ -61,6 +62,7 @@ "lucia": "^3.2.2", "mailgun-nodemailer-transport": "^3.0.2", "minio": "^8.0.3", + "mysql2": "^3.12.0", "nanoid": "^5.0.9", "nodemailer": "^6.9.16", "oslo": "^1.2.1", @@ -549,6 +551,7 @@ "kysely": "^0.27.5", "kysely-bun-sqlite": "^0.3.2", "kysely-wasm": "^0.7.0", + "mysql2": "^3.12.0", "pg": "^8.13.1", "postgres": "^3.4.5", "radash": "^12.1.0", @@ -1132,6 +1135,8 @@ "@lucia-auth/adapter-drizzle": ["@lucia-auth/adapter-drizzle@1.1.0", "https://registry.npmmirror.com/@lucia-auth/adapter-drizzle/-/adapter-drizzle-1.1.0.tgz", { "peerDependencies": { "drizzle-orm": ">= 0.29 <1", "lucia": "3.x" } }, "sha512-iCTnZWvfI5lLZOdUHZYiXA1jaspIFEeo2extLxQ3DjP3uOVys7IPwBi7zezLIRu9dhro4H4Kji+7gSYyjcef2A=="], + "@lucia-auth/adapter-mysql": ["@lucia-auth/adapter-mysql@3.0.2", "https://registry.npmmirror.com/@lucia-auth/adapter-mysql/-/adapter-mysql-3.0.2.tgz", { "peerDependencies": { "@planetscale/database": "^1.0.0", "lucia": "3.x", "mysql2": "^3.0.0" }, "optionalPeers": ["@planetscale/database", "mysql2"] }, "sha512-7acTeXQbqWn4SWrd8TDlJgQL5ZDZ2P2UGC3Y43m9ycYJ9LqIcq5udOW2J85HyrV0D5RkDPrKB5xv8l6tjR83xw=="], + "@lucia-auth/adapter-postgresql": ["@lucia-auth/adapter-postgresql@3.1.2", "https://registry.npmmirror.com/@lucia-auth/adapter-postgresql/-/adapter-postgresql-3.1.2.tgz", { "dependencies": { "pg": "^8.8.0", "postgres": "^3.3.5" }, "peerDependencies": { "@neondatabase/serverless": "0.7 - 0.9", "lucia": "3.x" }, "optionalPeers": ["@neondatabase/serverless"] }, "sha512-XgScy312JsaiyJZ0OaUHakk01hFBldF1m8abX4Ctk2Dkt7lEVS/u0xZ2Sf6Hlji1wZtEM0uiIWdeMUu79XcXZA=="], "@lucia-auth/adapter-sqlite": ["@lucia-auth/adapter-sqlite@3.0.2", "https://registry.npmmirror.com/@lucia-auth/adapter-sqlite/-/adapter-sqlite-3.0.2.tgz", { "peerDependencies": { "@libsql/client": "^0.3.0", "better-sqlite3": "8.x - 11.x", "lucia": "3.x" }, "optionalPeers": ["@libsql/client", "better-sqlite3"] }, "sha512-UlXpF+2UoFEdm1AsriJii5BOARwqko6SX29rQ8T8Za7rnjj9KLXLaRVQUgBhGmggAyvzCtguJ2+XOZDsfWm6Sw=="], @@ -1834,6 +1839,8 @@ "available-typed-arrays": ["available-typed-arrays@1.0.7", "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "https://registry.npmmirror.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + "axobject-query": ["axobject-query@4.1.0", "https://registry.npmmirror.com/axobject-query/-/axobject-query-4.1.0.tgz", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], "balanced-match": ["balanced-match@1.0.2", "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -2016,6 +2023,8 @@ "delayed-stream": ["delayed-stream@1.0.0", "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "denque": ["denque@2.1.0", "https://registry.npmmirror.com/denque/-/denque-2.1.0.tgz", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], + "dequal": ["dequal@2.0.3", "https://registry.npmmirror.com/dequal/-/dequal-2.0.3.tgz", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "des.js": ["des.js@1.1.0", "https://registry.npmmirror.com/des.js/-/des.js-1.1.0.tgz", { "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg=="], @@ -2198,6 +2207,8 @@ "fuse.js": ["fuse.js@7.0.0", "https://registry.npmmirror.com/fuse.js/-/fuse.js-7.0.0.tgz", {}, "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q=="], + "generate-function": ["generate-function@2.3.1", "https://registry.npmmirror.com/generate-function/-/generate-function-2.3.1.tgz", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], + "get-caller-file": ["get-caller-file@2.0.5", "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "get-east-asian-width": ["get-east-asian-width@1.3.0", "https://registry.npmmirror.com/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", {}, "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ=="], @@ -2270,6 +2281,8 @@ "i18next": ["i18next@24.2.1", "https://registry.npmmirror.com/i18next/-/i18next-24.2.1.tgz", { "dependencies": { "@babel/runtime": "^7.23.2" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-Q2wC1TjWcSikn1VAJg13UGIjc+okpFxQTxjVAymOnSA3RpttBQNMPf2ovcgoFVsV4QNxTfNZMAxorXZXsk4fBA=="], + "iconv-lite": ["iconv-lite@0.6.3", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + "ieee754": ["ieee754@1.2.1", "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "ignore": ["ignore@5.3.2", "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -2314,6 +2327,8 @@ "is-number": ["is-number@7.0.0", "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-property": ["is-property@1.0.2", "https://registry.npmmirror.com/is-property/-/is-property-1.0.2.tgz", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="], + "is-reference": ["is-reference@3.0.3", "https://registry.npmmirror.com/is-reference/-/is-reference-3.0.3.tgz", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="], "is-stream": ["is-stream@3.0.0", "https://registry.npmmirror.com/is-stream/-/is-stream-3.0.0.tgz", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], @@ -2420,6 +2435,8 @@ "lru-cache": ["lru-cache@10.4.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "lru.min": ["lru.min@1.1.1", "https://registry.npmmirror.com/lru.min/-/lru.min-1.1.1.tgz", {}, "sha512-FbAj6lXil6t8z4z3j0E5mfRlPzxkySotzUHwRXjlpRh10vc6AI6WN62ehZj82VG7M20rqogJ0GLwar2Xa05a8Q=="], + "lucia": ["lucia@3.2.2", "https://registry.npmmirror.com/lucia/-/lucia-3.2.2.tgz", { "dependencies": { "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0" } }, "sha512-P1FlFBGCMPMXu+EGdVD9W4Mjm0DqsusmKgO7Xc33mI5X1bklmsQb0hfzPhXomQr9waWIBDsiOjvr1e6BTaUqpA=="], "lucide-svelte": ["lucide-svelte@0.473.0", "https://registry.npmmirror.com/lucide-svelte/-/lucide-svelte-0.473.0.tgz", { "peerDependencies": { "svelte": "^3 || ^4 || ^5.0.0-next.42" } }, "sha512-Lw2+vrDmVlz/WC1/KcuCEV/1ENrHtChw4GH1cssMbbpdUFyVjZkt9S+7olCOGW8jOZJOrzZNfefV1DdaDw46jQ=="], @@ -2484,8 +2501,12 @@ "ms": ["ms@2.1.3", "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "mysql2": ["mysql2@3.12.0", "https://registry.npmmirror.com/mysql2/-/mysql2-3.12.0.tgz", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw=="], + "mz": ["mz@2.7.0", "https://registry.npmmirror.com/mz/-/mz-2.7.0.tgz", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + "named-placeholders": ["named-placeholders@1.1.3", "https://registry.npmmirror.com/named-placeholders/-/named-placeholders-1.1.3.tgz", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="], + "nanoid": ["nanoid@5.0.9", "https://registry.npmmirror.com/nanoid/-/nanoid-5.0.9.tgz", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q=="], "natural-compare": ["natural-compare@1.4.0", "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], @@ -2816,6 +2837,8 @@ "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "https://registry.npmmirror.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "safer-buffer": ["safer-buffer@2.1.2", "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "sass": ["sass@1.81.0", "https://registry.npmmirror.com/sass/-/sass-1.81.0.tgz", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA=="], "sax": ["sax@1.4.1", "https://registry.npmmirror.com/sax/-/sax-1.4.1.tgz", {}, "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="], @@ -2824,6 +2847,8 @@ "semver": ["semver@7.6.3", "https://registry.npmmirror.com/semver/-/semver-7.6.3.tgz", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], + "seq-queue": ["seq-queue@0.0.5", "https://registry.npmmirror.com/seq-queue/-/seq-queue-0.0.5.tgz", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], + "set-cookie-parser": ["set-cookie-parser@2.7.1", "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", {}, "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ=="], "set-function-length": ["set-function-length@1.2.2", "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], @@ -2868,6 +2893,8 @@ "sql.js": ["sql.js@1.12.0", "https://registry.npmmirror.com/sql.js/-/sql.js-1.12.0.tgz", {}, "sha512-Bi+43yMx/tUFZVYD4AUscmdL6NHn3gYQ+CM+YheFWLftOmrEC/Mz6Yh7E96Y2WDHYz3COSqT+LP6Z79zgrwJlA=="], + "sqlstring": ["sqlstring@2.3.3", "https://registry.npmmirror.com/sqlstring/-/sqlstring-2.3.3.tgz", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], + "ssf": ["ssf@0.11.2", "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz", { "dependencies": { "frac": "~1.1.2" } }, "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g=="], "stackback": ["stackback@0.0.2", "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], @@ -3370,6 +3397,8 @@ "miller-rabin/bn.js": ["bn.js@4.12.1", "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.1.tgz", {}, "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg=="], + "named-placeholders/lru-cache": ["lru-cache@7.18.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], + "npm-run-path/path-key": ["path-key@4.0.0", "https://registry.npmmirror.com/path-key/-/path-key-4.0.0.tgz", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], "npx-import/execa": ["execa@6.1.0", "https://registry.npmmirror.com/execa/-/execa-6.1.0.tgz", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", "human-signals": "^3.0.1", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^3.0.7", "strip-final-newline": "^3.0.0" } }, "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA=="], diff --git a/drizzle.mysql.config.ts b/drizzle.mysql.config.ts new file mode 100644 index 000000000..f254dd8bf --- /dev/null +++ b/drizzle.mysql.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "drizzle-kit" + +export default defineConfig({ + schema: "./packages/persistence/src/schema/mysql.ts", + out: "./apps/backend/drizzle/mysql", + dialect: "mysql", + tablesFilter: ["undb_*"], +}) diff --git a/package.json b/package.json index 36c76444d..dd3cf3237 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "generate": "run-s generate:db migrate:deploy", "generate:db": "run-p generate:db:*", "generate:db:postgres": "drizzle-kit generate --config drizzle.postgres.config.ts", + "generate:db:mysql": "drizzle-kit generate --config drizzle.mysql.config.ts", "generate:db:sqlite": "drizzle-kit generate --config drizzle.sqlite.config.ts", "migrate:db": "drizzle-kit push --config drizzle.sqlite.config.ts", "move-assets": "bun run ./scripts/move-assets.ts", diff --git a/packages/env/src/index.ts b/packages/env/src/index.ts index 6d94b5bbc..ba07d8d5e 100644 --- a/packages/env/src/index.ts +++ b/packages/env/src/index.ts @@ -44,6 +44,14 @@ const postgresEnv = createEnv({ emptyStringAsUndefined: true, }) +const mysqlEnv = createEnv({ + server: { + UNDB_DB_MYSQL_URL: z.string().optional(), + }, + runtimeEnv: import.meta.env, + emptyStringAsUndefined: true, +}) + const oauthEnv = createEnv({ server: { UNDB_OAUTH_GITHUB_ENABLED: z @@ -148,7 +156,7 @@ const emailEnv = createEnv({ const dbEnv = createEnv({ server: { - UNDB_DB_PROVIDER: z.enum(["sqlite", "turso", "postgres"]).default("sqlite").optional(), + UNDB_DB_PROVIDER: z.enum(["sqlite", "turso", "postgres", "mysql"]).default("sqlite").optional(), UNDB_OUTBOX_SCAN_BATCH_SIZE: z .string() .optional() @@ -171,5 +179,5 @@ export const env = createEnv({ }, runtimeEnv: import.meta.env, emptyStringAsUndefined: true, - extends: [tursoEnv, postgresEnv, dbEnv, oauthEnv, storageEnv, s3Env, emailEnv, minioEnv, authEnv], + extends: [tursoEnv, postgresEnv, mysqlEnv, dbEnv, oauthEnv, storageEnv, s3Env, emailEnv, minioEnv, authEnv], }) diff --git a/packages/persistence/package.json b/packages/persistence/package.json index 95434a17b..7a590ead9 100644 --- a/packages/persistence/package.json +++ b/packages/persistence/package.json @@ -43,6 +43,7 @@ "kysely": "^0.27.5", "kysely-bun-sqlite": "^0.3.2", "kysely-wasm": "^0.7.0", + "mysql2": "^3.12.0", "pg": "^8.13.1", "postgres": "^3.4.5", "radash": "^12.1.0", diff --git a/packages/persistence/src/dashboard/dashboard.mutate-visitor.ts b/packages/persistence/src/dashboard/dashboard.mutate-visitor.ts index 9421ce039..12b1b7181 100644 --- a/packages/persistence/src/dashboard/dashboard.mutate-visitor.ts +++ b/packages/persistence/src/dashboard/dashboard.mutate-visitor.ts @@ -15,6 +15,7 @@ import type { WithDashboardWidgets, } from "@undb/dashboard" import { AbstractQBMutationVisitor } from "../abstract-qb.visitor" +import type { IDbProvider } from "../db.provider" import type { IQueryBuilder } from "../qb.type" import { json } from "../qb.util" @@ -22,6 +23,7 @@ export class DashboardMutateVisitor extends AbstractQBMutationVisitor implements constructor( private readonly dashboard: Dashboard, private readonly qb: IQueryBuilder, + private readonly dbProvider: IDbProvider, ) { super() } @@ -57,7 +59,8 @@ export class DashboardMutateVisitor extends AbstractQBMutationVisitor implements const sql = this.qb .insertInto("undb_dashboard_table_id_mapping") .values({ dashboard_id: dashboardId, table_id: tableId }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .compile() this.addSql(sql) } diff --git a/packages/persistence/src/dashboard/dashboard.repository.ts b/packages/persistence/src/dashboard/dashboard.repository.ts index b7521b265..70341b685 100644 --- a/packages/persistence/src/dashboard/dashboard.repository.ts +++ b/packages/persistence/src/dashboard/dashboard.repository.ts @@ -12,6 +12,7 @@ import { inject, singleton } from "@undb/di" import { None, Some, type Option } from "@undb/domain" import type { ITxContext } from "../ctx.interface" import { injectTxCTX } from "../ctx.provider" +import { DbProviderService, type IDbProvider } from "../db.provider" import { injectQueryBuilder } from "../qb.provider" import type { IQueryBuilder } from "../qb.type" import { DashboardFilterVisitor } from "./dashboard.filter-visitor" @@ -32,6 +33,8 @@ export class DashboardRepository implements IDashboardRepository { private readonly context: IContext, @injectTxCTX() private readonly txContext: ITxContext, + @inject(DbProviderService) + private readonly dbProvider: IDbProvider, ) {} async find(spec: IDashboardSpecification): Promise { @@ -107,7 +110,7 @@ export class DashboardRepository implements IDashboardRepository { const userId = this.context.mustGetCurrentUserId() const qb = this.txContext.getCurrentTransaction() - const visitor = new DashboardMutateVisitor(dashboard, qb).$mutate(spec) + const visitor = new DashboardMutateVisitor(dashboard, qb, this.dbProvider).$mutate(spec) await qb .updateTable("undb_dashboard") diff --git a/packages/persistence/src/db-client.ts b/packages/persistence/src/db-client.ts index 0b880cd76..9d907e036 100644 --- a/packages/persistence/src/db-client.ts +++ b/packages/persistence/src/db-client.ts @@ -1,6 +1,7 @@ import { createClient } from "@libsql/client" import { inject } from "@undb/di" import Database from "bun:sqlite" +import mysql from "mysql2/promise" import pg from "pg" export const DATABASE_CLIENT = Symbol.for("DATABASE_CLIENT") @@ -20,3 +21,7 @@ export const createPostgresClient = (connectionString: string) => { connectionString, }) } + +export const createMysqlClient = (connectionString: string): mysql.Pool => { + return mysql.createPool(connectionString) +} diff --git a/packages/persistence/src/db.provider.ts b/packages/persistence/src/db.provider.ts index 38fbf12a3..e104d7817 100644 --- a/packages/persistence/src/db.provider.ts +++ b/packages/persistence/src/db.provider.ts @@ -7,20 +7,37 @@ export const injectDbProvider = () => inject(DB_PROVIDER) export interface IDbProvider { getDbProvider(): string + get not(): this + isPostgres(): boolean + isMysql(): boolean isSqlite(): boolean } @singleton() export class DbProviderService implements IDbProvider { constructor(@inject(DB_PROVIDER) private readonly dbProvider: string) {} + + #isNot: boolean = false + + get not(): this { + this.#isNot = true + return this + } + getDbProvider(): string { return this.dbProvider } + #is(dbProvider: string) { + return this.#isNot ? this.dbProvider !== dbProvider : this.dbProvider === dbProvider + } isPostgres(): boolean { - return this.dbProvider === "postgres" + return this.#is("postgres") } isSqlite(): boolean { - return this.dbProvider === "sqlite" || this.dbProvider === "turso" || !this.dbProvider + return this.#is("sqlite") || this.#is("turso") || !this.dbProvider + } + isMysql(): boolean { + return this.#is("mysql") } } diff --git a/packages/persistence/src/member/invitation.repository.ts b/packages/persistence/src/member/invitation.repository.ts index 61ac7d356..3b6cdc754 100644 --- a/packages/persistence/src/member/invitation.repository.ts +++ b/packages/persistence/src/member/invitation.repository.ts @@ -1,8 +1,9 @@ import type { IInvitationRepository, InvitationCompositeSpecification, InvitationDo } from "@undb/authz" import { injectContext, type IContext } from "@undb/context" -import { singleton } from "@undb/di" +import { inject, singleton } from "@undb/di" import type { ITxContext } from "../ctx.interface" import { injectTxCTX } from "../ctx.provider" +import { DbProviderService, type IDbProvider } from "../db.provider" import { InvitationMutationVisitor } from "./invitation.mutation-visitor" @singleton() @@ -12,6 +13,8 @@ export class InvitationRepository implements IInvitationRepository { private readonly context: IContext, @injectTxCTX() private readonly txContext: ITxContext, + @inject(DbProviderService) + private readonly dbProvider: IDbProvider, ) {} async deleteOneById(id: string): Promise { const trx = this.txContext.getCurrentTransaction() @@ -47,13 +50,22 @@ export class InvitationRepository implements IInvitationRepository { invited_at: invitation.invitedAt.getTime(), inviter_id: invitation.inviterId, }) - .onConflict((oc) => - oc.columns(["id", "email"]).doUpdateSet({ + .$if(this.dbProvider.isMysql(), (eb) => + eb.onDuplicateKeyUpdate({ invited_at: new Date(), status: invitation.status, role: invitation.role, }), ) + .$if(this.dbProvider.not.isMysql(), (eb) => + eb.onConflict((oc) => + oc.columns(["id", "email"]).doUpdateSet({ + invited_at: new Date(), + status: invitation.status, + role: invitation.role, + }), + ), + ) .execute() } diff --git a/packages/persistence/src/member/space-member.repository.ts b/packages/persistence/src/member/space-member.repository.ts index db8e2e12b..9675a28e9 100644 --- a/packages/persistence/src/member/space-member.repository.ts +++ b/packages/persistence/src/member/space-member.repository.ts @@ -1,8 +1,9 @@ import { SpaceMember, SpaceMemberComositeSpecification, type ISpaceMemberRepository } from "@undb/authz" -import { singleton } from "@undb/di" +import { inject, singleton } from "@undb/di" import { None, Some, type Option } from "@undb/domain" import type { ITxContext } from "../ctx.interface" import { injectTxCTX } from "../ctx.provider" +import { DbProviderService, type IDbProvider } from "../db.provider" import { injectQueryBuilder } from "../qb.provider" import type { IQueryBuilder } from "../qb.type" import { SpaceMemberFilterVisitor } from "./space-member.filter-visitor" @@ -14,6 +15,8 @@ export class SpaceMemberRepository implements ISpaceMemberRepository { private readonly qb: IQueryBuilder, @injectTxCTX() private readonly txContext: ITxContext, + @inject(DbProviderService) + private readonly dbProvider: IDbProvider, ) {} async exists(spec: SpaceMemberComositeSpecification): Promise { @@ -71,7 +74,8 @@ export class SpaceMemberRepository implements ISpaceMemberRepository { space_id: json.spaceId, user_id: json.userId, }) - .onConflict((c) => c.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((c) => c.doNothing())) .execute() } } diff --git a/packages/persistence/src/migrate.server.ts b/packages/persistence/src/migrate.server.ts index e9b4e9b58..a8b0224a5 100644 --- a/packages/persistence/src/migrate.server.ts +++ b/packages/persistence/src/migrate.server.ts @@ -5,8 +5,11 @@ import { drizzle as sqliteDrizzle } from "drizzle-orm/bun-sqlite" import { migrate as sqliteMigrate } from "drizzle-orm/bun-sqlite/migrator" import { drizzle as libsqlDrizzle } from "drizzle-orm/libsql" import { migrate as libsqlMigrate } from "drizzle-orm/libsql/migrator" +import { drizzle as mysqlDrizzle } from "drizzle-orm/mysql2" +import { migrate as mysqlMigrate } from "drizzle-orm/mysql2/migrator" import { drizzle as postgresDrizzle } from "drizzle-orm/node-postgres" import { migrate as postgresMigrate } from "drizzle-orm/node-postgres/migrator" +import mysql from "mysql2/promise" import pg from "pg" import { DATABASE_CLIENT } from "./db-client" import { DrizzleLogger } from "./db.logger" @@ -14,10 +17,12 @@ import { DB_PROVIDER } from "./db.provider" export async function dbMigrate() { const dbProvider = container.resolve(DB_PROVIDER) + const logger = new DrizzleLogger() + if (dbProvider === "sqlite" || !dbProvider) { const sqlite = container.resolve(DATABASE_CLIENT) const db = sqliteDrizzle(sqlite, { - logger: new DrizzleLogger(), + logger, }) sqliteMigrate(db, { migrationsFolder: "./drizzle/sqlite" }) @@ -26,16 +31,24 @@ export async function dbMigrate() { const pg = container.resolve(DATABASE_CLIENT) const db = postgresDrizzle(pg, { - logger: new DrizzleLogger(), + logger, }) await postgresMigrate(db, { migrationsFolder: "./drizzle/postgres" }) return + } else if (dbProvider === "mysql") { + const mysql = container.resolve(DATABASE_CLIENT) + const db = mysqlDrizzle(mysql, { + logger, + }) + + await mysqlMigrate(db, { migrationsFolder: "./drizzle/mysql" }) + return } const sqlite = container.resolve(DATABASE_CLIENT) const db = libsqlDrizzle(sqlite, { - logger: new DrizzleLogger(), + logger, }) await libsqlMigrate(db, { migrationsFolder: "./drizzle/sqlite" }) diff --git a/packages/persistence/src/qb.server.ts b/packages/persistence/src/qb.server.ts index 1e361f3ef..038cfec2e 100644 --- a/packages/persistence/src/qb.server.ts +++ b/packages/persistence/src/qb.server.ts @@ -1,8 +1,9 @@ import type { Client } from "@libsql/client" import { LibsqlDialect } from "@libsql/kysely-libsql" import { Database as SqliteDatabase } from "bun:sqlite" -import { PostgresDialect } from "kysely" +import { MysqlDialect, PostgresDialect } from "kysely" import { BunSqliteDialect } from "kysely-bun-sqlite" +import mysql from "mysql2/promise" import pg from "pg" import { createQueryBuilderWithDialect } from "./qb.util" @@ -29,3 +30,11 @@ export function createPostgresQueryBuilder(pg: pg.Pool) { }), ) } + +export function createMysqlQueryBuilder(mysql: mysql.Pool) { + return createQueryBuilderWithDialect( + new MysqlDialect({ + pool: mysql, + }), + ) +} diff --git a/packages/persistence/src/record/record.mutate-visitor.ts b/packages/persistence/src/record/record.mutate-visitor.ts index f8bacb29a..6638839b4 100644 --- a/packages/persistence/src/record/record.mutate-visitor.ts +++ b/packages/persistence/src/record/record.mutate-visitor.ts @@ -215,7 +215,8 @@ export class RecordMutateVisitor extends AbstractQBMutationVisitor implements IR } }), ) - .onConflict((bd) => bd.columns(["id"]).doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((bd) => bd.columns(["id"]).doNothing())) .compile() this.addSql(insert) @@ -229,7 +230,10 @@ export class RecordMutateVisitor extends AbstractQBMutationVisitor implements IR attachment_id: value.id, })), ) - .onConflict((bd) => bd.columns(["table_id", "field_id", "record_id", "attachment_id"]).doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => + eb.onConflict((bd) => bd.columns(["table_id", "field_id", "record_id", "attachment_id"]).doNothing()), + ) .compile() this.addSql(insertSql) } @@ -279,7 +283,10 @@ export class RecordMutateVisitor extends AbstractQBMutationVisitor implements IR return values.reduce((prev, value) => prev.unionAll(expression(value)), expression(values[0])) }) - .onConflict((bd) => bd.columns([fieldId, symmetricFieldId]).doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => + eb.onConflict((bd) => bd.columns([fieldId, symmetricFieldId]).doNothing()), + ) .compile() this.addSql(insert) } @@ -307,7 +314,10 @@ export class RecordMutateVisitor extends AbstractQBMutationVisitor implements IR [symmetricFieldId]: recordId, })), ) - .onConflict((bd) => bd.columns([fieldId, symmetricFieldId]).doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => + eb.onConflict((bd) => bd.columns([fieldId, symmetricFieldId]).doNothing()), + ) .compile() this.addSql(insert) } diff --git a/packages/persistence/src/schema/mysql.ts b/packages/persistence/src/schema/mysql.ts new file mode 100644 index 000000000..1228edc89 --- /dev/null +++ b/packages/persistence/src/schema/mysql.ts @@ -0,0 +1,439 @@ +import type { IAuditDetail } from "@undb/audit" +import type { IInvitationStatus, ISpaceMemberRole, ISpaceMemberWithoutOwner } from "@undb/authz" +import type { IDashboardLayouts, IDashboardWidgets } from "@undb/dashboard" +import type { RECORD_EVENTS } from "@undb/table" +import type { IWebhookMethod } from "@undb/webhook" +import { sql } from "drizzle-orm" +import { + bigint, + boolean, + foreignKey, + index, + int, + json, + mysqlTableCreator, + primaryKey, + text, + timestamp, + unique, + varchar, +} from "drizzle-orm/mysql-core" + +const mysqlTable = mysqlTableCreator((name) => `undb_${name}`) + +export const space = mysqlTable( + "space", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + name: varchar("name", { length: 255 }), + isPersonal: boolean("is_personal").notNull(), + avatar: text("avatar"), + createdAt: text("created_at") + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + createdBy: varchar("created_by", { length: 36 }) + .notNull() + .references(() => users.id), + updateAt: text("updated_at") + .notNull() + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), + updatedBy: varchar("updated_by", { length: 36 }) + .notNull() + .references(() => users.id), + deletedAt: bigint("deleted_at", { mode: "bigint" }), + deletedBy: varchar("deleted_by", { length: 36 }).references(() => users.id), + }, + (table) => [index("space_name_idx").on(table.name)], +) + +export const tables = mysqlTable( + "table", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + name: varchar("name", { length: 255 }).notNull(), + baseId: varchar("base_id", { length: 36 }) + .notNull() + .references(() => baseTable.id), + + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + + schema: json("schema").notNull(), + views: json("views").notNull(), + forms: json("forms"), + rls: json("rls"), + widgets: json("widgets"), + + createdAt: text("created_at") + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + createdBy: varchar("created_by", { length: 36 }) + .notNull() + .references(() => users.id), + updateAt: text("updated_at") + .notNull() + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), + updatedBy: varchar("updated_by", { length: 36 }) + .notNull() + .references(() => users.id), + }, + (table) => [ + index("table_base_id_idx").on(table.baseId), + unique("table_name_unique_idx").on(table.name, table.baseId), + index("table_space_id_idx").on(table.spaceId), + ], +) + +export const tableIdMapping = mysqlTable( + "table_id_mapping", + { + tableId: varchar("table_id", { length: 36 }).notNull(), + subjectId: varchar("subject_id", { length: 36 }).notNull(), + }, + (table) => [ + primaryKey({ columns: [table.tableId, table.subjectId] }), + foreignKey({ + columns: [table.tableId], + foreignColumns: [tables.id], + name: "table_id_mapping_table_id_fk", + }), + ], +) + +export const referenceIdMapping = mysqlTable( + "reference_id_mapping", + { + fieldId: varchar("field_id", { length: 36 }).notNull(), + tableId: varchar("table_id", { length: 36 }).notNull(), + symmetricFieldId: varchar("symmetric_field_id", { length: 36 }), + foreignTableId: varchar("foreign_table_id", { length: 36 }).notNull(), + }, + (table) => [ + unique("reference_id_mapping_unique_idx").on( + table.fieldId, + table.tableId, + table.symmetricFieldId, + table.foreignTableId, + ), + ], +) + +export const rollupIdMapping = mysqlTable( + "rollup_id_mapping", + { + fieldId: varchar("field_id", { length: 36 }).notNull(), + tableId: varchar("table_id", { length: 36 }).notNull(), + rollupId: varchar("rollup_id", { length: 36 }).notNull(), + rollupTableId: varchar("rollup_table_id", { length: 36 }).notNull(), + }, + (table) => [primaryKey({ columns: [table.fieldId, table.rollupId] })], +) + +export const dashboards = mysqlTable( + "dashboard", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + name: varchar("name", { length: 255 }).notNull(), + description: text("description"), + baseId: varchar("base_id", { length: 36 }) + .notNull() + .references(() => baseTable.id), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + + widgets: json("widgets").$type(), + layout: json("layout").$type(), + + createdAt: text("created_at") + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + createdBy: varchar("created_by", { length: 36 }) + .notNull() + .references(() => users.id), + updateAt: text("updated_at") + .notNull() + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), + updatedBy: varchar("updated_by", { length: 36 }) + .notNull() + .references(() => users.id), + }, + (table) => [ + index("dashboard_base_id_idx").on(table.baseId), + unique("dashboard_name_unique_idx").on(table.name, table.baseId), + index("dashboard_space_id_idx").on(table.spaceId), + ], +) + +export const dashboardTableIdMapping = mysqlTable( + "dashboard_table_id_mapping", + { + dashboardId: varchar("dashboard_id", { length: 36 }).notNull(), + tableId: varchar("table_id", { length: 36 }).notNull(), + }, + (table) => [ + primaryKey({ name: "pk", columns: [table.dashboardId, table.tableId] }), + foreignKey({ + columns: [table.dashboardId], + foreignColumns: [dashboards.id], + name: "dashboard_table_id_mapping_dashboard_id_fk", + }), + foreignKey({ + columns: [table.tableId], + foreignColumns: [tables.id], + name: "dashboard_table_id_mapping_table_id_fk", + }), + ], +) + +export const attachments = mysqlTable( + "attachment", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + name: varchar("name", { length: 255 }).notNull(), + size: int("size").notNull(), + mimeType: varchar("mime_type", { length: 255 }).notNull(), + url: varchar("url", { length: 255 }).notNull(), + token: varchar("token", { length: 36 }), + createdAt: bigint("created_at", { mode: "bigint" }).notNull(), + createdBy: varchar("created_by", { length: 36 }) + .notNull() + .references(() => users.id), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + }, + (table) => [index("attachment_size_idx").on(table.size), index("attachment_space_id_idx").on(table.spaceId)], +) + +export const attachmentMapping = mysqlTable( + "attachment_mapping", + { + attachmentId: varchar("attachment_id", { length: 36 }) + .notNull() + .references(() => attachments.id), + tableId: varchar("table_id", { length: 36 }) + .notNull() + .references(() => tables.id), + recordId: varchar("record_id", { length: 36 }).notNull(), + fieldId: varchar("field_id", { length: 36 }).notNull(), + }, + (table) => [primaryKey({ name: "pk", columns: [table.attachmentId, table.tableId, table.recordId, table.fieldId] })], +) + +export const outbox = mysqlTable( + "outbox", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + payload: json("payload").notNull(), + meta: json("meta"), + timestamp: bigint("timestamp", { mode: "bigint" }).notNull(), + userId: varchar("user_id", { length: 36 }), + name: text("name").notNull(), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + }, + (table) => [index("outbox_space_id_idx").on(table.spaceId)], +) + +export const users = mysqlTable( + "user", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + username: varchar("username", { length: 255 }).notNull(), + email: varchar("email", { length: 255 }).notNull().unique(), + email_verified: boolean("email_verified").notNull().default(false), + password: text("password").notNull(), + avatar: text("avatar"), + otp_secret: text("otp_secret"), + }, + (table) => [index("user_username_idx").on(table.username), index("user_email_idx").on(table.email)], +) + +export const passwordResetTokenTable = mysqlTable( + "password_reset_token", + { + id: int("id").autoincrement().primaryKey(), + token: varchar("token", { length: 36 }).notNull().unique(), + userId: varchar("user_id", { length: 36 }) + .notNull() + .references(() => users.id), + expiresAt: bigint("expires_at", { mode: "bigint" }).notNull(), + }, + (table) => [index("password_reset_token_user_id_idx").on(table.userId)], +) + +export const oauthAccount = mysqlTable( + "oauth_account", + { + provider_id: varchar("provider_id", { length: 36 }).notNull(), + provider_user_id: varchar("provider_user_id", { length: 36 }).notNull(), + user_id: varchar("user_id", { length: 36 }) + .notNull() + .references(() => users.id), + }, + (table) => [primaryKey({ columns: [table.provider_id, table.provider_user_id] })], +) + +export const emailVerificationCode = mysqlTable("email_verification_code", { + id: int("id").autoincrement().primaryKey(), + code: text("code").notNull(), + userId: varchar("user_id", { length: 36 }) + .unique() + .references(() => users.id), + email: text("email").notNull(), + expires_at: bigint("expires_at", { mode: "bigint" }).notNull(), +}) + +export const sessionTable = mysqlTable("session", { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + userId: varchar("user_id", { length: 36 }) + .notNull() + .references(() => users.id), + expiresAt: timestamp("expires_at", { mode: "date" }).notNull(), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), +}) + +export const webhook = mysqlTable( + "webhook", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + name: text("name").notNull(), + url: varchar("url", { length: 255 }).notNull(), + method: text("method").notNull().$type(), + enabled: boolean("enabled").notNull(), + tableId: varchar("table_id", { length: 36 }) + .notNull() + .references(() => tables.id), + headers: json("headers").notNull(), + condition: json("condition"), + event: text("event").notNull().$type(), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + }, + (table) => [ + index("webhook_table_id_idx").on(table.tableId), + index("webhook_space_id_idx").on(table.spaceId), + index("webhook_url_idx").on(table.url), + ], +) + +export const audit = mysqlTable( + "audit", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + timestamp: bigint("timestamp", { mode: "bigint" }).notNull(), + detail: json("detail").$type(), + meta: json("meta"), + op: text("op").notNull().$type(), + tableId: varchar("table_id", { length: 36 }).notNull(), + recordId: varchar("record_id", { length: 36 }).notNull(), + operatorId: varchar("operator_id", { length: 36 }).notNull(), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + }, + (table) => [ + index("audit_table_id_idx").on(table.tableId), + index("audit_space_id_idx").on(table.spaceId), + index("audit_record_id_idx").on(table.recordId), + ], +) + +export const spaceMember = mysqlTable( + "space_member", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + userId: varchar("user_id", { length: 36 }) + .notNull() + .references(() => users.id), + role: text("role").notNull().$type(), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + }, + (table) => [unique("space_member_unique_idx").on(table.userId, table.spaceId)], +) + +export const baseTable = mysqlTable( + "base", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + name: varchar("name", { length: 255 }).notNull(), + spaceId: varchar("space_id", { length: 36 }) + .references(() => space.id) + .notNull(), + createdAt: text("created_at") + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + createdBy: varchar("created_by", { length: 36 }) + .notNull() + .references(() => users.id), + updateAt: text("updated_at") + .notNull() + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), + updatedBy: varchar("updated_by", { length: 36 }) + .notNull() + .references(() => users.id), + }, + (base) => [unique("base_name_unique_idx").on(base.name, base.spaceId), index("base_space_id_idx").on(base.spaceId)], +) + +export const shareTable = mysqlTable( + "share", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + targetType: varchar("target_type", { length: 255 }).notNull(), + targetId: varchar("target_id", { length: 36 }).notNull(), + enabled: boolean("enabled").notNull(), + spaceId: varchar("space_id", { length: 36 }) + .notNull() + .references(() => space.id), + }, + (table) => [ + unique("share_unique_idx").on(table.targetType, table.targetId), + index("share_space_id_idx").on(table.spaceId), + ], +) + +export const invitations = mysqlTable( + "invitation", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + email: varchar("email", { length: 255 }).notNull(), + role: text("role").notNull().$type(), + status: text("status").notNull().$type(), + spaceId: varchar("space_id", { length: 36 }) + .references(() => space.id) + .notNull(), + invitedAt: bigint("invited_at", { mode: "bigint" }).notNull(), + inviterId: varchar("inviter_id", { length: 36 }) + .notNull() + .references(() => users.id), + }, + (table) => [ + index("invitation_space_id_idx").on(table.spaceId), + unique("invitation_unique_idx").on(table.email, table.spaceId), + ], +) + +export const apiTokenTable = mysqlTable( + "api_token", + { + id: varchar("id", { length: 36 }).notNull().primaryKey(), + name: varchar("name", { length: 255 }).notNull(), + userId: varchar("user_id", { length: 36 }) + .notNull() + .references(() => users.id), + spaceId: varchar("space_id", { length: 36 }) + .references(() => space.id) + .notNull(), + token: varchar("token", { length: 36 }).notNull().unique(), + }, + (table) => [index("api_token_space_id_idx").on(table.spaceId), index("api_token_user_id_idx").on(table.userId)], +) diff --git a/packages/persistence/src/server.ts b/packages/persistence/src/server.ts index 3eb7889e1..8a2bfe1d5 100644 --- a/packages/persistence/src/server.ts +++ b/packages/persistence/src/server.ts @@ -22,6 +22,7 @@ export * from "./ctx.interface" export * from "./ctx.provider" export { DATABASE_CLIENT, + createMysqlClient, createPostgresClient, createSqliteClient, createTursoClient, @@ -30,4 +31,5 @@ export { export * from "./db.provider" export { injectQueryBuilder } from "./qb.provider" export { type IQueryBuilder } from "./qb.type" +export { sessionTable as mysqlSessionTable, users as mysqlUsers } from "./schema/mysql" export { sessionTable as pgSessionTable, users as pgUsers } from "./schema/postgres" diff --git a/packages/persistence/src/share/share.repository.ts b/packages/persistence/src/share/share.repository.ts index e8b3ff1ea..6864d1810 100644 --- a/packages/persistence/src/share/share.repository.ts +++ b/packages/persistence/src/share/share.repository.ts @@ -3,6 +3,7 @@ import { None, Some, type Option } from "@undb/domain" import { WithShareId, type IShareRepository, type Share, type ShareSpecification } from "@undb/share" import type { ITxContext } from "../ctx.interface" import { injectTxCTX } from "../ctx.provider" +import { DbProviderService, type IDbProvider } from "../db.provider" import { injectQueryBuilder } from "../qb.provider" import type { IQueryBuilder } from "../qb.type" import { ShareFilterVisitor } from "./share.filter-visitor" @@ -17,6 +18,8 @@ export class ShareRepository implements IShareRepository { private readonly qb: IQueryBuilder, @injectTxCTX() private readonly txContext: ITxContext, + @inject(DbProviderService) + private readonly dbProvider: IDbProvider, ) {} insert(share: Share): Promise { throw new Error("Method not implemented.") @@ -28,7 +31,10 @@ export class ShareRepository implements IShareRepository { .getCurrentTransaction() .insertInto("undb_share") .values(entity) - .onConflict((ob) => ob.columns(["target_id", "target_type"]).doUpdateSet({ enabled: share.enabled })) + .$if(this.dbProvider.isMysql(), (eb) => eb.onDuplicateKeyUpdate({ enabled: share.enabled })) + .$if(this.dbProvider.not.isMysql(), (eb) => + eb.onConflict((ob) => ob.columns(["target_id", "target_type"]).doUpdateSet({ enabled: share.enabled })), + ) .execute() } async findOneById(id: string): Promise> { diff --git a/packages/persistence/src/table/table.mutation-visitor.ts b/packages/persistence/src/table/table.mutation-visitor.ts index 401d3a071..da4bab29a 100644 --- a/packages/persistence/src/table/table.mutation-visitor.ts +++ b/packages/persistence/src/table/table.mutation-visitor.ts @@ -36,6 +36,7 @@ import type { WithoutView, } from "@undb/table" import { AbstractQBMutationVisitor } from "../abstract-qb.visitor" +import type { IDbProvider } from "../db.provider" import { type IQueryBuilder } from "../qb.type" import { json } from "../qb.util" import { tables } from "../schema/sqlite" @@ -44,6 +45,7 @@ export class TableMutationVisitor extends AbstractQBMutationVisitor implements I constructor( private readonly table: TableDo, private readonly qb: IQueryBuilder, + private readonly dbProvider: IDbProvider, ) { super() } @@ -76,7 +78,8 @@ export class TableMutationVisitor extends AbstractQBMutationVisitor implements I table_id: this.table.id.value, subject_id: field.id.value, }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .compile() this.addSql(sql) @@ -91,7 +94,8 @@ export class TableMutationVisitor extends AbstractQBMutationVisitor implements I rollup_id: field.id.value, rollup_table_id: this.table.id.value, }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .compile() this.addSql(sql) } else if (field.type === "reference") { @@ -103,7 +107,8 @@ export class TableMutationVisitor extends AbstractQBMutationVisitor implements I symmetric_field_id: field.symmetricFieldId ?? null, foreign_table_id: field.foreignTableId, }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .compile() this.addSql(sql) @@ -165,7 +170,8 @@ export class TableMutationVisitor extends AbstractQBMutationVisitor implements I table_id: this.table.id.value, subject_id: views.view.id.value, }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .compile() this.addSql(sql) @@ -217,7 +223,8 @@ export class TableMutationVisitor extends AbstractQBMutationVisitor implements I table_id: this.table.id.value, subject_id: views.form.id, }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .compile() this.addSql(sql) diff --git a/packages/persistence/src/table/table.repository.ts b/packages/persistence/src/table/table.repository.ts index 3bcb9086e..c8c142780 100644 --- a/packages/persistence/src/table/table.repository.ts +++ b/packages/persistence/src/table/table.repository.ts @@ -14,6 +14,7 @@ import { import type { ITxContext } from "../ctx.interface" import { injectTxCTX } from "../ctx.provider" import type { InsertTable, InsertTableIdMapping } from "../db" +import { DbProviderService, type IDbProvider } from "../db.provider" import { json } from "../qb.util" import { UnderlyingTableService } from "../underlying/underlying-table.service" import { TableFilterVisitor } from "./table.filter-visitor" @@ -32,6 +33,8 @@ export class TableRepository implements ITableRepository { private readonly context: IContext, @injectTxCTX() private readonly txContext: ITxContext, + @inject(DbProviderService) + private readonly dbProvider: IDbProvider, ) {} get mapper() { @@ -51,7 +54,7 @@ export class TableRepository implements ITableRepository { const userId = this.context.mustGetCurrentUserId() - const visitor = new TableMutationVisitor(table, trx) + const visitor = new TableMutationVisitor(table, trx, this.dbProvider) spec.unwrap().accept(visitor) await trx @@ -100,7 +103,8 @@ export class TableRepository implements ITableRepository { await trx .insertInto("undb_table_id_mapping") .values(mapping) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .execute() for (const view of table.views.views) { @@ -110,7 +114,8 @@ export class TableRepository implements ITableRepository { table_id: table.id.value, subject_id: view.id.value, }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .execute() } @@ -121,7 +126,8 @@ export class TableRepository implements ITableRepository { table_id: table.id.value, subject_id: form.id, }) - .onConflict((ob) => ob.doNothing()) + .$if(this.dbProvider.isMysql(), (eb) => eb.ignore()) + .$if(this.dbProvider.not.isMysql(), (eb) => eb.onConflict((ob) => ob.doNothing())) .execute() }