UNPKG

@damourlabs/euro-clinical-trials

Version:

A Nuxt 3 application for visualizing and managing clinical trials data in Europe, built with modern web technologies.

203 lines (191 loc) 7.96 kB
// Drizzle ORM schema for Regulatory Compliance tables import { pgTable, uuid, varchar, text, timestamp, decimal, date, boolean, check, pgEnum } from 'drizzle-orm/pg-core'; import { sql } from 'drizzle-orm'; import { z } from 'zod'; import type { Expect, IsSameType } from '~/types/equality'; import { sites, trials, patients } from '.'; import { AESeverityEnum, ApprovalStatusEnum, ApprovalTypeEnum } from './enums'; export const regulatoryFieldDefaultValues = { approvalType: ApprovalTypeEnum.Enum.ClinicalTrial, status: ApprovalStatusEnum.Enum.Approved, gdprCompliant: false, overallCompliance: '0.00', patientCompliance: '0.00', siteCompliance: '0.00', severity: AESeverityEnum.Enum.Mild }; export const pgApprovalType = pgEnum('approval_type_enum', ApprovalTypeEnum.options); export const pgApprovalStatus = pgEnum('approval_status_enum', ApprovalStatusEnum.options); // ---------------------------- // --- Regulatory Approvals --- // ---------------------------- export const regulatoryApprovals = pgTable('regulatory_approvals', { uuid: uuid('uuid').primaryKey().defaultRandom(), trialUuid: uuid('trial_uuid').notNull().references(() => trials.uuid, { onDelete: 'cascade' }), approvalType: pgApprovalType().notNull().default(regulatoryFieldDefaultValues.approvalType), status: pgApprovalStatus().notNull().default(regulatoryFieldDefaultValues.status), authority: varchar('authority', { length: 255 }).notNull(), approvalDate: date('approval_date').default(sql`CURRENT_DATE`), expiryDate: date('expiry_date'), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(), }, (table) => [ check('regulatory_approvals_authority_not_empty', sql`LENGTH(TRIM(${table.authority})) > 0`), check('regulatory_approvals_date_order', sql`${table.approvalDate} IS NULL OR ${table.expiryDate} IS NULL OR ${table.approvalDate} <= ${table.expiryDate}`), ]); export const regulatoryApprovalsSchema = z.object({ uuid: z.string() .uuid() .describe("Unique identifier for the regulatory approval, automatically generated if not provided") , trialUuid: z.string() .uuid() .describe("UUID of the trial this approval belongs to") , approvalType: ApprovalTypeEnum .describe("Type of regulatory approval") .default(regulatoryFieldDefaultValues.approvalType) , status: ApprovalStatusEnum .describe("Status of the approval") .default(regulatoryFieldDefaultValues.status) , authority: z.string() .max(255) .min(1) .describe("Regulatory authority that granted the approval") , approvalDate: z.string() .nullable() .describe("Date when the approval was granted") , expiryDate: z.string() .nullable() .describe("Date when the approval expires") , createdAt: z.date() .nullable() .describe("Timestamp of when the approval record was created") , }); // ------------------------- // --- Compliance Status --- // ------------------------- export const complianceStatus = pgTable('compliance_status', { uuid: uuid('uuid').primaryKey().defaultRandom(), trialUuid: uuid('trial_uuid').notNull().unique().references(() => trials.uuid, { onDelete: 'cascade' }), gdprCompliant: boolean('gdpr_compliant').notNull().default(regulatoryFieldDefaultValues.gdprCompliant), overallCompliance: decimal('overall_compliance', { precision: 5, scale: 2 }).notNull().default(regulatoryFieldDefaultValues.overallCompliance), patientCompliance: decimal('patient_compliance', { precision: 5, scale: 2 }).notNull().default(regulatoryFieldDefaultValues.patientCompliance), siteCompliance: decimal('site_compliance', { precision: 5, scale: 2 }).notNull().default(regulatoryFieldDefaultValues.siteCompliance), lastUpdated: date('last_updated').notNull().default(sql`CURRENT_DATE`), }, (table) => [ check('compliance_status_percentages_valid', sql`${table.overallCompliance} >= 0.00 AND ${table.overallCompliance} <= 100.00 AND ${table.patientCompliance} >= 0.00 AND ${table.patientCompliance} <= 100.00 AND ${table.siteCompliance} >= 0.00 AND ${table.siteCompliance} <= 100.00`), ]); export const complianceStatusSchema = z.object({ uuid: z.string() .uuid() .describe("Unique identifier for the compliance status, automatically generated if not provided") , trialUuid: z.string() .uuid() .describe("UUID of the trial this compliance status belongs to") , gdprCompliant: z.boolean() .describe("Whether the trial is GDPR compliant") .default(regulatoryFieldDefaultValues.gdprCompliant) , overallCompliance: z.string() .describe("Overall compliance percentage") .default(regulatoryFieldDefaultValues.overallCompliance) , patientCompliance: z.string() .describe("Patient compliance percentage") .default(regulatoryFieldDefaultValues.patientCompliance) , siteCompliance: z.string() .describe("Site compliance percentage") .default(regulatoryFieldDefaultValues.siteCompliance) , lastUpdated: z.string() .describe("Date when compliance status was last updated") , }); // --------------------------- // --- Protocol Deviations --- // --------------------------- export const pgSeverity = pgEnum('severity_enum', AESeverityEnum.options) export const protocolDeviations = pgTable('protocol_deviations', { uuid: uuid('uuid').primaryKey().defaultRandom(), trialUuid: uuid('trial_uuid').notNull().references(() => trials.uuid, { onDelete: 'cascade' }), patientUuid: uuid('patient_uuid').references(() => patients.uuid, { onDelete: 'cascade' }), siteUuid: uuid('site_uuid').references(() => sites.uuid, { onDelete: 'cascade' }), description: text('description').notNull(), dateOccurred: date('date_occurred').notNull().default(sql`CURRENT_DATE`), severity: pgSeverity("severity").notNull().default(regulatoryFieldDefaultValues.severity), impactAssessment: text('impact_assessment'), correctiveAction: text('corrective_action'), reportedAt: timestamp('reported_at', { withTimezone: true }).defaultNow(), }, (table) => [ check('protocol_deviations_description_not_empty', sql`LENGTH(TRIM(${table.description})) > 0`), ]); export const protocolDeviationsSchema = z.object({ uuid: z.string() .uuid() .describe("Unique identifier for the protocol deviation, automatically generated if not provided") , trialUuid: z.string() .uuid() .describe("UUID of the trial this deviation belongs to") , patientUuid: z.string() .uuid() .nullable() .describe("UUID of the patient involved in the deviation") , siteUuid: z.string() .uuid() .nullable() .describe("UUID of the site where the deviation occurred") , description: z.string() .min(1) .describe("Description of the protocol deviation") , dateOccurred: z.string() .describe("Date when the deviation occurred") , severity: AESeverityEnum .describe("Severity of the deviation") .default(regulatoryFieldDefaultValues.severity) , impactAssessment: z.string() .nullable() .describe("Assessment of the deviation's impact") , correctiveAction: z.string() .nullable() .describe("Corrective action taken for the deviation") , reportedAt: z.date() .nullable() .describe("Timestamp when the deviation was reported") , }); export type RegulatoryApproval = z.infer<typeof regulatoryApprovalsSchema>; export type ComplianceStatus = z.infer<typeof complianceStatusSchema>; export type ProtocolDeviation = z.infer<typeof protocolDeviationsSchema>; // TODO: Fix type mismatches between Zod schemas and Drizzle table types type _regulatoryApprovalSchemaMatchesTable = Expect<IsSameType<RegulatoryApproval, typeof regulatoryApprovals.$inferSelect>> type _complianceStatusSchemaMatchesTable = Expect<IsSameType<ComplianceStatus, typeof complianceStatus.$inferSelect>> type _protocolDeviationSchemaMatchesTable = Expect<IsSameType<ProtocolDeviation, typeof protocolDeviations.$inferSelect>>