feat: add module migration contracts and validation
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { z } from "zod";
|
||||
import { moduleIdSchema } from "./identifiers.js";
|
||||
|
||||
export const DRIZZLE_MIGRATION_DIALECT = "postgresql";
|
||||
export const DRIZZLE_MIGRATION_FORMAT_VERSION = "7";
|
||||
export const DRIZZLE_MIGRATION_META_DIRECTORY = "meta";
|
||||
export const DRIZZLE_MIGRATION_JOURNAL_FILENAME = "_journal.json";
|
||||
export const EKKLESIA_MIGRATION_POLICY_FILENAME = "_ekklesia.json";
|
||||
export const DRIZZLE_MIGRATION_ORIGIN_UUID = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
export const moduleMigrationTagSchema = z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(120)
|
||||
.regex(
|
||||
/^\d{4,}_[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/u,
|
||||
"Must be an indexed lowercase Drizzle migration tag.",
|
||||
);
|
||||
|
||||
export const drizzleMigrationJournalEntrySchema = z
|
||||
.object({
|
||||
idx: z.number().int().safe().nonnegative(),
|
||||
version: z.literal(DRIZZLE_MIGRATION_FORMAT_VERSION),
|
||||
when: z.number().int().safe().positive(),
|
||||
tag: z.string().min(1).max(240),
|
||||
breakpoints: z.boolean(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const drizzleMigrationJournalSchema = z
|
||||
.object({
|
||||
version: z.literal(DRIZZLE_MIGRATION_FORMAT_VERSION),
|
||||
dialect: z.literal(DRIZZLE_MIGRATION_DIALECT),
|
||||
entries: z.array(drizzleMigrationJournalEntrySchema).min(1),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const drizzleMigrationSnapshotHeaderSchema = z
|
||||
.object({
|
||||
version: z.literal(DRIZZLE_MIGRATION_FORMAT_VERSION),
|
||||
dialect: z.literal(DRIZZLE_MIGRATION_DIALECT),
|
||||
id: z.uuid(),
|
||||
prevId: z.uuid(),
|
||||
})
|
||||
.passthrough();
|
||||
|
||||
export const moduleMigrationDestructiveDeclarationSchema = z.discriminatedUnion("mode", [
|
||||
z.object({ mode: z.literal("none") }).strict(),
|
||||
z
|
||||
.object({
|
||||
mode: z.literal("approval-required"),
|
||||
reason: z.string().trim().min(1).max(500),
|
||||
})
|
||||
.strict(),
|
||||
]);
|
||||
|
||||
export const moduleMigrationPolicyEntrySchema = z
|
||||
.object({
|
||||
tag: moduleMigrationTagSchema,
|
||||
destructive: moduleMigrationDestructiveDeclarationSchema,
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const moduleMigrationPolicySchema = z
|
||||
.object({
|
||||
version: z.literal(1),
|
||||
moduleId: moduleIdSchema,
|
||||
entries: z.array(moduleMigrationPolicyEntrySchema).min(1),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export function parseDrizzleMigrationJournal(input: unknown): DrizzleMigrationJournal {
|
||||
return drizzleMigrationJournalSchema.parse(input);
|
||||
}
|
||||
|
||||
export function parseDrizzleMigrationSnapshotHeader(
|
||||
input: unknown,
|
||||
): DrizzleMigrationSnapshotHeader {
|
||||
return drizzleMigrationSnapshotHeaderSchema.parse(input);
|
||||
}
|
||||
|
||||
export function parseModuleMigrationPolicy(input: unknown): ModuleMigrationPolicy {
|
||||
return moduleMigrationPolicySchema.parse(input);
|
||||
}
|
||||
|
||||
export type DrizzleMigrationJournal = z.output<typeof drizzleMigrationJournalSchema>;
|
||||
export type DrizzleMigrationJournalEntry = z.output<typeof drizzleMigrationJournalEntrySchema>;
|
||||
export type DrizzleMigrationSnapshotHeader = z.output<typeof drizzleMigrationSnapshotHeaderSchema>;
|
||||
export type ModuleMigrationDestructiveDeclaration = z.output<
|
||||
typeof moduleMigrationDestructiveDeclarationSchema
|
||||
>;
|
||||
export type ModuleMigrationPolicy = z.output<typeof moduleMigrationPolicySchema>;
|
||||
export type ModuleMigrationPolicyEntry = z.output<typeof moduleMigrationPolicyEntrySchema>;
|
||||
Reference in New Issue
Block a user