From d7f46ccee364e438e8ac8ac4011eaa0df8806a27 Mon Sep 17 00:00:00 2001 From: Devesh Kolte Date: Sun, 19 Jul 2026 20:00:13 +0530 Subject: [PATCH 1/2] fix(server): store null instead of empty string for session deviceType and deviceOS --- server/src/database.ts | 4 ++-- server/src/dtos/session.dto.ts | 8 ++++---- ...SessionDeviceTypeAndOSEmptyStringToNull.ts | 19 +++++++++++++++++++ server/src/schema/tables/session.table.ts | 8 ++++---- 4 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 server/src/schema/migrations/1784471379379-ConvertSessionDeviceTypeAndOSEmptyStringToNull.ts diff --git a/server/src/database.ts b/server/src/database.ts index 1770b9d720..c37a98b094 100644 --- a/server/src/database.ts +++ b/server/src/database.ts @@ -230,8 +230,8 @@ export type Session = { createdAt: Date; updatedAt: Date; expiresAt: Date | null; - deviceOS: string; - deviceType: string; + deviceOS: string | null; + deviceType: string | null; appVersion: string | null; pinExpiresAt: Date | null; isPendingSyncReset: boolean; diff --git a/server/src/dtos/session.dto.ts b/server/src/dtos/session.dto.ts index c81dac6d79..f49ac87bf1 100644 --- a/server/src/dtos/session.dto.ts +++ b/server/src/dtos/session.dto.ts @@ -5,8 +5,8 @@ import z from 'zod'; const SessionCreateSchema = z .object({ duration: z.int().min(1).optional().describe('Session duration in seconds'), - deviceType: z.string().optional().describe('Device type'), - deviceOS: z.string().optional().describe('Device OS'), + deviceType: z.string().nullish().transform((val) => (val === '' ? null : val)).describe('Device type'), + deviceOS: z.string().nullish().transform((val) => (val === '' ? null : val)).describe('Device OS'), }) .meta({ id: 'SessionCreateDto' }); @@ -23,8 +23,8 @@ const SessionResponseSchema = z updatedAt: z.string().describe('Last update date'), expiresAt: z.string().optional().describe('Expiration date'), current: z.boolean().describe('Is current session'), - deviceType: z.string().describe('Device type'), - deviceOS: z.string().describe('Device OS'), + deviceType: z.string().nullable().describe('Device type'), + deviceOS: z.string().nullable().describe('Device OS'), appVersion: z.string().nullable().describe('App version'), isPendingSyncReset: z.boolean().describe('Is pending sync reset'), }) diff --git a/server/src/schema/migrations/1784471379379-ConvertSessionDeviceTypeAndOSEmptyStringToNull.ts b/server/src/schema/migrations/1784471379379-ConvertSessionDeviceTypeAndOSEmptyStringToNull.ts new file mode 100644 index 0000000000..2bfbfd08e0 --- /dev/null +++ b/server/src/schema/migrations/1784471379379-ConvertSessionDeviceTypeAndOSEmptyStringToNull.ts @@ -0,0 +1,19 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await sql`ALTER TABLE "session" ALTER COLUMN "deviceType" DROP NOT NULL;`.execute(db); + await sql`ALTER TABLE "session" ALTER COLUMN "deviceType" SET DEFAULT NULL;`.execute(db); + await sql`UPDATE "session" SET "deviceType" = NULL WHERE "deviceType" = '';`.execute(db); + await sql`ALTER TABLE "session" ALTER COLUMN "deviceOS" DROP NOT NULL;`.execute(db); + await sql`ALTER TABLE "session" ALTER COLUMN "deviceOS" SET DEFAULT NULL;`.execute(db); + await sql`UPDATE "session" SET "deviceOS" = NULL WHERE "deviceOS" = '';`.execute(db); +} + +export async function down(): Promise { + await sql`UPDATE "session" SET "deviceOS" = '' WHERE "deviceOS" IS NULL;`.execute(db); + await sql`ALTER TABLE "session" ALTER COLUMN "deviceOS" SET DEFAULT '';`.execute(db); + await sql`ALTER TABLE "session" ALTER COLUMN "deviceOS" SET NOT NULL;`.execute(db); + await sql`UPDATE "session" SET "deviceType" = '' WHERE "deviceType" IS NULL;`.execute(db); + await sql`ALTER TABLE "session" ALTER COLUMN "deviceType" SET DEFAULT '';`.execute(db); + await sql`ALTER TABLE "session" ALTER COLUMN "deviceType" SET NOT NULL;`.execute(db); +} diff --git a/server/src/schema/tables/session.table.ts b/server/src/schema/tables/session.table.ts index 950c1eeffd..2ea99fb2e0 100644 --- a/server/src/schema/tables/session.table.ts +++ b/server/src/schema/tables/session.table.ts @@ -35,11 +35,11 @@ export class SessionTable { @ForeignKeyColumn(() => SessionTable, { onUpdate: 'CASCADE', onDelete: 'CASCADE', nullable: true }) parentId!: string | null; - @Column({ default: '' }) - deviceType!: Generated; + @Column({ nullable: true, default: null }) + deviceType!: string | null; - @Column({ default: '' }) - deviceOS!: Generated; + @Column({ nullable: true, default: null }) + deviceOS!: string | null; @Column({ nullable: true }) appVersion!: string | null; From 3c2f106f0d508b42d6827848fdeb6d18137fd6ed Mon Sep 17 00:00:00 2001 From: Devesh Kolte Date: Mon, 20 Jul 2026 19:01:11 +0530 Subject: [PATCH 2/2] fix(server): store null instead of empty string for asset_exif description --- ...56820-ConvertExifDescriptionEmptyStringToNull.ts | 13 +++++++++++++ server/src/schema/tables/asset-exif.table.ts | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 server/src/schema/migrations/1784554256820-ConvertExifDescriptionEmptyStringToNull.ts diff --git a/server/src/schema/migrations/1784554256820-ConvertExifDescriptionEmptyStringToNull.ts b/server/src/schema/migrations/1784554256820-ConvertExifDescriptionEmptyStringToNull.ts new file mode 100644 index 0000000000..090e3ac75e --- /dev/null +++ b/server/src/schema/migrations/1784554256820-ConvertExifDescriptionEmptyStringToNull.ts @@ -0,0 +1,13 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await sql`ALTER TABLE "asset_exif" ALTER COLUMN "description" DROP NOT NULL;`.execute(db); + await sql`ALTER TABLE "asset_exif" ALTER COLUMN "description" SET DEFAULT NULL;`.execute(db); + await sql`UPDATE "asset_exif" SET "description" = NULL WHERE "description" = '';`.execute(db); +} + +export async function down(): Promise { + await sql`UPDATE "asset_exif" SET "description" = '' WHERE "description" IS NULL;`.execute(db); + await sql`ALTER TABLE "asset_exif" ALTER COLUMN "description" SET DEFAULT '';`.execute(db); + await sql`ALTER TABLE "asset_exif" ALTER COLUMN "description" SET NOT NULL;`.execute(db); +} diff --git a/server/src/schema/tables/asset-exif.table.ts b/server/src/schema/tables/asset-exif.table.ts index d725189e6d..b2044512dd 100644 --- a/server/src/schema/tables/asset-exif.table.ts +++ b/server/src/schema/tables/asset-exif.table.ts @@ -74,8 +74,8 @@ export class AssetExifTable { @Column({ type: 'character varying', nullable: true }) country!: string | null; - @Column({ type: 'text', default: '' }) - description!: Generated; // or caption + @Column({ type: 'text', nullable: true, default: null }) + description!: string | null; // or caption @Column({ type: 'double precision', nullable: true }) fps!: number | null;