Skip to content

Commit 558cd52

Browse files
committed
feat: reorganize query functions, update testing
1 parent 0f5d9ec commit 558cd52

11 files changed

Lines changed: 327 additions & 293 deletions

File tree

README.md

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ npm install collegedb
4040
## Basic Usage
4141

4242
```typescript
43-
import { initialize, createSchema, insert, selectByPrimaryKey } from 'collegedb';
43+
import { initialize, createSchema, run, first } from 'collegedb';
4444

4545
// Initialize with your Cloudflare bindings (existing databases work automatically!)
4646
initialize({
@@ -57,17 +57,17 @@ initialize({
5757
await createSchema(env['db-new-shard']);
5858

5959
// Insert data (automatically routed to appropriate shard)
60-
await insert('user-123', 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['user-123', 'Alice Johnson', 'alice@example.com']);
60+
await run('user-123', 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['user-123', 'Alice Johnson', 'alice@example.com']);
6161

6262
// Query data (automatically routed to correct shard, works with existing data!)
63-
const result = await selectByPrimaryKey('existing-user-456', 'SELECT * FROM users WHERE id = ?', ['existing-user-456']);
63+
const result = await first<User>('existing-user-456', 'SELECT * FROM users WHERE id = ?', ['existing-user-456']);
6464

65-
console.log(result.results[0]); // User data from existing database
65+
console.log(result); // User data from existing database
6666
```
6767

68-
## 🔄 Drop-in Replacement for Existing Databases
68+
## Drop-in Replacement for Existing Databases
6969

70-
CollegeDB supports **seamless, automatic integration** with existing D1 databases that already contain data. Simply add your existing databases as shards in the configuration - CollegeDB will automatically detect existing data and create the necessary shard mappings **without requiring any manual migration steps**.
70+
CollegeDB supports **seamless, automatic integration** with existing D1 databases that already contain data. Simply add your existing databases as shards in the configuration. CollegeDB will automatically detect existing data and create the necessary shard mappings **without requiring any manual migration steps**.
7171

7272
### Requirements for Drop-in Replacement
7373

@@ -77,7 +77,7 @@ CollegeDB supports **seamless, automatic integration** with existing D1 database
7777
4. **KV Namespace**: A Cloudflare KV namespace for storing shard mappings
7878

7979
```typescript
80-
import { initialize, selectByPrimaryKey, insert } from 'collegedb';
80+
import { initialize, first, run } from 'collegedb';
8181

8282
// Add your existing databases as shards - that's it!
8383
initialize({
@@ -91,10 +91,10 @@ initialize({
9191
});
9292

9393
// Existing data works immediately! 🎉
94-
const existingUser = await selectByPrimaryKey('user-from-old-db', 'SELECT * FROM users WHERE id = ?', ['user-from-old-db']);
94+
const existingUser = await first('user-from-old-db', 'SELECT * FROM users WHERE id = ?', ['user-from-old-db']);
9595

9696
// New data gets distributed automatically
97-
await insert('new-user-123', 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['new-user-123', 'New User', 'new@example.com']);
97+
await run('new-user-123', 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['new-user-123', 'New User', 'new@example.com']);
9898
```
9999

