refactor: define survey model

This commit is contained in:
moonrailgun 2024-04-27 22:13:43 +08:00
parent 7d370b4fc5
commit 9143cc468c
8 changed files with 192 additions and 3 deletions

View File

@ -0,0 +1,48 @@
-- CreateTable
CREATE TABLE "Survey" (
"id" VARCHAR(30) NOT NULL,
"workspaceId" VARCHAR(30) NOT NULL,
"name" TEXT NOT NULL,
"payload" JSON NOT NULL,
"createdAt" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMPTZ(6) NOT NULL,
CONSTRAINT "Survey_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "SurveyResult" (
"id" VARCHAR(30) NOT NULL,
"surveyId" VARCHAR(30) NOT NULL,
"createdAt" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"sessionId" UUID NOT NULL,
"payload" JSON NOT NULL,
"browser" VARCHAR(20),
"os" VARCHAR(20),
"language" VARCHAR(35),
"ip" VARCHAR(45),
"country" CHAR(2),
"subdivision1" VARCHAR(20),
"subdivision2" VARCHAR(50),
"city" VARCHAR(50),
"longitude" DOUBLE PRECISION,
"latitude" DOUBLE PRECISION,
"accuracyRadius" INTEGER,
CONSTRAINT "SurveyResult_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "Survey_workspaceId_idx" ON "Survey"("workspaceId");
-- CreateIndex
CREATE INDEX "SurveyResult_surveyId_idx" ON "SurveyResult"("surveyId");
-- CreateIndex
CREATE INDEX "SurveyResult_sessionId_idx" ON "SurveyResult"("sessionId");
-- AddForeignKey
ALTER TABLE "Survey" ADD CONSTRAINT "Survey_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "SurveyResult" ADD CONSTRAINT "SurveyResult_surveyId_fkey" FOREIGN KEY ("surveyId") REFERENCES "Survey"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -55,6 +55,7 @@ model Workspace {
selectedUsers User[] // user list who select this workspace, not use in most of case selectedUsers User[] // user list who select this workspace, not use in most of case
workspaceDailyUsage WorkspaceDailyUsage[] workspaceDailyUsage WorkspaceDailyUsage[]
workspaceAuditLog WorkspaceAuditLog[] workspaceAuditLog WorkspaceAuditLog[]
surveys Survey[]
} }
model WorkspacesOnUsers { model WorkspacesOnUsers {
@ -400,3 +401,46 @@ enum WorkspaceAuditLogType {
Monitor Monitor
Notification Notification
} }
model Survey {
id String @id @default(cuid()) @db.VarChar(30)
workspaceId String @db.VarChar(30)
name String
/// [SurveyPayload]
/// @zod.custom(imports.SurveyPayloadSchema)
payload Json @db.Json
createdAt DateTime @default(now()) @db.Timestamptz(6)
updatedAt DateTime @updatedAt @db.Timestamptz(6)
workspace Workspace @relation(fields: [workspaceId], references: [id], onUpdate: Cascade, onDelete: Cascade)
surveyResultList SurveyResult[]
@@index([workspaceId])
}
model SurveyResult {
id String @id @default(cuid()) @db.VarChar(30)
surveyId String @db.VarChar(30)
createdAt DateTime @default(now()) @db.Timestamptz(6)
sessionId String @db.Uuid
/// [CommonPayload]
/// @zod.custom(imports.CommonPayloadSchema)
payload Json @db.Json
browser String? @db.VarChar(20)
os String? @db.VarChar(20)
language String? @db.VarChar(35)
ip String? @db.VarChar(45) // The max length of ipv6 which adapter with ipv4 is 45(for example: [::ffff:192.168.100.228] => 0000:0000:0000:0000:0000:ffff:192.168.100.228)
country String? @db.Char(2)
subdivision1 String? @db.VarChar(20)
subdivision2 String? @db.VarChar(50)
city String? @db.VarChar(50)
longitude Float?
latitude Float?
accuracyRadius Int?
survey Survey @relation(fields: [surveyId], references: [id], onUpdate: Cascade, onDelete: Cascade)
@@index([surveyId])
@@index([sessionId])
}

View File

@ -17,3 +17,5 @@ export * from "./monitorstatus"
export * from "./monitorstatuspage" export * from "./monitorstatuspage"
export * from "./workspacedailyusage" export * from "./workspacedailyusage"
export * from "./workspaceauditlog" export * from "./workspaceauditlog"
export * from "./survey"
export * from "./surveyresult"

View File

@ -1,5 +1,7 @@
import { z } from 'zod'; import { z } from 'zod';
export const CommonPayloadSchema = z.record(z.string(), z.any());
export const MonitorStatusPageListSchema = z.array( export const MonitorStatusPageListSchema = z.array(
z.object({ z.object({
id: z.string(), id: z.string(),
@ -7,4 +9,11 @@ export const MonitorStatusPageListSchema = z.array(
}) })
); );
export const CommonPayloadSchema = z.record(z.string(), z.any()); export const SurveyPayloadSchema = z.object({
items: z.object({
label: z.string(),
name: z.string(),
type: z.enum(['text', 'select', 'email']),
options: z.array(z.string()).optional(),
}),
});

View File

@ -0,0 +1,36 @@
import * as z from "zod"
import * as imports from "./schemas"
import { CompleteWorkspace, RelatedWorkspaceModelSchema, CompleteSurveyResult, RelatedSurveyResultModelSchema } from "./index"
// Helper schema for JSON fields
type Literal = boolean | number | string
type Json = Literal | { [key: string]: Json } | Json[]
const literalSchema = z.union([z.string(), z.number(), z.boolean()])
const jsonSchema: z.ZodSchema<Json> = z.lazy(() => z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]))
export const SurveyModelSchema = z.object({
id: z.string(),
workspaceId: z.string(),
name: z.string(),
/**
* [SurveyPayload]
*/
payload: imports.SurveyPayloadSchema,
createdAt: z.date(),
updatedAt: z.date(),
})
export interface CompleteSurvey extends z.infer<typeof SurveyModelSchema> {
workspace: CompleteWorkspace
surveyResultList: CompleteSurveyResult[]
}
/**
* RelatedSurveyModelSchema contains all relations on your model in addition to the scalars
*
* NOTE: Lazy required in case of potential circular dependencies within schema
*/
export const RelatedSurveyModelSchema: z.ZodSchema<CompleteSurvey> = z.lazy(() => SurveyModelSchema.extend({
workspace: RelatedWorkspaceModelSchema,
surveyResultList: RelatedSurveyResultModelSchema.array(),
}))

