Skip to content

Commit 0e8ed6d

Browse files
Copilothotlong
andcommitted
docs: add driver-turso README, update CHANGELOG and ROADMAP
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> Agent-Logs-Url: https://github.com/objectstack-ai/spec/sessions/f3d58acb-4d15-42db-a9ef-f318b266842f
1 parent 63eb057 commit 0e8ed6d

3 files changed

Lines changed: 205 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- **`@objectstack/driver-turso` plugin** — Migrated and standardized the Turso/libSQL driver from
12+
`@objectql/driver-turso` into `packages/plugins/driver-turso/`. The driver **extends** `SqlDriver`
13+
from `@objectstack/driver-sql` — all CRUD, schema, filter, aggregation, and introspection logic
14+
is inherited with zero code duplication. Turso-specific features include: three connection modes
15+
(local file, in-memory, embedded replica), `@libsql/client` sync mechanism for embedded replicas,
16+
multi-tenant router with TTL-based driver caching, and enhanced capability flags (FTS5, JSON1,
17+
CTE, savepoints, indexes). Includes 53 unit tests. Factory function `createTursoDriver()` and
18+
plugin manifest for kernel integration.
19+
- **Multi-tenant routing** (`createMultiTenantRouter`) — Database-per-tenant architecture with
20+
automatic driver lifecycle management, tenant ID validation, configurable TTL cache, and
21+
`onTenantCreate`/`onTenantEvict` lifecycle callbacks. Serverless-safe (no global intervals).
22+
23+
### Changed
24+
- **`@objectstack/driver-sql` — Protected extensibility** — Changed `private` to `protected` for
25+
all internal properties and methods (`knex`, `config`, `jsonFields`, `booleanFields`,
26+
`tablesWithTimestamps`, `isSqlite`, `isPostgres`, `isMysql`, `getBuilder`, `applyFilters`,
27+
`applyFilterCondition`, `mapSortField`, `mapAggregateFunc`, `buildWindowFunction`,
28+
`createColumn`, `ensureDatabaseExists`, `createDatabase`, `isJsonField`, `formatInput`,
29+
`formatOutput`, `introspectColumns`, `introspectForeignKeys`, `introspectPrimaryKeys`,
30+
`introspectUniqueConstraints`). Enables clean subclassing for driver variants (Turso, D1, etc.)
31+
without code duplication.
32+
33+
### Fixed
34+
- **`@objectstack/driver-sql``count()` returns NaN for zero results** — Fixed `count()` method
35+
using `||` (logical OR) instead of `??` (nullish coalescing) to read the count value. When the
36+
actual count was `0`, `row.count || row['count(*)']` evaluated to `Number(undefined)` = `NaN`
37+
because `0` is falsy. Now uses `row.count ?? row['count(*)'] ?? 0` for correct zero handling.
38+
1039
### Changed
1140
- **Unified Data Driver Contract (`IDataDriver`)** — Resolved the split between `DriverInterface`
1241
(core, minimal ~13 methods) and `IDataDriver` (spec, comprehensive 28 methods). `IDataDriver`