100100
**That's it!** No migration scripts, no manual mapping creation, no downtime. Your existing data is immediately accessible through CollegeDB's sharding system.
@@ -169,7 +169,7 @@ if (result.success) {
169169
After integration, initialize CollegeDB with your existing databases as shards:
170170

171171
```typescript
172-
import { initialize } from 'collegedb';
172+
import { initialize, first } from 'collegedb';
173173

174174
// Include existing databases as shards
175175
initialize({
@@ -184,15 +184,15 @@ initialize({
184184
});
185185

186186
// Existing data is now automatically routed!
187-
const user = await selectByPrimaryKey('existing-user-123', 'SELECT * FROM users WHERE id = ?', ['existing-user-123']);
187+
const user = await first('existing-user-123', 'SELECT * FROM users WHERE id = ?', ['existing-user-123']);
188188
```
189189

190190
### Complete Drop-in Example
191191

192192
The simplest possible integration - just add your existing databases:
193193

194194
```typescript
195-
import { initialize, selectByPrimaryKey, insert } from 'collegedb';
195+
import { initialize, first, run } from 'collegedb';
196196

197197
export default {
198198
async fetch(request: Request, env: Env): Promise<Response> {
@@ -208,10 +208,11 @@ export default {
208208
});
209209

210210
// Step 2: Use existing data immediately - no migration needed!
211-
const existingUser = await selectByPrimaryKey('user-from-old-db', 'SELECT * FROM users WHERE id = ?', ['user-from-old-db']);
211+
// Supports typed queries, inserts, updates, deletes, etc.
212+
const existingUser = await first<User>('user-from-old-db', 'SELECT * FROM users WHERE id = ?', ['user-from-old-db']);
212213

213214
// Step 3: New data gets distributed automatically
214-
await insert('new-user-123', 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['new-user-123', 'New User', 'new@example.com']);
215+
await run('new-user-123', 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['new-user-123', 'New User', 'new@example.com']);
215216

216217
return new Response(
217218
JSON.stringify({
@@ -313,17 +314,17 @@ for (const [table, pkColumn] of Object.entries(customIntegration)) {
313314

314315
## 📚 API Reference
315316

316-
| Function | Description | Parameters |
317-
| ---------------------------------------- | --------------------------------------- | ----------------------- |
318-
| `initialize(config)` | Initialize CollegeDB with configuration | `CollegeDBConfig` |
319-
| `createSchema(d1)` | Create database schema on a D1 instance | `D1Database` |
320-
| `insert(key, sql, bindings)` | Insert record using primary key routing | `string, string, any[]` |
321-
| `selectByPrimaryKey(key, sql, bindings)` | Select records by primary key | `string, string, any[]` |
322-
| `updateByPrimaryKey(key, sql, bindings)` | Update records by primary key | `string, string, any[]` |
323-
| `deleteByPrimaryKey(key, sql, bindings)` | Delete records by primary key | `string, string, any[]` |
324-
| `reassignShard(key, newShard)` | Move primary key to different shard | `string, string` |
325-
| `listKnownShards()` | Get list of available shards | `void` |
326-
| `getShardStats()` | Get statistics for all shards | `void` |
317+
| Function | Description | Parameters |
318+
| ------------------------------ | -------------------------------------------- | ----------------------- |
319+
| `initialize(config)` | Initialize CollegeDB with configuration | `CollegeDBConfig` |
320+
| `createSchema(d1)` | Create database schema on a D1 instance | `D1Database` |
321+
| `prepare(key, sql)` | Prepare a SQL statement for execution | `string, string` |
322+
| `run(key, sql, bindings)` | Execute a SQL query with primary key routing | `string, string, any[]` |
323+
| `first(key, sql, bindings)` | Execute a SQL query and return first result | `string, string, any[]` |
324+
| `all(key, sql, bindings)` | Execute a SQL query and return all results | `string, string, any[]` |
325+
| `reassignShard(key, newShard)` | Move primary key to different shard | `string, string` |
326+
| `listKnownShards()` | Get list of available shards | `void` |
327+
| `getShardStats()` | Get statistics for all shards | `void` |
327328

328329
### Drop-in Replacement Functions
329330

demos/worker-demo.ts

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,7 @@
4646

4747
import type { ExecutionContext } from '@cloudflare/workers-types';
4848
import { ShardCoordinator } from '../src/durable.js';
49-
import {
50-
createSchemaAcrossShards,
51-
deleteByPrimaryKey,
52-
flush,
53-
getShardStats,
54-
initialize,
55-
insert,
56-
listKnownShards,
57-
reassignShard,
58-
selectByPrimaryKey,
59-
updateByPrimaryKey
60-
} from '../src/index.js';
49+
import { createSchemaAcrossShards, first, flush, getShardStats, initialize, listKnownShards, reassignShard, run } from '../src/index.js';
6150
import type { Env } from '../src/types.js';
6251

6352
// Demo schema for college database
@@ -359,7 +348,7 @@ async function handleCreateUser(request: Request): Promise<Response> {
359348
);
360349
}
361350

362-
await insert(userData.id, 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', [userData.id, userData.name, userData.email || null]);
351+
await run(userData.id, 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', [userData.id, userData.name, userData.email || null]);
363352

364353
return new Response(
365354
JSON.stringify({
@@ -387,9 +376,9 @@ async function handleGetUser(url: URL): Promise<Response> {
387376
);
388377
}
389378

390-
const result = await selectByPrimaryKey(userId, 'SELECT * FROM users WHERE id = ?', [userId]);
379+
const result = await first(userId, 'SELECT * FROM users WHERE id = ?', [userId]);
391380

392-
if (result.results.length === 0) {
381+
if (!result) {
393382
return new Response(
394383
JSON.stringify({
395384
error: 'User not found'
@@ -403,7 +392,7 @@ async function handleGetUser(url: URL): Promise<Response> {
403392

404393
return new Response(
405394
JSON.stringify({
406-
user: result.results[0]
395+
user: result
407396
}),
408397
{
409398
headers: { 'Content-Type': 'application/json' }
@@ -427,9 +416,9 @@ async function handleUpdateUser(request: Request): Promise<Response> {
427416
}
428417

429418
// Check if user exists first
430-
const existing = await selectByPrimaryKey(userData.id, 'SELECT * FROM users WHERE id = ?', [userData.id]);
419+
const existing = await first(userData.id, 'SELECT * FROM users WHERE id = ?', [userData.id]);
431420

432-
if (existing.results.length === 0) {
421+
if (!existing) {
433422
return new Response(
434423
JSON.stringify({
435424
error: 'User not found'
@@ -441,7 +430,7 @@ async function handleUpdateUser(request: Request): Promise<Response> {
441430
);
442431
}
443432

444-
await updateByPrimaryKey(userData.id, 'UPDATE users SET name = COALESCE(?, name), email = COALESCE(?, email) WHERE id = ?', [
433+
await run(userData.id, 'UPDATE users SET name = COALESCE(?, name), email = COALESCE(?, email) WHERE id = ?', [
445434
userData.name,
446435
userData.email,
447436
userData.id
@@ -472,7 +461,7 @@ async function handleDeleteUser(url: URL): Promise<Response> {
472461
);
473462
}
474463

475-
await deleteByPrimaryKey(userId, 'DELETE FROM users WHERE id = ?', [userId]);
464+
await run(userId, 'DELETE FROM users WHERE id = ?', [userId]);
476465

477466
return new Response(
478467
JSON.stringify({

examples/advanced-usage.ts

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,7 @@
3737
* @since 1.0.0
3838
*/
3939

40-
import {
41-
createSchema,
42-
getShardStats,
43-
initialize,
44-
insert,
45-
listKnownShards,
46-
queryOnShard,
47-
reassignShard,
48-
selectByPrimaryKey
49-
} from '../src/index.js';
40+
import { allShard, createSchema, first, getShardStats, initialize, listKnownShards, reassignShard, run } from '../src/index.js';
5041
import type { CollegeDBConfig, Env } from '../src/types.js';
5142

5243
// Example schema for advanced usage scenarios
@@ -185,7 +176,7 @@ async function handleLoadTest(): Promise<Response> {
185176
for (let j = 0; j < batchSize && i + j < userCount; j++) {
186177
const userId = `load-test-user-${i + j}`;
187178
batch.push(
188-
insert(userId, 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', [
179+
run(userId, 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', [
189180
userId,
190181
`Load Test User ${i + j}`,
191182
`user${i + j}@loadtest.com`
@@ -204,7 +195,7 @@ async function handleLoadTest(): Promise<Response> {
204195
for (let i = 0; i < userCount; i += 5) {
205196
// Sample every 5th user
206197
const userId = `load-test-user-${i}`;
207-
readPromises.push(selectByPrimaryKey(userId, 'SELECT * FROM users WHERE id = ?', [userId]));
198+
readPromises.push(first(userId, 'SELECT * FROM users WHERE id = ?', [userId]));
208199
}
209200
await Promise.all(readPromises);
210201
const readTime = Date.now() - readStartTime;
@@ -321,7 +312,7 @@ async function handleCrossShardQuery(config: CollegeDBConfig): Promise<Response>
321312
// Query each shard directly for aggregate operations
322313
for (const [shardName, _] of Object.entries(config.shards)) {
323314
try {
324-
const result = await queryOnShard(shardName, 'SELECT COUNT(*) as user_count FROM users', []);
315+
const result = await allShard(shardName, 'SELECT COUNT(*) as user_count FROM users', []);
325316
results.push({
326317
shard: shardName,
327318
userCount: result.results[0]?.user_count || 0
@@ -336,7 +327,7 @@ async function handleCrossShardQuery(config: CollegeDBConfig): Promise<Response>
336327
}
337328
}
338329

339-
const totalUsers = results.reduce((sum, r) => sum + (r.userCount || 0), 0);
330+
const totalUsers = results.reduce((sum, r) => sum + (typeof r.userCount === 'number' ? r.userCount : 0), 0);
340331

341332
return new Response(
342333
JSON.stringify({
@@ -357,10 +348,10 @@ async function handleErrorRecovery(): Promise<Response> {
357348

358349
// Test 1: Query non-existent user
359350
try {
360-
const result = await selectByPrimaryKey('non-existent-user', 'SELECT * FROM users WHERE id = ?', ['non-existent-user']);
351+
const result = await first('non-existent-user', 'SELECT * FROM users WHERE id = ?', ['non-existent-user']);
361352
tests.push({
362353
test: 'Query non-existent user',
363-
passed: result.results.length === 0,
354+
passed: !result,
364355
details: 'Should return empty results'
365356
});
366357
} catch (error) {
@@ -389,7 +380,7 @@ async function handleErrorRecovery(): Promise<Response> {
389380

390381
// Test 3: Malformed SQL
391382
try {
392-
await selectByPrimaryKey('test-user', 'INVALID SQL STATEMENT', []);
383+
await run('test-user', 'INVALID SQL STATEMENT', []);
393384
tests.push({
394385
test: 'Malformed SQL',
395386
passed: false,
@@ -432,7 +423,7 @@ async function handleDemo(): Promise<Response> {
432423
// Insert users and track which shard they go to
433424
const userPlacements = [];
434425
for (const user of demoUsers) {
435-
await insert(user.id, 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', [user.id, user.name, user.email]);
426+
await run(user.id, 'INSERT INTO users (id, name, email) VALUES (?, ?, ?)', [user.id, user.name, user.email]);
436427

437428
// This would require access to the KV to determine actual shard
438429
userPlacements.push({

examples/automatic-migration.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
* @since 1.0.0
2525
*/
2626

27-
import { getShardStats, initialize, insert, selectByPrimaryKey, updateByPrimaryKey } from '../src/index.js';
27+
import { first, getShardStats, initialize, run } from '../src/index.js';
2828
import type { Env } from '../src/types.js';
2929

3030
export default {
@@ -94,14 +94,14 @@ async function handleAutomaticDemo(env: Env): Promise<Response> {
9494

9595
for (const userId of sampleExistingIds) {
9696
try {
97-
const result = await selectByPrimaryKey(userId, 'SELECT * FROM users WHERE id = ?', [userId]);
97+
const result = await first(userId, 'SELECT * FROM users WHERE id = ?', [userId]);
9898

99-
if (result.results.length > 0) {
99+
if (result) {
100100
results.push({
101101
type: 'existing_data',
102102
userId,
103103
found: true,
104-
data: result.results[0],
104+
data: result,
105105
message: 'Existing data automatically accessible!'
106106
});
107107
} else {
@@ -129,16 +129,16 @@ async function handleAutomaticDemo(env: Env): Promise<Response> {
129129

130130
for (const user of newUsers) {
131131
try {
132-
await insert(user.id, 'INSERT OR REPLACE INTO users (id, name, email) VALUES (?, ?, ?)', [user.id, user.name, user.email]);
132+
await run(user.id, 'INSERT OR REPLACE INTO users (id, name, email) VALUES (?, ?, ?)', [user.id, user.name, user.email]);
133133

134134
// Immediately query it back
135-
const result = await selectByPrimaryKey(user.id, 'SELECT * FROM users WHERE id = ?', [user.id]);
135+
const result = await first(user.id, 'SELECT * FROM users WHERE id = ?', [user.id]);
136136

137137
results.push({
138138
type: 'new_data',
139139
userId: user.id,
140140
action: 'inserted_and_retrieved',
141-
data: result.results[0],
141+
data: result,
142142
message: 'New data automatically distributed and queryable!'
143143
});
144144
} catch (error) {
@@ -152,20 +152,20 @@ async function handleAutomaticDemo(env: Env): Promise<Response> {
152152

153153
// Step 4: Update existing data if any was found
154154
const existingUser = results.find((r) => r.type === 'existing_data' && r.found);
155-
if (existingUser) {
155+
if (existingUser && existingUser.data) {
156156
try {
157-
await updateByPrimaryKey(existingUser.userId, 'UPDATE users SET name = ? WHERE id = ?', [
157+
await run(existingUser.userId, 'UPDATE users SET name = ? WHERE id = ?', [
158158
`${existingUser.data.name} (Updated)`,
159159
existingUser.userId
160160
]);
161161

162-
const updatedResult = await selectByPrimaryKey(existingUser.userId, 'SELECT * FROM users WHERE id = ?', [existingUser.userId]);
162+
const updatedResult = await first(existingUser.userId, 'SELECT * FROM users WHERE id = ?', [existingUser.userId]);
163163

164164
results.push({
165165
type: 'updated_data',
166166
userId: existingUser.userId,
167167
action: 'updated_existing',
168-
data: updatedResult.results[0],
168+
data: updatedResult,
169169
message: 'Existing data successfully updated through sharding!'
170170
});
171171
} catch (error) {

examples/drop-in-replacement.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
*/
2828

2929
import {
30+
all,
3031
discoverExistingPrimaryKeys,
3132
initialize,
3233
integrateExistingDatabase,
3334
listTables,
34-
selectByPrimaryKey,
3535
validateTableForSharding
3636
} from '../src/index.js';
3737
import { KVShardMapper } from '../src/kvmap.js';
@@ -222,7 +222,7 @@ async function handleDemo(env: Env): Promise<Response> {
222222

223223
for (const userId of sampleUserIds) {
224224
try {
225-
const result = await selectByPrimaryKey(userId, 'SELECT * FROM users WHERE id = ?', [userId]);
225+
const result = await all(userId, 'SELECT * FROM users WHERE id = ?', [userId]);
226226

227227
results.push({
228228
userId,

0 commit comments

Comments
 (0)