View File

@ -0,0 +1,44 @@
import * as z from "zod"
import * as imports from "./schemas"
import { CompleteSurvey, RelatedSurveyModelSchema } from "./index"
// Helper schema for JSON fields
type Literal = boolean | number | string
type Json = Literal | { [key: string]: Json } | Json[]
const literalSchema = z.union([z.string(), z.number(), z.boolean()])
const jsonSchema: z.ZodSchema<Json> = z.lazy(() => z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]))
export const SurveyResultModelSchema = z.object({
id: z.string(),
surveyId: z.string(),
createdAt: z.date(),
sessionId: z.string(),
/**
* [CommonPayload]
*/
payload: imports.CommonPayloadSchema,
browser: z.string().nullish(),
os: z.string().nullish(),
language: z.string().nullish(),
ip: z.string().nullish(),
country: z.string().nullish(),
subdivision1: z.string().nullish(),
subdivision2: z.string().nullish(),
city: z.string().nullish(),
longitude: z.number().nullish(),
latitude: z.number().nullish(),
accuracyRadius: z.number().int().nullish(),
})
export interface CompleteSurveyResult extends z.infer<typeof SurveyResultModelSchema> {
survey: CompleteSurvey
}
/**
* RelatedSurveyResultModelSchema contains all relations on your model in addition to the scalars
*
* NOTE: Lazy required in case of potential circular dependencies within schema
*/
export const RelatedSurveyResultModelSchema: z.ZodSchema<CompleteSurveyResult> = z.lazy(() => SurveyResultModelSchema.extend({
survey: RelatedSurveyModelSchema,
}))

