mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
Add property_overrides table + override_component enum (0221)
The per-Property fact layer deferred by ADR-0004: one row per (property, building_part, override_component) holding the resolved landlord-override enum as a denormalised text snapshot, plus the raw spreadsheet description it resolved from. Schema only — no writer yet. The bulk_upload_finaliser application will populate it (recalculate-on-rerun via upsert on the unique key). Design and rationale (snapshot-not-FK, drop source, recalculate semantics) in docs/design/bulk-upload-finaliser.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e923cf0ff6
commit
fa9bf538da
4 changed files with 10774 additions and 0 deletions
16
src/app/db/migrations/0221_nice_sumo.sql
Normal file
16
src/app/db/migrations/0221_nice_sumo.sql
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
CREATE TYPE "public"."override_component" AS ENUM('wall_type', 'roof_type', 'property_type', 'built_form_type');--> statement-breakpoint
|
||||
CREATE TABLE "property_overrides" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"property_id" bigint NOT NULL,
|
||||
"portfolio_id" bigint NOT NULL,
|
||||
"building_part" smallint NOT NULL,
|
||||
"override_component" "override_component" NOT NULL,
|
||||
"override_value" text NOT NULL,
|
||||
"original_spreadsheet_description" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "property_overrides_property_component_part_unique" UNIQUE("property_id","override_component","building_part")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "property_overrides" ADD CONSTRAINT "property_overrides_property_id_property_id_fk" FOREIGN KEY ("property_id") REFERENCES "public"."property"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "property_overrides" ADD CONSTRAINT "property_overrides_portfolio_id_portfolio_id_fk" FOREIGN KEY ("portfolio_id") REFERENCES "public"."portfolio"("id") ON DELETE cascade ON UPDATE no action;
|
||||
10683
src/app/db/migrations/meta/0221_snapshot.json
Normal file
10683
src/app/db/migrations/meta/0221_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1541,6 +1541,13 @@
|
|||
"when": 1780491109956,
|
||||
"tag": "0220_round_retro_girl",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 221,
|
||||
"version": "7",
|
||||
"when": 1780566543108,
|
||||
"tag": "0221_nice_sumo",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
68
src/app/db/schema/property_overrides.ts
Normal file
68
src/app/db/schema/property_overrides.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import {
|
||||
bigint,
|
||||
pgEnum,
|
||||
pgTable,
|
||||
smallint,
|
||||
text,
|
||||
timestamp,
|
||||
unique,
|
||||
uuid,
|
||||
} from "drizzle-orm/pg-core";
|
||||
import { portfolio } from "./portfolio";
|
||||
import { property } from "./property";
|
||||
|
||||
// The per-Property fact layer deferred by ADR-0004: one row per
|
||||
// (property, building_part, override_component) carrying the resolved enum value
|
||||
// as a denormalised snapshot. Design + rationale (Q6–Q9, snapshot-not-FK,
|
||||
// recalculate-on-rerun) live in docs/design/bulk-upload-finaliser.md.
|
||||
//
|
||||
// `override_component` values mirror the classifier category keys used in BOTH the
|
||||
// frontend (src/lib/bulkUpload/columnFields.ts) and the Model backend
|
||||
// (ClassifiableColumn.name), so the finaliser maps category → component with no
|
||||
// translation. This is the only DB-level typing left on a row — `override_value`
|
||||
// is a free-text snapshot of the resolved enum from `landlord_*_overrides`.
|
||||
export const OverrideComponentValues: [string, ...string[]] = [
|
||||
"wall_type",
|
||||
"roof_type",
|
||||
"property_type",
|
||||
"built_form_type",
|
||||
];
|
||||
|
||||
export const overrideComponentEnum = pgEnum(
|
||||
"override_component",
|
||||
OverrideComponentValues,
|
||||
);
|
||||
|
||||
export const propertyOverrides = pgTable(
|
||||
"property_overrides",
|
||||
{
|
||||
id: uuid("id").defaultRandom().primaryKey(),
|
||||
propertyId: bigint("property_id", { mode: "bigint" })
|
||||
.notNull()
|
||||
.references(() => property.id, { onDelete: "cascade" }),
|
||||
portfolioId: bigint("portfolio_id", { mode: "bigint" })
|
||||
.notNull()
|
||||
.references(() => portfolio.id, { onDelete: "cascade" }),
|
||||
// 0 = main building, 1 = extension 1, 2 = extension 2, … (ADR-0004 ordering).
|
||||
buildingPart: smallint("building_part").notNull(),
|
||||
overrideComponent: overrideComponentEnum("override_component").notNull(),
|
||||
// Denormalised snapshot copy of the resolved enum from landlord_*_overrides.
|
||||
overrideValue: text("override_value").notNull(),
|
||||
// Raw spreadsheet cell text this snapshot resolved from (provenance + re-sync key).
|
||||
originalSpreadsheetDescription: text(
|
||||
"original_spreadsheet_description",
|
||||
).notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.notNull()
|
||||
.defaultNow(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true })
|
||||
.notNull()
|
||||
.defaultNow()
|
||||
.$onUpdate(() => new Date()),
|
||||
},
|
||||
(table) => ({
|
||||
propertyComponentPartUnique: unique(
|
||||
"property_overrides_property_component_part_unique",
|
||||
).on(table.propertyId, table.overrideComponent, table.buildingPart),
|
||||
}),
|
||||
);
|
||||
Loading…
Add table
Reference in a new issue