@earth-app/collegedb 1.0.1
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/LICENSE +21 -0
- package/README.md +518 -0
- package/dist/durable.d.ts +241 -0
- package/dist/durable.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +14 -0
- package/dist/kvmap.d.ts +255 -0
- package/dist/kvmap.d.ts.map +1 -0
- package/dist/migrations.d.ts +392 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/router.d.ts +509 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/types.d.ts +107 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +50 -0
package/dist/kvmap.d.ts
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview KV-based shard mapping implementation for CollegeDB
|
|
3
|
+
*
|
|
4
|
+
* This module provides the KVShardMapper class that uses Cloudflare KV storage
|
|
5
|
+
* to maintain mappings between primary keys and their assigned D1 database shards.
|
|
6
|
+
* It handles the persistence and retrieval of shard assignments, enabling the
|
|
7
|
+
* database router to consistently route queries to the correct shard.
|
|
8
|
+
*
|
|
9
|
+
* Key features:
|
|
10
|
+
* - Primary key to shard mapping storage and retrieval
|
|
11
|
+
* - Shard discovery and management
|
|
12
|
+
* - Key counting and statistics for load balancing
|
|
13
|
+
* - Batch operations for efficient KV usage
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const mapper = new KVShardMapper(env.KV);
|
|
18
|
+
*
|
|
19
|
+
* // Set a mapping
|
|
20
|
+
* await mapper.setShardMapping('user-123', 'db-east');
|
|
21
|
+
*
|
|
22
|
+
* // Get a mapping
|
|
23
|
+
* const mapping = await mapper.getShardMapping('user-123');
|
|
24
|
+
* console.log(mapping?.shard); // 'db-east'
|
|
25
|
+
*
|
|
26
|
+
* // Get statistics
|
|
27
|
+
* const counts = await mapper.getShardKeyCounts();
|
|
28
|
+
* console.log(counts); // { 'db-east': 42, 'db-west': 38 }
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @author Gregory Mitchell
|
|
32
|
+
* @since 1.0.0
|
|
33
|
+
*/
|
|
34
|
+
import type { KVNamespace } from '@cloudflare/workers-types';
|
|
35
|
+
import type { ShardMapping } from './types.js';
|
|
36
|
+
/**
|
|
37
|
+
* The KVShardMapper class provides a persistent storage layer for mapping
|
|
38
|
+
* primary keys to their assigned D1 database shards. It uses Cloudflare KV
|
|
39
|
+
* for global, eventually consistent storage with low latency reads.
|
|
40
|
+
*
|
|
41
|
+
* Features:
|
|
42
|
+
* - CRUD operations for shard mappings
|
|
43
|
+
* - Atomic updates with timestamp tracking
|
|
44
|
+
* - Efficient bulk operations and statistics
|
|
45
|
+
* - Prefix-based key organization for performance
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const mapper = new KVShardMapper(env.KV);
|
|
50
|
+
*
|
|
51
|
+
* // Create a new mapping
|
|
52
|
+
* await mapper.setShardMapping('order-456', 'db-central');
|
|
53
|
+
*
|
|
54
|
+
* // Update an existing mapping
|
|
55
|
+
* await mapper.updateShardMapping('order-456', 'db-west');
|
|
56
|
+
*
|
|
57
|
+
* // Query mapping
|
|
58
|
+
* const mapping = await mapper.getShardMapping('order-456');
|
|
59
|
+
* if (mapping) {
|
|
60
|
+
* console.log(`Order 456 is on ${mapping.shard}`);
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare class KVShardMapper {
|
|
65
|
+
private kv;
|
|
66
|
+
/**
|
|
67
|
+
* Cloudflare KV namespace for storing mappings
|
|
68
|
+
* @readonly
|
|
69
|
+
*/
|
|
70
|
+
constructor(kv: KVNamespace);
|
|
71
|
+
/**
|
|
72
|
+
* Retrieves the shard assignment for a given primary key from KV storage.
|
|
73
|
+
* Returns null if no mapping exists, indicating the key has not been
|
|
74
|
+
* assigned to any shard yet.
|
|
75
|
+
* @param primaryKey - The primary key to look up
|
|
76
|
+
* @returns Promise resolving to the shard mapping or null if not found
|
|
77
|
+
* @throws {Error} If KV read operation fails
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const mapping = await mapper.getShardMapping('user-789');
|
|
81
|
+
* if (mapping) {
|
|
82
|
+
* console.log(`User 789 is on shard: ${mapping.shard}`);
|
|
83
|
+
* console.log(`Created: ${new Date(mapping.createdAt)}`);
|
|
84
|
+
* } else {
|
|
85
|
+
* console.log('User 789 not yet assigned to any shard');
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
getShardMapping(primaryKey: string): Promise<ShardMapping | null>;
|
|
90
|
+
/**
|
|
91
|
+
* Creates a new shard assignment for a primary key. This is typically used
|
|
92
|
+
* when a new primary key is first encountered and needs to be assigned to
|
|
93
|
+
* a shard. Sets both created and updated timestamps to the current time.
|
|
94
|
+
*
|
|
95
|
+
* **Note**: This will overwrite any existing mapping for the same key.
|
|
96
|
+
* Use updateShardMapping() if you want to preserve creation timestamp.
|
|
97
|
+
* @param primaryKey - The primary key to map
|
|
98
|
+
* @param shard - The shard binding name to assign
|
|
99
|
+
* @returns Promise that resolves when the mapping is stored
|
|
100
|
+
* @throws {Error} If KV write operation fails
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* // Assign a new user to the west coast shard
|
|
104
|
+
* await mapper.setShardMapping('user-california-123', 'db-west');
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
setShardMapping(primaryKey: string, shard: string): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Changes the shard assignment for a primary key that already has a mapping.
|
|
110
|
+
* Preserves the original creation timestamp while updating the modified
|
|
111
|
+
* timestamp. Throws an error if no existing mapping is found.
|
|
112
|
+
*
|
|
113
|
+
* This is typically used during shard rebalancing or data migration operations.
|
|
114
|
+
* @param primaryKey - The primary key to update
|
|
115
|
+
* @param newShard - The new shard binding name to assign
|
|
116
|
+
* @returns Promise that resolves when the mapping is updated
|
|
117
|
+
* @throws {Error} If no existing mapping found or KV operation fails
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* try {
|
|
121
|
+
* // Move user to a different shard for rebalancing
|
|
122
|
+
* await mapper.updateShardMapping('user-456', 'db-central');
|
|
123
|
+
* console.log('User successfully moved to central shard');
|
|
124
|
+
* } catch (error) {
|
|
125
|
+
* console.error('Failed to update mapping:', error.message);
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
updateShardMapping(primaryKey: string, newShard: string): Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Completely removes the shard assignment for a primary key from KV storage.
|
|
132
|
+
* This is typically used when data is being permanently deleted or when
|
|
133
|
+
* cleaning up orphaned mappings.
|
|
134
|
+
*
|
|
135
|
+
* **WARNING**: After deletion, the primary key will be treated as new
|
|
136
|
+
* and may be assigned to a different shard on next access.
|
|
137
|
+
*
|
|
138
|
+
* @param primaryKey - The primary key mapping to remove
|
|
139
|
+
* @returns Promise that resolves when the mapping is deleted
|
|
140
|
+
* @throws {Error} If KV delete operation fails
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* // Remove mapping for deleted user
|
|
144
|
+
* await mapper.deleteShardMapping('user-deleted-789');
|
|
145
|
+
* console.log('Mapping removed for deleted user');
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
deleteShardMapping(primaryKey: string): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Retrieves the list of all shard binding names that have been registered
|
|
151
|
+
* with the system. This is maintained separately from the individual mappings
|
|
152
|
+
* for efficient shard discovery.
|
|
153
|
+
*
|
|
154
|
+
* @returns Promise resolving to array of shard binding names
|
|
155
|
+
* @throws {Error} If KV read operation fails
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* const shards = await mapper.getKnownShards();
|
|
159
|
+
* console.log('Available shards:', shards);
|
|
160
|
+
* // Output: ['db-east', 'db-west', 'db-central']
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
getKnownShards(): Promise<string[]>;
|
|
164
|
+
/**
|
|
165
|
+
* Replaces the entire list of known shards with a new list. This is typically
|
|
166
|
+
* used during system initialization or when shards are added/removed in bulk.
|
|
167
|
+
*
|
|
168
|
+
* @param shards - Array of shard binding names to store
|
|
169
|
+
* @returns Promise that resolves when the list is updated
|
|
170
|
+
* @throws {Error} If KV write operation fails
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* // Update shard list after adding new regions
|
|
174
|
+
* await mapper.setKnownShards(['db-east', 'db-west', 'db-central', 'db-asia']);
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
setKnownShards(shards: string[]): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Appends a new shard to the list of known shards if it's not already present.
|
|
180
|
+
* This operation is idempotent - adding the same shard multiple times has no effect.
|
|
181
|
+
*
|
|
182
|
+
* @param shard - The shard binding name to add
|
|
183
|
+
* @returns Promise that resolves when the shard is added
|
|
184
|
+
* @throws {Error} If KV operations fail
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* // Register a new shard when it comes online
|
|
188
|
+
* await mapper.addKnownShard('db-europe');
|
|
189
|
+
* console.log('European shard registered');
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
addKnownShard(shard: string): Promise<void>;
|
|
193
|
+
/**
|
|
194
|
+
* Scans all shard mappings to find primary keys assigned to the specified shard.
|
|
195
|
+
* This operation requires reading all mappings and can be expensive for large
|
|
196
|
+
* datasets. Consider caching results or using getShardKeyCounts() for statistics.
|
|
197
|
+
*
|
|
198
|
+
* @param shard - The shard binding name to search for
|
|
199
|
+
* @returns Promise resolving to array of primary keys assigned to the shard
|
|
200
|
+
* @throws {Error} If KV operations fail
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // Find all users on the east coast shard
|
|
204
|
+
* const eastCoastUsers = await mapper.getKeysForShard('db-east');
|
|
205
|
+
* console.log(`East coast has ${eastCoastUsers.length} users`);
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
getKeysForShard(shard: string): Promise<string[]>;
|
|
209
|
+
/**
|
|
210
|
+
* Scans all shard mappings to count how many primary keys are assigned to
|
|
211
|
+
* each shard. Returns a mapping of shard names to their key counts. This
|
|
212
|
+
* is useful for load balancing and monitoring shard utilization.
|
|
213
|
+
*
|
|
214
|
+
* **Performance Note**: This operation scans all mappings and can be
|
|
215
|
+
* expensive for large datasets. Consider implementing caching for frequently
|
|
216
|
+
* accessed statistics.
|
|
217
|
+
*
|
|
218
|
+
* @returns Promise resolving to object mapping shard names to key counts
|
|
219
|
+
* @throws {Error} If KV operations fail
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* const counts = await mapper.getShardKeyCounts();
|
|
223
|
+
* console.log('Shard utilization:', counts);
|
|
224
|
+
* // Output: { 'db-east': 1247, 'db-west': 982, 'db-central': 1156 }
|
|
225
|
+
*
|
|
226
|
+
* // Find the least loaded shard
|
|
227
|
+
* const leastLoaded = Object.entries(counts)
|
|
228
|
+
* .sort(([,a], [,b]) => a - b)[0][0];
|
|
229
|
+
* console.log('Least loaded shard:', leastLoaded);
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
getShardKeyCounts(): Promise<Record<string, number>>;
|
|
233
|
+
/**
|
|
234
|
+
* Deletes ALL shard mappings from KV storage. This is a destructive operation
|
|
235
|
+
* that removes all primary key assignments. After this operation, all keys
|
|
236
|
+
* will be treated as new and may be assigned to different shards.
|
|
237
|
+
*
|
|
238
|
+
* **DANGER**: This operation is irreversible and will cause data routing
|
|
239
|
+
* issues if used in production. Only use during development, testing, or
|
|
240
|
+
* complete system resets.
|
|
241
|
+
*
|
|
242
|
+
* @returns Promise that resolves when all mappings are deleted
|
|
243
|
+
* @throws {Error} If KV operations fail
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* // Only use in development/testing!
|
|
247
|
+
* if (process.env.NODE_ENV === 'development') {
|
|
248
|
+
* await mapper.clearAllMappings();
|
|
249
|
+
* console.log('All mappings cleared for testing');
|
|
250
|
+
* }
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
clearAllMappings(): Promise<void>;
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=kvmap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kvmap.d.ts","sourceRoot":"","sources":["../src/kvmap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAyB/C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,aAAa;IAKb,OAAO,CAAC,EAAE;IAJtB;;;OAGG;gBACiB,EAAE,EAAE,WAAW;IAEnC;;;;;;;;;;;;;;;;;OAiBG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAMvE;;;;;;;;;;;;;;;;OAgBG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvE;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7E;;;;;;;;;;;;;;;;;OAiBG;IACG,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D;;;;;;;;;;;;;OAaG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAKzC;;;;;;;;;;;;OAYG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrD;;;;;;;;;;;;;OAaG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjD;;;;;;;;;;;;;;OAcG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAcvD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAc1D;;;;;;;;;;;;;;;;;;;OAmBG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;CAKvC"}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Database schema management and data migration utilities for CollegeDB
|
|
3
|
+
*
|
|
4
|
+
* This module provides utilities for managing database schemas across multiple D1 shards
|
|
5
|
+
* and migrating data between shards. It includes default schema definitions, schema
|
|
6
|
+
* validation, and data migration functions that ensure consistency across the distributed
|
|
7
|
+
* database system.
|
|
8
|
+
*
|
|
9
|
+
* Key features:
|
|
10
|
+
* - Default schema creation for typical use cases
|
|
11
|
+
* - Schema validation and existence checking
|
|
12
|
+
* - Data migration between D1 database instances
|
|
13
|
+
* - Batch schema operations across multiple shards
|
|
14
|
+
* - Table discovery and management utilities
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { createSchema, migrateRecord, schemaExists } from './migrations.js';
|
|
19
|
+
*
|
|
20
|
+
* // Create schema on a new shard
|
|
21
|
+
* await createSchema(env.DB_EAST);
|
|
22
|
+
*
|
|
23
|
+
* // Check if schema exists
|
|
24
|
+
* const hasSchema = await schemaExists(env.DB_WEST);
|
|
25
|
+
*
|
|
26
|
+
* // Migrate a user from one shard to another
|
|
27
|
+
* await migrateRecord(env.DB_EAST, env.DB_WEST, 'user-123', 'users');
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @author Gregory Mitchell
|
|
31
|
+
* @since 1.0.0
|
|
32
|
+
*/
|
|
33
|
+
import type { D1Database } from '@cloudflare/workers-types';
|
|
34
|
+
import type { KVShardMapper } from './kvmap.js';
|
|
35
|
+
import type { CollegeDBConfig, ShardingStrategy } from './types.js';
|
|
36
|
+
/**
|
|
37
|
+
* Executes SQL statements to create the default table structure and indexes
|
|
38
|
+
* in the specified D1 database. Supports custom schemas and handles SQL
|
|
39
|
+
* statement parsing with comment filtering.
|
|
40
|
+
*
|
|
41
|
+
* The function:
|
|
42
|
+
* 1. Splits the schema into individual SQL statements
|
|
43
|
+
* 2. Filters out comments and empty statements
|
|
44
|
+
* 3. Executes each statement using prepared statements
|
|
45
|
+
* 4. Provides detailed error reporting on failures
|
|
46
|
+
*
|
|
47
|
+
* @param d1 - The D1 database instance to create schema in
|
|
48
|
+
* @param schema - Schema SQL to use
|
|
49
|
+
* @returns Promise that resolves when all schema statements are executed
|
|
50
|
+
* @throws {Error} If any schema statement fails with detailed error information
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const sql = `
|
|
54
|
+
* CREATE TABLE products (
|
|
55
|
+
* id TEXT PRIMARY KEY,
|
|
56
|
+
* name TEXT NOT NULL,
|
|
57
|
+
* price REAL
|
|
58
|
+
* );
|
|
59
|
+
* `;
|
|
60
|
+
* await createSchema(env.DB_PRODUCTS, sql);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function createSchema(d1: D1Database, schema: string): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Applies the schema to all provided D1 database instances in parallel.
|
|
66
|
+
* This is useful for initializing a complete sharded database system
|
|
67
|
+
* where all shards need the same table structure.
|
|
68
|
+
*
|
|
69
|
+
* The function executes schema creation on all shards concurrently for
|
|
70
|
+
* performance, but provides detailed error reporting that identifies
|
|
71
|
+
* which specific shard failed if any errors occur.
|
|
72
|
+
*
|
|
73
|
+
* @param shards - Record mapping shard names to D1 database instances
|
|
74
|
+
* @param schema - Schema SQL to use
|
|
75
|
+
* @returns Promise that resolves when schema is created on all shards
|
|
76
|
+
* @throws {Error} If schema creation fails on any shard, with shard identification
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const shards = {
|
|
80
|
+
* 'db-east': env.DB_EAST,
|
|
81
|
+
* 'db-west': env.DB_WEST,
|
|
82
|
+
* 'db-central': env.DB_CENTRAL
|
|
83
|
+
* };
|
|
84
|
+
*
|
|
85
|
+
* try {
|
|
86
|
+
* await createSchemaAcrossShards(shards);
|
|
87
|
+
* console.log('Schema created on all shards successfully');
|
|
88
|
+
* } catch (error) {
|
|
89
|
+
* console.error('Schema creation failed:', error.message);
|
|
90
|
+
* // Error will specify which shard failed
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function createSchemaAcrossShards(shards: Record<string, D1Database>, schema: string): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Performs a lightweight check to determine if the expected schema is present
|
|
97
|
+
* in the database.
|
|
98
|
+
*
|
|
99
|
+
* @param d1 - The D1 database instance to check
|
|
100
|
+
* @param table - The name of the table to check
|
|
101
|
+
* @returns Promise resolving to true if schema tables exist, false otherwise
|
|
102
|
+
* @example
|
|
103
|
+
* ```typescript
|
|
104
|
+
* const hasSchema = await schemaExists(env.DB_NEW_SHARD, "users");
|
|
105
|
+
* if (!hasSchema) {
|
|
106
|
+
* console.log('Creating schema on new shard...');
|
|
107
|
+
* await createSchema(env.DB_NEW_SHARD, usersSchema);
|
|
108
|
+
* }
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export declare function schemaExists(d1: D1Database, table: string): Promise<boolean>;
|
|
112
|
+
/**
|
|
113
|
+
* Removes all tables that are part of the default CollegeDB schema from
|
|
114
|
+
* the specified database. This is a destructive operation that cannot be undone.
|
|
115
|
+
*
|
|
116
|
+
* **DANGER**: This operation permanently deletes all data in the affected
|
|
117
|
+
* tables. Only use during development, testing, or complete system resets.
|
|
118
|
+
*
|
|
119
|
+
* @param d1 - The D1 database instance to drop tables from
|
|
120
|
+
* @param tables - The table schemas to drop
|
|
121
|
+
* @returns Promise that resolves when all tables are dropped
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* // Only use in development/testing environments!
|
|
125
|
+
* if (process.env.NODE_ENV === 'development') {
|
|
126
|
+
* await dropSchema(env.DB_TEST);
|
|
127
|
+
* console.log('Test database reset completed');
|
|
128
|
+
* }
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export declare function dropSchema(d1: D1Database, ...tables: string[]): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Queries the SQLite system catalog to retrieve all user-created tables
|
|
134
|
+
* in the database. This is useful for schema inspection, validation,
|
|
135
|
+
* and debugging purposes.
|
|
136
|
+
*
|
|
137
|
+
* @param d1 - The D1 database instance to inspect
|
|
138
|
+
* @returns Promise resolving to array of table names, sorted alphabetically
|
|
139
|
+
* @throws Returns empty array if query fails or database is inaccessible
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* const tables = await listTables(env.DB_EAST);
|
|
143
|
+
* console.log('Available tables:', tables);
|
|
144
|
+
* // Output: ['posts', 'shard_mappings', 'users']
|
|
145
|
+
*
|
|
146
|
+
* // Check for specific table
|
|
147
|
+
* if (tables.includes('users')) {
|
|
148
|
+
* console.log('Users table exists');
|
|
149
|
+
* }
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export declare function listTables(d1: D1Database): Promise<string[]>;
|
|
153
|
+
/**
|
|
154
|
+
* Moves a single record from a source D1 database to a target D1 database.
|
|
155
|
+
* This is typically used during shard rebalancing operations when data needs
|
|
156
|
+
* to be redistributed across shards for load balancing.
|
|
157
|
+
*
|
|
158
|
+
* The migration process:
|
|
159
|
+
* 1. Retrieves the complete record from the source database
|
|
160
|
+
* 2. Ensures the target database has the required schema
|
|
161
|
+
* 3. Inserts the record into the target database (using REPLACE for safety)
|
|
162
|
+
* 4. Deletes the record from the source database
|
|
163
|
+
*
|
|
164
|
+
* The operation is atomic from the perspective of each database, but not
|
|
165
|
+
* across databases. If the operation fails partway through, manual cleanup
|
|
166
|
+
* may be required.
|
|
167
|
+
*
|
|
168
|
+
* @param source - Source D1 database containing the record
|
|
169
|
+
* @param target - Target D1 database to receive the record
|
|
170
|
+
* @param primaryKey - Primary key of the record to migrate
|
|
171
|
+
* @param tableName - Name of the table containing the record
|
|
172
|
+
* @returns Promise that resolves when migration is complete
|
|
173
|
+
* @throws {Error} If source record not found, schema creation fails, or database operations fail
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* // Migrate a user from east to west shard
|
|
177
|
+
* try {
|
|
178
|
+
* await migrateRecord(env.DB_EAST, env.DB_WEST, 'user-123', 'users');
|
|
179
|
+
* console.log('User migration completed successfully');
|
|
180
|
+
* } catch (error) {
|
|
181
|
+
* console.error('Migration failed:', error.message);
|
|
182
|
+
* // May need manual cleanup depending on where it failed
|
|
183
|
+
* }
|
|
184
|
+
*
|
|
185
|
+
* // Migrate a post between shards
|
|
186
|
+
* await migrateRecord(source, target, 'post-456', 'posts');
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export declare function migrateRecord(source: D1Database, target: D1Database, primaryKey: string, tableName: string): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Scans an existing table to find all primary keys that need to be mapped to shards.
|
|
192
|
+
* This is useful when integrating CollegeDB with an existing database that already
|
|
193
|
+
* contains data. The function assumes the table has an 'id' column as the primary key.
|
|
194
|
+
*
|
|
195
|
+
* @param d1 - The D1 database instance to scan
|
|
196
|
+
* @param tableName - Name of the table to discover primary keys from
|
|
197
|
+
* @param primaryKeyColumn - Name of the primary key column (defaults to 'id')
|
|
198
|
+
* @returns Promise resolving to array of primary key values
|
|
199
|
+
* @throws {Error} If table doesn't exist or database query fails
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* // Discover all user IDs in an existing users table
|
|
203
|
+
* const userIds = await discoverExistingPrimaryKeys(env.DB_EXISTING, 'users');
|
|
204
|
+
* console.log(`Found ${userIds.length} existing users`);
|
|
205
|
+
*
|
|
206
|
+
* // Discover with custom primary key column
|
|
207
|
+
* const orderIds = await discoverExistingPrimaryKeys(env.DB_ORDERS, 'orders', 'order_id');
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
export declare function discoverExistingPrimaryKeys(d1: D1Database, tableName: string, primaryKeyColumn?: string): Promise<string[]>;
|
|
211
|
+
/**
|
|
212
|
+
* Takes a list of existing primary keys and creates shard mappings for them using
|
|
213
|
+
* the specified allocation strategy. This allows existing data to be integrated
|
|
214
|
+
* into the CollegeDB sharding system without data migration.
|
|
215
|
+
*
|
|
216
|
+
* @param primaryKeys - Array of primary key values to create mappings for
|
|
217
|
+
* @param shardBindings - Array of available shard binding names
|
|
218
|
+
* @param strategy - Allocation strategy to use ('hash', 'round-robin', or 'random')
|
|
219
|
+
* @param mapper - KVShardMapper instance for storing mappings
|
|
220
|
+
* @returns Promise that resolves when all mappings are created
|
|
221
|
+
* @throws {Error} If mapping creation fails
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* import { KVShardMapper } from './kvmap.js';
|
|
225
|
+
*
|
|
226
|
+
* const mapper = new KVShardMapper(env.KV);
|
|
227
|
+
* const existingIds = await discoverExistingPrimaryKeys(env.DB_EXISTING, 'users');
|
|
228
|
+
* const shards = ['db-east', 'db-west', 'db-central'];
|
|
229
|
+
*
|
|
230
|
+
* await createMappingsForExistingKeys(existingIds, shards, 'hash', mapper);
|
|
231
|
+
* console.log('All existing users mapped to shards');
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
export declare function createMappingsForExistingKeys(primaryKeys: string[], shardBindings: string[], strategy: 'hash' | 'round-robin' | 'random', mapper: any): Promise<void>;
|
|
235
|
+
/**
|
|
236
|
+
* Represents the result of validating a table for sharding.
|
|
237
|
+
* Contains information about the table structure, primary key, record count,
|
|
238
|
+
* and any issues encountered during validation.
|
|
239
|
+
*/
|
|
240
|
+
export type ValidationResult = {
|
|
241
|
+
isValid: boolean;
|
|
242
|
+
tableName: string;
|
|
243
|
+
primaryKeyColumn: string;
|
|
244
|
+
recordCount: number;
|
|
245
|
+
issues: string[];
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Checks if a table exists and has a primary key column that can be used
|
|
249
|
+
* for sharding. Returns information about the table structure and primary key.
|
|
250
|
+
*
|
|
251
|
+
* @param d1 - The D1 database instance to check
|
|
252
|
+
* @param tableName - Name of the table to validate
|
|
253
|
+
* @param primaryKeyColumn - Expected primary key column name (defaults to 'id')
|
|
254
|
+
* @returns Promise resolving to validation result with table info
|
|
255
|
+
* @throws {Error} If table doesn't exist or validation fails
|
|
256
|
+
* @example
|
|
257
|
+
* ```typescript
|
|
258
|
+
* const validation = await validateTableForSharding(env.DB_EXISTING, 'users');
|
|
259
|
+
* if (validation.isValid) {
|
|
260
|
+
* console.log(`Table ${validation.tableName} is ready for sharding`);
|
|
261
|
+
* console.log(`Primary key: ${validation.primaryKeyColumn}`);
|
|
262
|
+
* console.log(`Record count: ${validation.recordCount}`);
|
|
263
|
+
* } else {
|
|
264
|
+
* console.error('Table validation failed:', validation.issues);
|
|
265
|
+
* }
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
export declare function validateTableForSharding(d1: D1Database, tableName: string, primaryKeyColumn: string): Promise<ValidationResult>;
|
|
269
|
+
/**
|
|
270
|
+
* Configuration options for integrating an existing database with CollegeDB.
|
|
271
|
+
* Allows customization of which tables to process, primary key column,
|
|
272
|
+
* sharding strategy, and whether to add the shard_mappings table.
|
|
273
|
+
*/
|
|
274
|
+
export type IntegrationOptions = {
|
|
275
|
+
tables?: string[];
|
|
276
|
+
primaryKeyColumn?: string;
|
|
277
|
+
strategy?: ShardingStrategy;
|
|
278
|
+
addShardMappingsTable?: boolean;
|
|
279
|
+
dryRun?: boolean;
|
|
280
|
+
};
|
|
281
|
+
/**
|
|
282
|
+
* Represents the result of integrating an existing database with CollegeDB.
|
|
283
|
+
* Contains information about the success of the integration, shard name,
|
|
284
|
+
* number of tables processed, total records integrated, mappings created,
|
|
285
|
+
* and any issues encountered during the process.
|
|
286
|
+
*/
|
|
287
|
+
export type IntegrationResult = {
|
|
288
|
+
success: boolean;
|
|
289
|
+
shardName: string;
|
|
290
|
+
tablesProcessed: number;
|
|
291
|
+
totalRecords: number;
|
|
292
|
+
mappingsCreated: number;
|
|
293
|
+
issues: string[];
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Performs a complete drop-in integration of an existing database.
|
|
297
|
+
* This is the main function for integrating CollegeDB with an existing database
|
|
298
|
+
* that already contains data. It discovers tables, validates them, creates shard
|
|
299
|
+
* mappings, and optionally adds the shard_mappings table if needed.
|
|
300
|
+
*
|
|
301
|
+
* @param d1 - The existing D1 database to integrate
|
|
302
|
+
* @param shardName - The shard binding name for this database
|
|
303
|
+
* @param mapper - KVShardMapper instance for storing mappings
|
|
304
|
+
* @param options - Configuration options for the integration
|
|
305
|
+
* @returns Promise resolving to integration summary
|
|
306
|
+
* @throws {Error} If integration fails
|
|
307
|
+
* @example
|
|
308
|
+
* ```typescript
|
|
309
|
+
* import { KVShardMapper } from './kvmap.js';
|
|
310
|
+
*
|
|
311
|
+
* const mapper = new KVShardMapper(env.KV);
|
|
312
|
+
* const result = await integrateExistingDatabase(env.DB_EXISTING, 'db-existing', mapper, {
|
|
313
|
+
* tables: ['users', 'posts'],
|
|
314
|
+
* strategy: 'hash',
|
|
315
|
+
* addShardMappingsTable: true
|
|
316
|
+
* });
|
|
317
|
+
*
|
|
318
|
+
* console.log(`Integrated ${result.totalRecords} records from ${result.tablesProcessed} tables`);
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
export declare function integrateExistingDatabase(d1: D1Database, shardName: string, mapper: KVShardMapper, options?: IntegrationOptions): Promise<IntegrationResult>;
|
|
322
|
+
/**
|
|
323
|
+
* Automatically detects if a database needs migration and performs it
|
|
324
|
+
*
|
|
325
|
+
* This function is called automatically by CollegeDB operations to detect
|
|
326
|
+
* existing databases that contain data but haven't been integrated into the
|
|
327
|
+
* sharding system. It performs seamless migration without user intervention.
|
|
328
|
+
*
|
|
329
|
+
* The detection process:
|
|
330
|
+
* 1. Checks if the database has data tables with primary keys
|
|
331
|
+
* 2. Verifies if primary key mappings exist in KV
|
|
332
|
+
* 3. If unmapped data is found, performs automatic integration
|
|
333
|
+
* 4. Caches results to avoid repeated checks
|
|
334
|
+
*
|
|
335
|
+
* @param d1 - The D1 database instance to check and potentially migrate
|
|
336
|
+
* @param shardName - The shard binding name for this database
|
|
337
|
+
* @param config - CollegeDB configuration containing KV and strategy
|
|
338
|
+
* @param options - Optional migration configuration
|
|
339
|
+
* @returns Promise resolving to migration result summary
|
|
340
|
+
* @example
|
|
341
|
+
* ```typescript
|
|
342
|
+
* // Called automatically by CollegeDB operations
|
|
343
|
+
* const result = await autoDetectAndMigrate(env.DB_EXISTING, 'db-existing', config);
|
|
344
|
+
* if (result.migrationPerformed) {
|
|
345
|
+
* console.log(`Auto-migrated ${result.recordsMigrated} records`);
|
|
346
|
+
* }
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
export declare function autoDetectAndMigrate(d1: D1Database, shardName: string, config: CollegeDBConfig, options?: {
|
|
350
|
+
primaryKeyColumn?: string;
|
|
351
|
+
tablesToCheck?: string[];
|
|
352
|
+
skipCache?: boolean;
|
|
353
|
+
maxRecordsToCheck?: number;
|
|
354
|
+
}): Promise<{
|
|
355
|
+
migrationNeeded: boolean;
|
|
356
|
+
migrationPerformed: boolean;
|
|
357
|
+
recordsMigrated: number;
|
|
358
|
+
tablesProcessed: number;
|
|
359
|
+
issues: string[];
|
|
360
|
+
}>;
|
|
361
|
+
/**
|
|
362
|
+
* Performs a lightweight check to determine if a database contains
|
|
363
|
+
* existing data that hasn't been mapped to the sharding system.
|
|
364
|
+
* This is used internally to trigger automatic migration.
|
|
365
|
+
*
|
|
366
|
+
* @param d1 - The D1 database instance to check
|
|
367
|
+
* @param shardName - The shard binding name
|
|
368
|
+
* @param config - CollegeDB configuration
|
|
369
|
+
* @returns Promise resolving to true if migration is needed
|
|
370
|
+
* @example
|
|
371
|
+
* ```typescript
|
|
372
|
+
* const needsMigration = await checkMigrationNeeded(env.DB, 'db-main', config);
|
|
373
|
+
* if (needsMigration) {
|
|
374
|
+
* console.log('Database contains unmapped data');
|
|
375
|
+
* }
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
export declare function checkMigrationNeeded(d1: D1Database, shardName: string, config: CollegeDBConfig): Promise<boolean>;
|
|
379
|
+
/**
|
|
380
|
+
* Clears the migration status cache
|
|
381
|
+
*
|
|
382
|
+
* Resets the internal cache used to track which databases have been
|
|
383
|
+
* checked for migration. Useful for testing or forcing re-checks.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```typescript
|
|
387
|
+
* // Force re-check of all databases
|
|
388
|
+
* clearMigrationCache();
|
|
389
|
+
* ```
|
|
390
|
+
*/
|
|
391
|
+
export declare function clearMigrationCache(): void;
|
|
392
|
+
//# sourceMappingURL=migrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"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"}
|