import { index, integer, json, pgTable, serial, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core"; import { user } from "./better.auth.schema"; import { relations } from "drizzle-orm"; import { file } from "./file.schema"; export const mobileDevice = pgTable( "mobile_device", { id: serial("id").primaryKey(), externalDeviceId: text("external_device_id").notNull(), name: text("name").notNull(), manufacturer: text("manufacturer").notNull(), model: text("model").notNull(), androidVersion: text("android_version").notNull(), ownerUserId: text("owner_user_id") .notNull() .references(() => user.id, { onDelete: "cascade" }), lastPingAt: timestamp("last_ping_at"), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), }, (table) => ({ externalDeviceUniqueIdx: uniqueIndex( "mobile_device_external_device_id_uq", ).on(table.externalDeviceId), ownerUserIdx: index("mobile_device_owner_user_id_idx").on( table.ownerUserId, ), lastPingIdx: index("mobile_device_last_ping_at_idx").on( table.lastPingAt, ), }), ); export const mobileSMS = pgTable( "mobile_sms", { id: serial("id").primaryKey(), deviceId: integer("device_id") .notNull() .references(() => mobileDevice.id, { onDelete: "cascade" }), externalMessageId: text("external_message_id"), sender: text("sender").notNull(), recipient: text("recipient"), body: text("body").notNull(), sentAt: timestamp("sent_at").notNull(), receivedAt: timestamp("received_at"), dedupHash: text("dedup_hash").notNull(), rawPayload: json("raw_payload").$type>(), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), }, (table) => ({ deviceSentIdx: index("mobile_sms_device_sent_at_idx").on( table.deviceId, table.sentAt, ), dedupHashUniqueIdx: uniqueIndex("mobile_sms_device_dedup_hash_uq").on( table.deviceId, table.dedupHash, ), externalMessageUniqueIdx: uniqueIndex( "mobile_sms_device_external_msg_uq", ).on(table.deviceId, table.externalMessageId), }), ); export const mobileMediaAsset = pgTable( "mobile_media_asset", { id: serial("id").primaryKey(), deviceId: integer("device_id") .notNull() .references(() => mobileDevice.id, { onDelete: "cascade" }), externalMediaId: text("external_media_id"), fileId: text("file_id") .notNull() .references(() => file.id, { onDelete: "cascade" }), mimeType: text("mime_type").notNull(), filename: text("filename"), capturedAt: timestamp("captured_at"), sizeBytes: integer("size_bytes"), hash: text("hash"), metadata: json("metadata").$type>(), createdAt: timestamp("created_at").notNull(), updatedAt: timestamp("updated_at").notNull(), }, (table) => ({ deviceCreatedIdx: index("mobile_media_asset_device_created_at_idx").on( table.deviceId, table.createdAt, ), externalMediaUniqueIdx: uniqueIndex( "mobile_media_asset_device_external_media_uq", ).on(table.deviceId, table.externalMediaId), fileUniqueIdx: uniqueIndex("mobile_media_asset_file_id_uq").on( table.fileId, ), }), ); export const mobileDeviceRelations = relations( mobileDevice, ({ one, many }) => ({ owner: one(user, { fields: [mobileDevice.ownerUserId], references: [user.id], }), sms: many(mobileSMS), mediaAssets: many(mobileMediaAsset), }), ); export const mobileSMSRelations = relations(mobileSMS, ({ one }) => ({ device: one(mobileDevice, { fields: [mobileSMS.deviceId], references: [mobileDevice.id], }), })); export const mobileMediaAssetRelations = relations( mobileMediaAsset, ({ one }) => ({ device: one(mobileDevice, { fields: [mobileMediaAsset.deviceId], references: [mobileDevice.id], }), file: one(file, { fields: [mobileMediaAsset.fileId], references: [file.id], }), }), );