Drop-in replacement for @prisma/client that runs natively — no Node.js, no Prisma engine, no network overhead. Built for Perry apps targeting macOS, iOS, Linux, Android, and Windows.
Uses sqlx with SQLite under the hood. Same API as perry-prisma (MySQL) and perry-postgres, ~95% identical Rust code.
TypeScript → JSON string → FFI → Rust (sqlx + SQLite) → JSON result → TypeScript
import { PrismaClient } from 'perry-sqlite'; const prisma = new PrismaClient(); await prisma.$connect(); const user = await prisma.user.create({ data: { id: 'u1', email: '[email protected]', passwordHash: 'hash' }, }); const users = await prisma.user.findMany({ where: { email: { contains: '@example.com' } }, orderBy: { email: 'asc' }, take: 10, }); await prisma.$disconnect();
Set DATABASE_URL to a SQLite URL before connecting:
export DATABASE_URL=sqlite:/path/to/app.db| Operation | Notes |
|---|---|
findMany |
where, orderBy, take, skip, select, distinct |
findFirst |
Returns null if not found |
findUnique |
Returns null if not found |
findUniqueOrThrow |
Throws if not found |
create |
Returns created record |
createMany |
skipDuplicates via INSERT OR IGNORE |
update |
Returns updated record |
updateMany |
Returns { count } |
upsert |
Create-or-update |
delete |
Returns deleted record |
deleteMany |
Returns { count } |
count |
Supports where filters |
$transaction |
Serializable via dedicated single-connection pool |
$executeRaw |
Returns affected row count |
$queryRaw |
Returns array of row objects |
// Equality { where: { email: '[email protected]' } } // String operators { where: { email: { contains: 'example', startsWith: 'alice', endsWith: '.com' } } } // Numeric operators { where: { chainId: { gt: 1, lte: 100 } } } // Null checks { where: { lastActiveAt: { isNull: true } } } { where: { lastActiveAt: { isNotNull: true } } } // Set membership { where: { id: { in: ['u1', 'u2'] } } } { where: { id: { notIn: ['u3'] } } } // Logical combinators { where: { AND: [{ email: '[email protected]' }, { passwordHash: 'x' }] } } { where: { OR: [{ email: '[email protected]' }, { email: '[email protected]' }] } } { where: { NOT: { email: '[email protected]' } } }
build.rs reads your Prisma schema at compile time to generate model metadata. Point it at your schema:
# Option 1: env var export PRISMA_SCHEMA_PATH=/path/to/prisma/schema.prisma # Option 2: default location (relative to native/) # ../../chainblick/api/prisma/schema.prisma
Only scalar fields are mapped to columns. Relation fields are tracked as metadata but not queried.
# Type-check the Rust crate cd native && cargo check # Cross-compile for iOS cd native && cargo check --target aarch64-apple-ios # Perry type-check (from package root) perry check
cd tests ./run.sh # or: DATABASE_URL=sqlite:/tmp/test.db ./run.sh
Tests cover all 26 operation categories: CRUD, filters, orderBy, pagination, upsert, transactions, raw SQL, and more (45 assertions total).
perry-sqlite/
├── src/index.ts # PrismaClient, ModelClient, FFI declarations
├── native/
│ ├── src/lib.rs # Query builder, row→JSON conversion, FFI exports
│ ├── build.rs # Prisma schema parser → generated_models.rs
│ └── Cargo.toml
├── tests/
│ ├── test.ts # Integration test suite
│ └── run.sh
└── perry.config.ts # Perry compiler config (targets, FFI)
Query flow:
- TypeScript serializes query args to JSON
- JSON string crosses the FFI boundary to Rust
- Rust parses the query, builds SQL with bound parameters, executes via sqlx
- Result rows are serialized back to JSON
- TypeScript receives the JSON string and parses it
Transactions use a dedicated max_connections(1) SqlitePool per transaction, ensuring BEGIN, all queries, and COMMIT/ROLLBACK run on the same physical connection.
| Behavior | SQLite | MySQL (perry-prisma) |
|---|---|---|
| Identifier quoting | "col" |
`col` |
| Skip duplicates | INSERT OR IGNORE |
INSERT IGNORE |
| Unlimited offset | LIMIT -1 OFFSET n |
LIMIT 18446744073709551615 OFFSET n |
| Last insert ID | last_insert_rowid() |
last_insert_id() |
| Boolean binding | native bool | i8 |
| TLS deps | none | Security.framework / OpenSSL |
MIT