View File

@ -1,6 +1,6 @@
import * as z from "zod" import * as z from "zod"
import * as imports from "./schemas" import * as imports from "./schemas"
import { CompleteWorkspacesOnUsers, RelatedWorkspacesOnUsersModelSchema, CompleteWebsite, RelatedWebsiteModelSchema, CompleteNotification, RelatedNotificationModelSchema, CompleteMonitor, RelatedMonitorModelSchema, CompleteMonitorStatusPage, RelatedMonitorStatusPageModelSchema, CompleteTelemetry, RelatedTelemetryModelSchema, CompleteUser, RelatedUserModelSchema, CompleteWorkspaceDailyUsage, RelatedWorkspaceDailyUsageModelSchema, CompleteWorkspaceAuditLog, RelatedWorkspaceAuditLogModelSchema } from "./index" import { CompleteWorkspacesOnUsers, RelatedWorkspacesOnUsersModelSchema, CompleteWebsite, RelatedWebsiteModelSchema, CompleteNotification, RelatedNotificationModelSchema, CompleteMonitor, RelatedMonitorModelSchema, CompleteMonitorStatusPage, RelatedMonitorStatusPageModelSchema, CompleteTelemetry, RelatedTelemetryModelSchema, CompleteUser, RelatedUserModelSchema, CompleteWorkspaceDailyUsage, RelatedWorkspaceDailyUsageModelSchema, CompleteWorkspaceAuditLog, RelatedWorkspaceAuditLogModelSchema, CompleteSurvey, RelatedSurveyModelSchema } from "./index"
// Helper schema for JSON fields // Helper schema for JSON fields
type Literal = boolean | number | string type Literal = boolean | number | string
@ -34,6 +34,7 @@ export interface CompleteWorkspace extends z.infer<typeof WorkspaceModelSchema>
selectedUsers: CompleteUser[] selectedUsers: CompleteUser[]
workspaceDailyUsage: CompleteWorkspaceDailyUsage[] workspaceDailyUsage: CompleteWorkspaceDailyUsage[]
workspaceAuditLog: CompleteWorkspaceAuditLog[] workspaceAuditLog: CompleteWorkspaceAuditLog[]
surveys: CompleteSurvey[]
} }
/** /**
@ -51,4 +52,5 @@ export const RelatedWorkspaceModelSchema: z.ZodSchema<CompleteWorkspace> = z.laz
selectedUsers: RelatedUserModelSchema.array(), selectedUsers: RelatedUserModelSchema.array(),
workspaceDailyUsage: RelatedWorkspaceDailyUsageModelSchema.array(), workspaceDailyUsage: RelatedWorkspaceDailyUsageModelSchema.array(),
workspaceAuditLog: RelatedWorkspaceAuditLogModelSchema.array(), workspaceAuditLog: RelatedWorkspaceAuditLogModelSchema.array(),
surveys: RelatedSurveyModelSchema.array(),
})) }))

View File

@ -1,5 +1,8 @@
import type { JWTPayload } from '../middleware/auth'; import type { JWTPayload } from '../middleware/auth';
import type { MonitorStatusPageListSchema } from '../prisma/zod/schemas'; import type {
MonitorStatusPageListSchema,
SurveyPayloadSchema,
} from '../prisma/zod/schemas';
declare global { declare global {
namespace Express { namespace Express {
@ -13,5 +16,6 @@ declare global {
items: any[]; items: any[];
} | null; } | null;
type MonitorStatusPageList = z.infer<typeof MonitorStatusPageListSchema>; type MonitorStatusPageList = z.infer<typeof MonitorStatusPageListSchema>;
type SurveyPayload = z.infer<typeof SurveyPayloadSchema>;
} }
} }