-
Notifications
You must be signed in to change notification settings - Fork 8
Implement orbis forms #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
37b37b2
589fe3a
4620427
43dff90
250a905
ad82bff
781b806
71a3d2f
3276dee
3febd68
6c3ee02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| -- CreateEnum | ||
| CREATE TYPE "FieldType" AS ENUM ('TEXT', 'NUMBER', 'EMAIL', 'MULTIPLE_CHOICE', 'CHECKBOX', 'SINGLE_CHOICE', 'FILE', 'DATE', 'STAR_RATING', 'DROPDOWN'); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "Form" ( | ||
| "id" TEXT NOT NULL, | ||
| "title" TEXT NOT NULL, | ||
| "description" TEXT, | ||
| "createdBy" TEXT NOT NULL, | ||
| "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| "updatedAt" TIMESTAMP(3) NOT NULL, | ||
| "isActive" BOOLEAN NOT NULL DEFAULT true, | ||
| "slug" TEXT NOT NULL, | ||
| "isTemplate" BOOLEAN NOT NULL DEFAULT false, | ||
|
|
||
| CONSTRAINT "Form_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "FormContributor" ( | ||
| "id" TEXT NOT NULL, | ||
| "formId" TEXT NOT NULL, | ||
| "userId" TEXT NOT NULL, | ||
| "addedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
|
|
||
| CONSTRAINT "FormContributor_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "FormField" ( | ||
| "id" TEXT NOT NULL, | ||
| "formId" TEXT NOT NULL, | ||
| "label" TEXT NOT NULL, | ||
| "fieldType" "FieldType" NOT NULL, | ||
| "isRequired" BOOLEAN NOT NULL DEFAULT false, | ||
| "options" JSONB, | ||
| "position" INTEGER NOT NULL, | ||
| "placeholder" TEXT, | ||
| "helpText" TEXT, | ||
| "validation" JSONB, | ||
| "conditions" JSONB, | ||
|
|
||
| CONSTRAINT "FormField_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "FormResponse" ( | ||
| "id" TEXT NOT NULL, | ||
| "formId" TEXT NOT NULL, | ||
| "submittedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| "submittedBy" TEXT, | ||
| "responderIp" TEXT, | ||
| "userAgent" TEXT, | ||
| "metadata" JSONB, | ||
|
|
||
| CONSTRAINT "FormResponse_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "FieldAnswer" ( | ||
| "id" TEXT NOT NULL, | ||
| "responseId" TEXT NOT NULL, | ||
| "fieldId" TEXT NOT NULL, | ||
| "answerValue" TEXT, | ||
| "answerJson" JSONB, | ||
|
|
||
| CONSTRAINT "FieldAnswer_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateIndex | ||
| CREATE UNIQUE INDEX "Form_slug_key" ON "Form"("slug"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE UNIQUE INDEX "FormContributor_formId_userId_key" ON "FormContributor"("formId", "userId"); | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "Form" ADD CONSTRAINT "Form_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FormContributor" ADD CONSTRAINT "FormContributor_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FormContributor" ADD CONSTRAINT "FormContributor_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FormField" ADD CONSTRAINT "FormField_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FormResponse" ADD CONSTRAINT "FormResponse_formId_fkey" FOREIGN KEY ("formId") REFERENCES "Form"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FormResponse" ADD CONSTRAINT "FormResponse_submittedBy_fkey" FOREIGN KEY ("submittedBy") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_responseId_fkey" FOREIGN KEY ("responseId") REFERENCES "FormResponse"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_fieldId_fkey" FOREIGN KEY ("fieldId") REFERENCES "FormField"("id") ON DELETE RESTRICT ON UPDATE CASCADE; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| /* | ||
| Warnings: | ||
|
|
||
| - A unique constraint covering the columns `[formUrl]` on the table `Form` will be added. If there are existing duplicate values, this will fail. | ||
| - Added the required column `formUrl` to the `Form` table without a default value. This is not possible if the table is not empty. | ||
|
|
||
| */ | ||
| -- AlterTable | ||
| ALTER TABLE "Form" ADD COLUMN "formUrl" TEXT NOT NULL; | ||
|
|
||
| -- CreateIndex | ||
| CREATE UNIQUE INDEX "Form_formUrl_key" ON "Form"("formUrl"); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| /* | ||
| Warnings: | ||
|
|
||
| - The primary key for the `FieldAnswer` table will be changed. If it partially fails, the table could be left without primary key constraint. | ||
| - The `id` column on the `FieldAnswer` table would be dropped and recreated. This will lead to data loss if there is data in the column. | ||
| - You are about to drop the column `isTemplate` on the `Form` table. All the data in the column will be lost. | ||
| - You are about to drop the column `slug` on the `Form` table. All the data in the column will be lost. | ||
| - The primary key for the `FormContributor` table will be changed. If it partially fails, the table could be left without primary key constraint. | ||
| - The `id` column on the `FormContributor` table would be dropped and recreated. This will lead to data loss if there is data in the column. | ||
| - The primary key for the `FormField` table will be changed. If it partially fails, the table could be left without primary key constraint. | ||
| - The `id` column on the `FormField` table would be dropped and recreated. This will lead to data loss if there is data in the column. | ||
| - The primary key for the `FormResponse` table will be changed. If it partially fails, the table could be left without primary key constraint. | ||
| - The `id` column on the `FormResponse` table would be dropped and recreated. This will lead to data loss if there is data in the column. | ||
| - Changed the type of `responseId` on the `FieldAnswer` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. | ||
| - Changed the type of `fieldId` on the `FieldAnswer` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. | ||
|
|
||
| */ | ||
| -- CreateEnum | ||
| CREATE TYPE "PermissionLevel" AS ENUM ('VIEW', 'EDIT'); | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "FieldAnswer" DROP CONSTRAINT "FieldAnswer_fieldId_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "FieldAnswer" DROP CONSTRAINT "FieldAnswer_responseId_fkey"; | ||
|
|
||
| -- DropIndex | ||
| DROP INDEX "Form_slug_key"; | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "FieldAnswer" DROP CONSTRAINT "FieldAnswer_pkey", | ||
| DROP COLUMN "id", | ||
| ADD COLUMN "id" SERIAL NOT NULL, | ||
| DROP COLUMN "responseId", | ||
| ADD COLUMN "responseId" INTEGER NOT NULL, | ||
| DROP COLUMN "fieldId", | ||
| ADD COLUMN "fieldId" INTEGER NOT NULL, | ||
| ADD CONSTRAINT "FieldAnswer_pkey" PRIMARY KEY ("id"); | ||
|
Comment on lines
+31
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. High risk of data loss by drop/recreate; prefer in-place type change or staged backfill. Dropping Safer pattern: -ALTER TABLE "FieldAnswer" DROP CONSTRAINT "FieldAnswer_pkey",
-DROP COLUMN "id",
-ADD COLUMN "id" SERIAL NOT NULL,
-DROP COLUMN "responseId",
-ADD COLUMN "responseId" INTEGER NOT NULL,
-DROP COLUMN "fieldId",
-ADD COLUMN "fieldId" INTEGER NOT NULL,
-ADD CONSTRAINT "FieldAnswer_pkey" PRIMARY KEY ("id");
+-- Option A: in-place cast if prior types are castable
+ALTER TABLE "FieldAnswer" ALTER COLUMN "responseId" TYPE INTEGER USING ("responseId"::INTEGER);
+ALTER TABLE "FieldAnswer" ALTER COLUMN "fieldId" TYPE INTEGER USING ("fieldId"::INTEGER);
+-- If changing PK strategy, add new column, backfill, then swap in a transaction with minimal lock.
+-- Example:
+-- ALTER TABLE "FieldAnswer" ADD COLUMN "id2" SERIAL;
+-- UPDATE "FieldAnswer" SET "id2" = nextval(pg_get_serial_sequence('"FieldAnswer"','id2')) WHERE "id2" IS NULL;
+-- ALTER TABLE "FieldAnswer" DROP CONSTRAINT "FieldAnswer_pkey";
+-- ALTER TABLE "FieldAnswer" RENAME COLUMN "id" TO "id_old";
+-- ALTER TABLE "FieldAnswer" RENAME COLUMN "id2" TO "id";
+-- ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_pkey" PRIMARY KEY ("id");Schedule a maintenance window and take backups before applying.
🤖 Prompt for AI Agents |
||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "Form" DROP COLUMN "isTemplate", | ||
| DROP COLUMN "slug", | ||
| ADD COLUMN "isEditable" BOOLEAN NOT NULL DEFAULT false; | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "FormContributor" DROP CONSTRAINT "FormContributor_pkey", | ||
| ADD COLUMN "permission" "PermissionLevel" NOT NULL DEFAULT 'VIEW', | ||
| DROP COLUMN "id", | ||
| ADD COLUMN "id" SERIAL NOT NULL, | ||
| ADD CONSTRAINT "FormContributor_pkey" PRIMARY KEY ("id"); | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "FormField" DROP CONSTRAINT "FormField_pkey", | ||
| DROP COLUMN "id", | ||
| ADD COLUMN "id" SERIAL NOT NULL, | ||
| ADD CONSTRAINT "FormField_pkey" PRIMARY KEY ("id"); | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "FormResponse" DROP CONSTRAINT "FormResponse_pkey", | ||
| DROP COLUMN "id", | ||
| ADD COLUMN "id" SERIAL NOT NULL, | ||
| ADD CONSTRAINT "FormResponse_pkey" PRIMARY KEY ("id"); | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_responseId_fkey" FOREIGN KEY ("responseId") REFERENCES "FormResponse"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_fieldId_fkey" FOREIGN KEY ("fieldId") REFERENCES "FormField"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
Comment on lines
+64
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use cascading deletes for child rows to prevent referential dead-ends.
-ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_responseId_fkey" FOREIGN KEY ("responseId") REFERENCES "FormResponse"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_responseId_fkey" FOREIGN KEY ("responseId") REFERENCES "FormResponse"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_fieldId_fkey" FOREIGN KEY ("fieldId") REFERENCES "FormField"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+ALTER TABLE "FieldAnswer" ADD CONSTRAINT "FieldAnswer_fieldId_fkey" FOREIGN KEY ("fieldId") REFERENCES "FormField"("id") ON DELETE CASCADE ON UPDATE CASCADE; |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| /* | ||
| Warnings: | ||
|
|
||
| - You are about to drop the column `metadata` on the `FormResponse` table. All the data in the column will be lost. | ||
| - You are about to drop the column `responderIp` on the `FormResponse` table. All the data in the column will be lost. | ||
| - You are about to drop the column `userAgent` on the `FormResponse` table. All the data in the column will be lost. | ||
|
|
||
| */ | ||
| -- AlterTable | ||
| ALTER TABLE "FormField" ADD COLUMN "allowMultiple" BOOLEAN NOT NULL DEFAULT false; | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "FormResponse" DROP COLUMN "metadata", | ||
| DROP COLUMN "responderIp", | ||
| DROP COLUMN "userAgent", | ||
| ADD COLUMN "anonymousId" TEXT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Risky NOT NULL add on non-empty table; backfill first, then enforce NOT NULL + UNIQUE.
As written, this fails if
Formhas rows or duplicates. Prefer a safe, two-step migration that backfills from an existing unique field (e.g.,slug) before adding constraints.Please confirm
Form.slugexists and is unique; if not, we should generate a stable code (e.g., shortid/uuid) and backfill instead. Also check for case-insensitive uniqueness needs; if required, consider a functional index onlower("formUrl").I need to verify the safety of this migration by examining the codebase context. Let me gather information about the Form table structure and the migration context.
🏁 Script executed:
Length of output: 30
🏁 Script executed:
Length of output: 69
🏁 Script executed:
Length of output: 10878
🏁 Script executed:
Length of output: 30
🏁 Script executed:
Length of output: 797
I need to examine the earlier migration to understand the Form table evolution and determine if the backfill suggestion is valid.
Length of output: 3384
🏁 Script executed:
Length of output: 450
🏁 Script executed:
Length of output: 0
Migration adds NOT NULL constraint without safe backfill; use two-step approach.
The migration's risk is real: the Prisma warning confirms "This is not possible if the table is not empty". The Form table was created with a
slugfield that is unique, so backfilling fromslugis a sound strategy. The two-step migration approach is appropriate: add nullable column, backfill fromslug, create unique index, then enforce NOT NULL.📝 Committable suggestion
🤖 Prompt for AI Agents