ROADMAP.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ the ecosystem for enterprise workloads.
4444
| Microkernel (ObjectKernel / LiteKernel) || `@objectstack/core` |
4545
| Data Engine (ObjectQL) || `@objectstack/objectql` |
4646
| In-Memory Driver || `@objectstack/driver-memory` |
47+
| SQL Driver (PostgreSQL, MySQL, SQLite) || `@objectstack/driver-sql` |
48+
| Turso/libSQL Driver (Edge SQLite) || `@objectstack/driver-turso` |
4749
| Metadata Service || `@objectstack/metadata` |
4850
| REST API Server || `@objectstack/rest` |
4951
| Client SDK (TypeScript) || `@objectstack/client` |
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# @objectstack/driver-turso
2+
3+
Turso/libSQL driver for ObjectStack — edge-first SQLite with embedded replicas and database-per-tenant multi-tenancy.
4+
5+
## Architecture
6+
7+
`TursoDriver` **extends** `SqlDriver` from `@objectstack/driver-sql`. All CRUD operations, schema management, filtering, aggregation, window functions, introspection, and transactions are **inherited** — zero duplicated query/schema code.
8+
9+
```
10+
TursoDriver extends SqlDriver (via Knex + better-sqlite3)
11+
├── Inherited: find, findOne, create, update, delete, count, upsert
12+
├── Inherited: bulkCreate, bulkUpdate, bulkDelete, updateMany, deleteMany
13+
├── Inherited: syncSchema, dropTable, introspectSchema
14+
├── Inherited: aggregate, distinct, findWithWindowFunctions
15+
├── Inherited: beginTransaction, commit, rollback
16+
├── Inherited: applyFilters (MongoDB-style + array-style)
17+
├── Override: name, version, supports (Turso-specific capabilities)
18+
├── Override: connect / disconnect (libSQL client lifecycle)
19+
├── Added: sync() — Embedded replica sync via @libsql/client
20+
├── Added: Multi-tenant router with TTL cache
21+
└── Added: TursoDriverConfig (url, authToken, syncUrl, encryptionKey)
22+
```
23+
24+
## Installation
25+
26+
```bash
27+
pnpm add @objectstack/driver-turso
28+
```
29+
30+
## Connection Modes
31+
32+
### Local File (Embedded SQLite)
33+
34+
```typescript
35+
import { TursoDriver } from '@objectstack/driver-turso';
36+
37+
const driver = new TursoDriver({
38+
url: 'file:./data/app.db',
39+
});
40+
await driver.connect();
41+
```
42+
43+
### In-Memory (Testing)
44+
45+
```typescript
46+
const driver = new TursoDriver({
47+
url: ':memory:',
48+
});
49+
await driver.connect();
50+
```
51+
52+
### Embedded Replica (Hybrid)
53+
54+
Local SQLite file + automatic sync from Turso cloud:
55+
56+
```typescript
57+
const driver = new TursoDriver({
58+
url: 'file:./data/replica.db',
59+
syncUrl: 'libsql://my-db-orgname.turso.io',
60+
authToken: process.env.TURSO_AUTH_TOKEN,
61+
sync: {
62+
intervalSeconds: 60, // sync every 60 seconds
63+
onConnect: true, // sync on initial connect
64+
},
65+
});
66+
await driver.connect();
67+
68+
// Manual sync
69+
await driver.sync();
70+
```
71+
72+
## Multi-Tenant Routing
73+
74+
Database-per-tenant architecture with automatic driver caching:
75+
76+
```typescript
77+
import { createMultiTenantRouter } from '@objectstack/driver-turso';
78+
79+
const router = createMultiTenantRouter({
80+
urlTemplate: 'file:./data/{tenant}.db',
81+
clientCacheTTL: 300_000, // 5 minutes
82+
onTenantCreate: async (tenantId) => {
83+
console.log(`Provisioned database for tenant: ${tenantId}`);
84+
},
85+
});
86+
87+
// In a request handler:
88+
const driver = await router.getDriverForTenant('acme');
89+
const users = await driver.find('users', { where: { active: true } });
90+
91+
// Cleanup on shutdown
92+
await router.destroyAll();
93+
```
94+
95+
### Multi-Tenant with Turso Cloud
96+
97+
```typescript
98+
const router = createMultiTenantRouter({
99+
urlTemplate: 'file:./data/{tenant}-replica.db',
100+
groupAuthToken: process.env.TURSO_GROUP_TOKEN,
101+
driverConfigOverrides: {
102+
syncUrl: 'libsql://{tenant}-myorg.turso.io',
103+
sync: { intervalSeconds: 30 },
104+
},
105+
});
106+
```
107+
108+
## Configuration
109+
110+
```typescript
111+
interface TursoDriverConfig {
112+
/** Database URL (file:, :memory:, libsql://, https://) */
113+
url: string;
114+
115+
/** JWT auth token for remote Turso database */
116+
authToken?: string;
117+
118+
/** AES-256 encryption key for local files */
119+
encryptionKey?: string;
120+
121+
/** Maximum concurrent requests. Default: 20 */
122+
concurrency?: number;
123+
124+
/** Remote sync URL for embedded replica mode */
125+
syncUrl?: string;
126+
127+
/** Sync configuration */
128+
sync?: {
129+
intervalSeconds?: number; // Default: 60
130+
onConnect?: boolean; // Default: true
131+
};
132+
133+
/** Operation timeout in milliseconds */
134+
timeout?: number;
135+
}
136+
```
137+
138+
## Capabilities
139+
140+
TursoDriver declares enhanced capabilities beyond the base SqlDriver:
141+
142+
| Capability | SqlDriver | TursoDriver |
143+
|:---|:---:|:---:|
144+
| FTS5 Full-Text Search |||
145+
| JSON1 Query |||
146+
| Common Table Expressions |||
147+
| Savepoints |||
148+
| Indexes |||
149+
| Connection Pooling || ❌ (concurrency limits) |
150+
| Embedded Replica Sync |||
151+
| Multi-Tenant Routing |||
152+
153+
## Plugin Registration
154+
155+
```typescript
156+
import tursoPlugin from '@objectstack/driver-turso';
157+
158+
// Via plugin system
159+
await kernel.enablePlugin(tursoPlugin, {
160+
url: 'file:./data/app.db',
161+
});
162+
```
163+
164+
## Testing
165+
166+
```bash
167+
pnpm test # Run all 53 tests
168+
```
169+
170+
Tests run against in-memory SQLite (`:memory:`) — no external services required.
171+
172+
## License
173+
174+
Apache-2.0 — Copyright (c) 2025 ObjectStack

0 commit comments

Comments
 (0)