diff --git a/api/spec/factories/Room/KitchenFactory.ts b/api/spec/factories/Room/KitchenFactory.ts
new file mode 100644
index 0000000..cb6d068
--- /dev/null
+++ b/api/spec/factories/Room/KitchenFactory.ts
@@ -0,0 +1,9 @@
+import { UpdateableProperties } from '@rvoh/dream/types'
+import Kitchen from '@models/Room/Kitchen.js'
+
+export default async function createKitchen(attrs: UpdateableProperties<Kitchen> = {}) {
+ return await Kitchen.create({
+ appliances: ['stove'],
+ ...attrs,
+ })
+}
diff --git a/api/spec/unit/models/Room/Kitchen.spec.ts b/api/spec/unit/models/Room/Kitchen.spec.ts
new file mode 100644
index 0000000..d5dfbf9
--- /dev/null
+++ b/api/spec/unit/models/Room/Kitchen.spec.ts
@@ -0,0 +1,3 @@
+describe('Room/Kitchen', () => {
+ it.todo('add a test here to get started building Room/Kitchen')
+})
diff --git a/api/src/app/models/Room/Kitchen.ts b/api/src/app/models/Room/Kitchen.ts
new file mode 100644
index 0000000..e6e9a80
--- /dev/null
+++ b/api/src/app/models/Room/Kitchen.ts
@@ -0,0 +1,17 @@
+import { Decorators, STI } from '@rvoh/dream'
+import { DreamColumn, DreamSerializers } from '@rvoh/dream/types'
+import Room from '@models/Room.js'
+
+const deco = new Decorators<typeof Kitchen>()
+
+@STI(Room)
+export default class Kitchen extends Room {
+ public override get serializers(): DreamSerializers<Kitchen> {
+ return {
+ default: 'Room/KitchenSerializer',
+ summary: 'Room/KitchenSummarySerializer',
+ }
+ }
+
+ public appliances: DreamColumn<Kitchen, 'appliances'>
+}
diff --git a/api/src/app/serializers/Room/KitchenSerializer.ts b/api/src/app/serializers/Room/KitchenSerializer.ts
new file mode 100644
index 0000000..633aa8f
--- /dev/null
+++ b/api/src/app/serializers/Room/KitchenSerializer.ts
@@ -0,0 +1,9 @@
+import { RoomSerializer, RoomSummarySerializer } from '@serializers/RoomSerializer.js'
+import Kitchen from '@models/Room/Kitchen.js'
+
+export const RoomKitchenSummarySerializer = (kitchen: Kitchen) =>
+ RoomSummarySerializer(Kitchen, kitchen)
+
+export const RoomKitchenSerializer = (kitchen: Kitchen) =>
+ RoomSerializer(Kitchen, kitchen)
+ .attribute('appliances')
diff --git a/api/src/db/migrations/1773153098012-create-room-kitchen.ts b/api/src/db/migrations/1773153098012-create-room-kitchen.ts
new file mode 100644
index 0000000..d798b22
--- /dev/null
+++ b/api/src/db/migrations/1773153098012-create-room-kitchen.ts
@@ -0,0 +1,29 @@
+import { Kysely, sql } from 'kysely'
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export async function up(db: Kysely<any>): Promise<void> {
+ await db.schema
+ .createType('appliance_types_enum')
+ .asEnum([
+ 'stove',
+ 'oven',
+ 'microwave',
+ 'dishwasher'
+ ])
+ .execute()
+
+ await db.schema
+ .alterTable('rooms')
+ .addColumn('appliances', sql`appliance_types_enum[]`, col => col.notNull().defaultTo('{}'))
+ .execute()
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export async function down(db: Kysely<any>): Promise<void> {
+ await db.schema
+ .alterTable('rooms')
+ .dropColumn('appliances')
+ .execute()
+
+ await db.schema.dropType('appliance_types_enum').execute()
+}
\ No newline at end of file
diff --git a/api/src/openapi/mobile.openapi.json b/api/src/openapi/mobile.openapi.json
index 8cf4e91..fed01ca 100644
--- a/api/src/openapi/mobile.openapi.json
+++ b/api/src/openapi/mobile.openapi.json
@@ -349,6 +349,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroomSummary"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchenSummary"
}
]
}
@@ -393,6 +396,18 @@
"schema": {
"type": "object",
"properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
"bathOrShowerStyle": {
"type": [
"string",
@@ -442,6 +457,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroom"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchen"
}
]
}
@@ -508,6 +526,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroom"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchen"
}
]
}
@@ -549,6 +570,18 @@
"schema": {
"type": "object",
"properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
"bathOrShowerStyle": {
"type": [
"string",
@@ -860,6 +893,58 @@
}
}
},
+ "RoomKitchen": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "appliances",
+ "deletedAt",
+ "id",
+ "position",
+ "type"
+ ],
+ "properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "description": "The following values will be allowed:\n dishwasher,\n microwave,\n oven,\n stove"
+ }
+ },
+ "deletedAt": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "id": {
+ "type": "string"
+ },
+ "position": {
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "The following values will be allowed:\n Kitchen"
+ }
+ }
+ },
+ "RoomKitchenSummary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ },
"ValidationErrors": {
"type": "object",
"required": [
diff --git a/api/src/openapi/openapi.json b/api/src/openapi/openapi.json
index e5027c7..9890837 100644
--- a/api/src/openapi/openapi.json
+++ b/api/src/openapi/openapi.json
@@ -349,6 +349,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroomSummary"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchenSummary"
}
]
}
@@ -393,6 +396,18 @@
"schema": {
"type": "object",
"properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
"bathOrShowerStyle": {
"type": [
"string",
@@ -442,6 +457,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroom"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchen"
}
]
}
@@ -508,6 +526,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroom"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchen"
}
]
}
@@ -549,6 +570,18 @@
"schema": {
"type": "object",
"properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
"bathOrShowerStyle": {
"type": [
"string",
@@ -885,6 +918,65 @@
}
}
},
+ "RoomKitchen": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "appliances",
+ "deletedAt",
+ "id",
+ "position",
+ "type"
+ ],
+ "properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
+ "deletedAt": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "id": {
+ "type": "string"
+ },
+ "position": {
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "Kitchen"
+ ]
+ }
+ }
+ },
+ "RoomKitchenSummary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ },
"ValidationErrors": {
"type": "object",
"required": [
diff --git a/api/src/openapi/tests.openapi.json b/api/src/openapi/tests.openapi.json
index 73bcb9c..15038fa 100644
--- a/api/src/openapi/tests.openapi.json
+++ b/api/src/openapi/tests.openapi.json
@@ -349,6 +349,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroomSummary"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchenSummary"
}
]
}
@@ -393,6 +396,18 @@
"schema": {
"type": "object",
"properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
"bathOrShowerStyle": {
"type": [
"string",
@@ -442,6 +457,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroom"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchen"
}
]
}
@@ -508,6 +526,9 @@
},
{
"$ref": "#/components/schemas/RoomBedroom"
+ },
+ {
+ "$ref": "#/components/schemas/RoomKitchen"
}
]
}
@@ -549,6 +570,18 @@
"schema": {
"type": "object",
"properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
"bathOrShowerStyle": {
"type": [
"string",
@@ -885,6 +918,65 @@
}
}
},
+ "RoomKitchen": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "appliances",
+ "deletedAt",
+ "id",
+ "position",
+ "type"
+ ],
+ "properties": {
+ "appliances": {
+ "type": "array",
+ "items": {
+ "type": "string",
+ "enum": [
+ "dishwasher",
+ "microwave",
+ "oven",
+ "stove"
+ ]
+ }
+ },
+ "deletedAt": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "id": {
+ "type": "string"
+ },
+ "position": {
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "enum": [
+ "Kitchen"
+ ]
+ }
+ }
+ },
+ "RoomKitchenSummary": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string"
+ }
+ }
+ },
"ValidationErrors": {
"type": "object",
"required": [
diff --git a/api/src/types/db.ts b/api/src/types/db.ts
index 822576f..cacb7e2 100644
--- a/api/src/types/db.ts
+++ b/api/src/types/db.ts
@@ -68,6 +68,15 @@ import {
*/
import type { ColumnType } from 'kysely'
+export type ApplianceTypesEnum = 'dishwasher' | 'microwave' | 'oven' | 'stove'
+
+export const ApplianceTypesEnumValues = [
+ 'dishwasher',
+ 'microwave',
+ 'oven',
+ 'stove',
+] as const
+
export type ArrayType<T> =
ArrayTypeImpl<T> extends (infer U)[] ? U[] : ArrayTypeImpl<T>
@@ -181,6 +190,7 @@ export interface Places {
}
export interface Rooms {
+ appliances: Generated<ArrayType<ApplianceTypesEnum>>
bathOrShowerStyle: BathOrShowerStylesEnum | null
bedTypes: Generated<ArrayType<BedTypesEnum>>
createdAt: Timestamp
diff --git a/api/src/types/dream.globals.ts b/api/src/types/dream.globals.ts
index 6109591..a014277 100644
--- a/api/src/types/dream.globals.ts
+++ b/api/src/types/dream.globals.ts
@@ -68,6 +68,8 @@ export const globalTypeConfig = {
'Room/BathroomSummarySerializer',
'Room/BedroomSerializer',
'Room/BedroomSummarySerializer',
+ 'Room/KitchenSerializer',
+ 'Room/KitchenSummarySerializer',
'RoomSerializer',
'RoomSummarySerializer',
],
diff --git a/api/src/types/dream.ts b/api/src/types/dream.ts
index 8203e1f..946a014 100644
--- a/api/src/types/dream.ts
+++ b/api/src/types/dream.ts
@@ -63,10 +63,12 @@ import {
type ClockTimeTz,
} from '@rvoh/dream'
import {
+ type ApplianceTypesEnum,
type BathOrShowerStylesEnum,
type BedTypesEnum,
type PlaceStylesEnum,
type RoomTypesEnum,
+ ApplianceTypesEnumValues,
BathOrShowerStylesEnumValues,
BedTypesEnumValues,
PlaceStylesEnumValues,
@@ -409,6 +411,7 @@ export const schema = {
named: [],
},
nonJsonColumnNames: [
+ 'appliances',
'bathOrShowerStyle',
'bedTypes',
'createdAt',
@@ -420,6 +423,15 @@ export const schema = {
'updatedAt',
],
columns: {
+ appliances: {
+ coercedType: {} as ApplianceTypesEnum[],
+ enumType: {} as ApplianceTypesEnum,
+ enumArrayType: [] as ApplianceTypesEnum[],
+ enumValues: ApplianceTypesEnumValues,
+ dbType: 'appliance_types_enum[]',
+ allowNull: false,
+ isArray: true,
+ },
bathOrShowerStyle: {
coercedType: {} as BathOrShowerStylesEnum | null,
enumType: {} as BathOrShowerStylesEnum,
@@ -611,6 +623,7 @@ export const connectionTypeConfig = {
Room: 'rooms',
'Room/Bathroom': 'rooms',
'Room/Bedroom': 'rooms',
+ 'Room/Kitchen': 'rooms',
User: 'users',
},
},
diff --git a/api/src/types/openapi/tests.openapi.d.ts b/api/src/types/openapi/tests.openapi.d.ts
index 60e921d..6ac23ac 100644
--- a/api/src/types/openapi/tests.openapi.d.ts
+++ b/api/src/types/openapi/tests.openapi.d.ts
@@ -225,7 +225,7 @@ export interface paths {
content: {
"application/json": {
cursor: string | null;
- results: (components["schemas"]["RoomBathroomSummary"] | components["schemas"]["RoomBedroomSummary"])[];
+ results: (components["schemas"]["RoomBathroomSummary"] | components["schemas"]["RoomBedroomSummary"] | components["schemas"]["RoomKitchenSummary"])[];
};
};
};
@@ -255,6 +255,7 @@ export interface paths {
requestBody?: {
content: {
"application/json": {
+ appliances?: ("dishwasher" | "microwave" | "oven" | "stove")[];
/** @enum {string|null} */
bathOrShowerStyle?: "bath" | "bath_and_shower" | "none" | "shower" | null;
bedTypes?: ("bunk" | "cot" | "king" | "queen" | "sofabed" | "twin")[];
@@ -269,7 +270,7 @@ export interface paths {
[name: string]: unknown;
};
content: {
- "application/json": components["schemas"]["RoomBathroom"] | components["schemas"]["RoomBedroom"];
+ "application/json": components["schemas"]["RoomBathroom"] | components["schemas"]["RoomBedroom"] | components["schemas"]["RoomKitchen"];
};
};
400: components["responses"]["BadRequest"];
@@ -316,7 +317,7 @@ export interface paths {
[name: string]: unknown;
};
content: {
- "application/json": components["schemas"]["RoomBathroom"] | components["schemas"]["RoomBedroom"];
+ "application/json": components["schemas"]["RoomBathroom"] | components["schemas"]["RoomBedroom"] | components["schemas"]["RoomKitchen"];
};
};
400: components["responses"]["BadRequest"];
@@ -370,6 +371,7 @@ export interface paths {
requestBody?: {
content: {
"application/json": {
+ appliances?: ("dishwasher" | "microwave" | "oven" | "stove")[];
/** @enum {string|null} */
bathOrShowerStyle?: "bath" | "bath_and_shower" | "none" | "shower" | null;
bedTypes?: ("bunk" | "cot" | "king" | "queen" | "sofabed" | "twin")[];
@@ -446,6 +448,18 @@ export interface components {
RoomBedroomSummary: {
id: string;
};
+ RoomKitchen: {
+ appliances: ("dishwasher" | "microwave" | "oven" | "stove")[];
+ /** Format: date-time */
+ deletedAt: string | null;
+ id: string;
+ position: number | null;
+ /** @enum {string} */
+ type: "Kitchen";
+ };
+ RoomKitchenSummary: {
+ id: string;
+ };
ValidationErrors: {
/** @enum {string} */
type: "validation";