Skip to content
/ sqlite Public

Perry native package for Prisma ORM — drop-in replacement for @prisma/client using sqlx + SQLite

Notifications You must be signed in to change notification settings

PerryTS/sqlite

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

perry-sqlite

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

Usage

import { PrismaClient } from 'perry-sqlite';

const prisma = new PrismaClient();
await prisma.$connect();

const user = await prisma.user.create({
  data: { id: 'u1', email: 'alice@example.com', 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

Supported operations

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

Where filters

// Equality
{ where: { email: 'alice@example.com' } }

// 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: 'a@b.com' }, { passwordHash: 'x' }] } }
{ where: { OR: [{ email: 'a@b.com' }, { email: 'b@b.com' }] } }
{ where: { NOT: { email: 'alice@example.com' } } }

Schema setup

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.

Build & verify

# 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

Running tests

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).

Architecture

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:

  1. TypeScript serializes query args to JSON
  2. JSON string crosses the FFI boundary to Rust
  3. Rust parses the query, builds SQL with bound parameters, executes via sqlx
  4. Result rows are serialized back to JSON
  5. 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.

SQLite dialect notes

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

License

MIT

About

Perry native package for Prisma ORM — drop-in replacement for @prisma/client using sqlx + SQLite

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors