@dataql/react-native
Version:
DataQL React Native SDK with offline-first capabilities and clean API
89 lines (82 loc) • 3.58 kB
text/typescript
import { sql } from "drizzle-orm";
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
// Table for tracking offline operations
export const offlineOperations = sqliteTable("offline_operations", {
id: text("id").primaryKey(),
type: text("type", {
enum: ["create", "update", "upsert", "delete"],
}).notNull(),
tableName: text("table_name").notNull(),
data: text("data", { mode: "json" }).notNull(), // JSON serialized data
timestamp: integer("timestamp", { mode: "timestamp" })
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
status: text("status", { enum: ["pending", "syncing", "synced", "failed"] })
.notNull()
.default("pending"),
retryCount: integer("retry_count").notNull().default(0),
error: text("error"),
serverId: text("server_id"), // ID from server after sync
});
// Table for sync metadata
export const syncMetadata = sqliteTable("sync_metadata", {
id: text("id").primaryKey(),
tableName: text("table_name").notNull(),
lastSyncTime: integer("last_sync_time", { mode: "timestamp" }),
lastServerTimestamp: integer("last_server_timestamp", { mode: "timestamp" }),
syncVersion: integer("sync_version").notNull().default(1),
});
// Generic data table for storing cached data
export const cachedData = sqliteTable("cached_data", {
id: text("id").primaryKey(),
tableName: text("table_name").notNull(),
itemId: text("item_id").notNull(),
data: text("data", { mode: "json" }).notNull(),
createdAt: integer("created_at", { mode: "timestamp" })
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
updatedAt: integer("updated_at", { mode: "timestamp" })
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
serverUpdatedAt: integer("server_updated_at", { mode: "timestamp" }),
isDeleted: integer("is_deleted", { mode: "boolean" })
.notNull()
.default(false),
});
// Table for storing sync conflicts
export const syncConflicts = sqliteTable("sync_conflicts", {
id: text("id").primaryKey(),
tableName: text("table_name").notNull(),
itemId: text("item_id").notNull(),
localData: text("local_data", { mode: "json" }).notNull(),
serverData: text("server_data", { mode: "json" }).notNull(),
conflictType: text("conflict_type", {
enum: ["update_update", "update_delete", "delete_update"],
}).notNull(),
createdAt: integer("created_at", { mode: "timestamp" })
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
resolved: integer("resolved", { mode: "boolean" }).notNull().default(false),
resolution: text("resolution", { enum: ["local", "server", "merge"] }),
});
// Application settings table
export const appSettings = sqliteTable("app_settings", {
key: text("key").primaryKey(),
value: text("value"),
type: text("type", { enum: ["string", "number", "boolean", "json"] })
.notNull()
.default("string"),
updatedAt: integer("updated_at", { mode: "timestamp" })
.notNull()
.default(sql`CURRENT_TIMESTAMP`),
});
export type OfflineOperation = typeof offlineOperations.$inferSelect;
export type NewOfflineOperation = typeof offlineOperations.$inferInsert;
export type SyncMetadata = typeof syncMetadata.$inferSelect;
export type NewSyncMetadata = typeof syncMetadata.$inferInsert;
export type CachedData = typeof cachedData.$inferSelect;
export type NewCachedData = typeof cachedData.$inferInsert;
export type SyncConflict = typeof syncConflicts.$inferSelect;
export type NewSyncConflict = typeof syncConflicts.$inferInsert;
export type AppSetting = typeof appSettings.$inferSelect;
export type NewAppSetting = typeof appSettings.$inferInsert;