@shetty4l/core 0.1.34 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/state/collection/decorators.ts +252 -0
- package/src/state/collection/query.ts +259 -0
- package/src/state/collection/types.ts +160 -0
- package/src/state/decorators.ts +4 -1
- package/src/state/index.ts +103 -5
- package/src/state/loader.ts +682 -2
- package/src/state/schema.ts +104 -1
- package/src/state/types.ts +3 -0
package/src/state/schema.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Schema management for SQLite persistence.
|
|
3
3
|
*
|
|
4
|
-
* Handles table creation and additive schema migrations
|
|
4
|
+
* Handles table creation and additive schema migrations for both
|
|
5
|
+
* singleton (@Persisted) and collection (@PersistedCollection) tables.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
import type { Database } from "bun:sqlite";
|
|
9
|
+
import type { CollectionMeta } from "./collection/types";
|
|
8
10
|
import { sqliteType } from "./serialization";
|
|
9
11
|
import type { ClassMeta } from "./types";
|
|
10
12
|
|
|
@@ -67,3 +69,104 @@ export function migrateAdditive(db: Database, meta: ClassMeta): void {
|
|
|
67
69
|
db.exec(`ALTER TABLE ${meta.table} ADD COLUMN updated_at TEXT`);
|
|
68
70
|
}
|
|
69
71
|
}
|
|
72
|
+
|
|
73
|
+
// --------------------------------------------------------------------------
|
|
74
|
+
// Collection schema functions
|
|
75
|
+
// --------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Ensure a collection table exists for the given collection metadata.
|
|
79
|
+
*
|
|
80
|
+
* Creates a table with:
|
|
81
|
+
* - @Id field as PRIMARY KEY
|
|
82
|
+
* - One column per @Field (snake_case names)
|
|
83
|
+
* - `created_at` TEXT for tracking creation time
|
|
84
|
+
* - `updated_at` TEXT for tracking modifications
|
|
85
|
+
*
|
|
86
|
+
* @param db - SQLite database instance
|
|
87
|
+
* @param meta - Collection metadata from @PersistedCollection decorators
|
|
88
|
+
*/
|
|
89
|
+
export function ensureCollectionTable(
|
|
90
|
+
db: Database,
|
|
91
|
+
meta: CollectionMeta,
|
|
92
|
+
): void {
|
|
93
|
+
// Start with primary key column
|
|
94
|
+
const idSqlType = sqliteType(meta.idType);
|
|
95
|
+
const columns: string[] = [`${meta.idColumn} ${idSqlType} PRIMARY KEY`];
|
|
96
|
+
|
|
97
|
+
// Add all field columns
|
|
98
|
+
for (const field of meta.fields.values()) {
|
|
99
|
+
const fieldSqlType = sqliteType(field.type);
|
|
100
|
+
columns.push(`${field.column} ${fieldSqlType}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Add auto-managed timestamp columns
|
|
104
|
+
columns.push("created_at TEXT");
|
|
105
|
+
columns.push("updated_at TEXT");
|
|
106
|
+
|
|
107
|
+
const sql = `CREATE TABLE IF NOT EXISTS ${meta.table} (${columns.join(", ")})`;
|
|
108
|
+
db.exec(sql);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Create indices for a collection table.
|
|
113
|
+
*
|
|
114
|
+
* Creates indices as defined in the collection metadata:
|
|
115
|
+
* - Index name format: {table}_idx_{col1}_{col2}_...
|
|
116
|
+
* - Uses CREATE INDEX IF NOT EXISTS for idempotency
|
|
117
|
+
*
|
|
118
|
+
* @param db - SQLite database instance
|
|
119
|
+
* @param meta - Collection metadata from @PersistedCollection decorators
|
|
120
|
+
*/
|
|
121
|
+
export function ensureIndices(db: Database, meta: CollectionMeta): void {
|
|
122
|
+
for (const index of meta.indices) {
|
|
123
|
+
const indexName = `${meta.table}_idx_${index.columns.join("_")}`;
|
|
124
|
+
const columnList = index.columns.join(", ");
|
|
125
|
+
const sql = `CREATE INDEX IF NOT EXISTS ${indexName} ON ${meta.table} (${columnList})`;
|
|
126
|
+
db.exec(sql);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Perform additive migration for a collection table: add any missing columns.
|
|
132
|
+
*
|
|
133
|
+
* This function:
|
|
134
|
+
* - Reads existing columns via PRAGMA table_info
|
|
135
|
+
* - Adds columns for any @Field not yet in the table
|
|
136
|
+
* - Ensures created_at and updated_at columns exist
|
|
137
|
+
* - Never drops or modifies existing columns
|
|
138
|
+
* - Is idempotent (safe to call multiple times)
|
|
139
|
+
*
|
|
140
|
+
* @param db - SQLite database instance
|
|
141
|
+
* @param meta - Collection metadata from @PersistedCollection decorators
|
|
142
|
+
*/
|
|
143
|
+
export function migrateCollectionAdditive(
|
|
144
|
+
db: Database,
|
|
145
|
+
meta: CollectionMeta,
|
|
146
|
+
): void {
|
|
147
|
+
// Get existing columns
|
|
148
|
+
const info = db.prepare(`PRAGMA table_info(${meta.table})`).all() as {
|
|
149
|
+
name: string;
|
|
150
|
+
}[];
|
|
151
|
+
const existingColumns = new Set(info.map((row) => row.name));
|
|
152
|
+
|
|
153
|
+
// Add missing field columns
|
|
154
|
+
for (const field of meta.fields.values()) {
|
|
155
|
+
if (!existingColumns.has(field.column)) {
|
|
156
|
+
const fieldSqlType = sqliteType(field.type);
|
|
157
|
+
db.exec(
|
|
158
|
+
`ALTER TABLE ${meta.table} ADD COLUMN ${field.column} ${fieldSqlType}`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Ensure created_at exists
|
|
164
|
+
if (!existingColumns.has("created_at")) {
|
|
165
|
+
db.exec(`ALTER TABLE ${meta.table} ADD COLUMN created_at TEXT`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Ensure updated_at exists
|
|
169
|
+
if (!existingColumns.has("updated_at")) {
|
|
170
|
+
db.exec(`ALTER TABLE ${meta.table} ADD COLUMN updated_at TEXT`);
|
|
171
|
+
}
|
|
172
|
+
}
|
package/src/state/types.ts
CHANGED