supalite 0.6.1 → 0.7.2
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/.github/workflows/ci.yml +41 -0
- package/CHANGELOG.md +30 -0
- package/README.ko.md +192 -3
- package/README.md +192 -3
- package/SPEC.md +22 -1
- package/bin/supalite +2 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +238 -0
- package/dist/gen-types.d.ts +26 -0
- package/dist/gen-types.js +1574 -0
- package/docs/limitations.ko.md +10 -0
- package/docs/limitations.md +10 -0
- package/package.json +12 -3
- package/scripts/cleanup-gen-types.sql +13 -0
- package/scripts/seed-gen-types.sql +80 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["**"]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
services:
|
|
12
|
+
postgres:
|
|
13
|
+
image: postgres:16
|
|
14
|
+
env:
|
|
15
|
+
POSTGRES_PASSWORD: postgres
|
|
16
|
+
ports:
|
|
17
|
+
- 5432:5432
|
|
18
|
+
options: >-
|
|
19
|
+
--health-cmd="pg_isready -U postgres"
|
|
20
|
+
--health-interval=10s
|
|
21
|
+
--health-timeout=5s
|
|
22
|
+
--health-retries=5
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: "20"
|
|
29
|
+
cache: "npm"
|
|
30
|
+
|
|
31
|
+
- run: npm ci
|
|
32
|
+
- name: Initialize test database
|
|
33
|
+
env:
|
|
34
|
+
PGPASSWORD: postgres
|
|
35
|
+
run: psql -h localhost -U postgres -f setup-postgres-test.sql
|
|
36
|
+
|
|
37
|
+
- run: npm run build
|
|
38
|
+
- run: npm test
|
|
39
|
+
env:
|
|
40
|
+
DB_CONNECTION: postgresql://testuser:testpassword@localhost:5432/testdb
|
|
41
|
+
- run: npm run lint
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.2] - 2026-01-17
|
|
4
|
+
|
|
5
|
+
### ✨ Added
|
|
6
|
+
- `--no-bigint` 옵션을 추가해 BIGINT를 `number`로 출력할 수 있습니다.
|
|
7
|
+
|
|
8
|
+
### 🐞 Fixed
|
|
9
|
+
- `js-yaml` 의존성을 보안 패치 버전으로 업데이트했습니다. (prototype pollution 대응)
|
|
10
|
+
|
|
11
|
+
## [0.7.1] - 2026-01-17
|
|
12
|
+
|
|
13
|
+
### ✨ Added
|
|
14
|
+
- `supalite gen types` 기본 출력이 Supabase CLI 포맷과 최대한 동일하도록 정렬/포맷/헬퍼 타입/Constants를 추가했습니다.
|
|
15
|
+
- `--format supabase|supalite`, `--bigint-type`, `--json-bigint` 옵션을 추가했습니다.
|
|
16
|
+
- Supabase 포맷에서 insertable view에 `Insert`/`Update`를 포함하고, 함수 오버로드 출력 형태를 Supabase와 맞췄습니다.
|
|
17
|
+
|
|
18
|
+
### 🔧 Changed
|
|
19
|
+
- Supabase 포맷 기본값 기준으로 관계/복합 타입/함수 시그니처가 기본 포함됩니다. (legacy 출력은 `--format supalite`)
|
|
20
|
+
|
|
21
|
+
## [0.7.0] - 2026-01-17
|
|
22
|
+
|
|
23
|
+
### ✨ Added
|
|
24
|
+
- `supalite gen types` CLI to generate TypeScript Database types from PostgreSQL schemas.
|
|
25
|
+
- BIGINT columns are emitted as `bigint` in the generated types.
|
|
26
|
+
- `--date-as-date` option to map `date`/`timestamp` columns to `Date` in generated types.
|
|
27
|
+
- `--include-relationships`, `--include-constraints`, `--include-indexes` options to emit schema metadata.
|
|
28
|
+
- `--include-composite-types` and `--include-function-signatures` options for composite types and typed function signatures.
|
|
29
|
+
- `--type-case` and `--function-case` options to control enum/composite and function key casing.
|
|
30
|
+
- `--dump-functions-sql` option to export `CREATE FUNCTION/PROCEDURE` definitions to a local file.
|
|
31
|
+
- Added gen-types seed/cleanup scripts and limitations docs.
|
|
32
|
+
|
|
3
33
|
## [0.6.1] - 2026-01-16
|
|
4
34
|
|
|
5
35
|
### ✨ Added
|
package/README.ko.md
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
# SupaLite
|
|
2
|
+
Supabase가 서버리스 지연으로 느리게 느껴진다면, DB 쿼리에는 SupaLite가 더 빠른 대안이 될 수 있습니다.
|
|
2
3
|
|
|
3
4
|
[](https://www.npmjs.com/package/supalite)
|
|
5
|
+
[](https://www.npmjs.com/package/supalite)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://www.npmjs.com/package/supalite)
|
|
8
|
+
[](https://www.npmjs.com/package/supalite)
|
|
9
|
+
[](https://github.com/genideas-labs/supalite/actions/workflows/ci.yml)
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
Supabase 쿼리 빌더에 집중한 가벼운 PostgreSQL 클라이언트입니다. 익숙한 API를 유지하면서도 표면적을 줄여 더 작은 풋프린트와 낮은 오버헤드를 목표로 합니다.
|
|
12
|
+
|
|
13
|
+
한 줄 요약: **SupaLite는 쿼리 빌더 + RPC + 트랜잭션에 집중한 슬림 Supabase 클라이언트입니다.** Auth/Storage/Realtime까지 필요하면 `supabase-js`를 사용하세요.
|
|
14
|
+
|
|
15
|
+
실서비스 사용: [oqoq.ai](https://oqoq.ai)
|
|
16
|
+
|
|
17
|
+
호환 범위 요약:
|
|
18
|
+
- ✅ 조회/필터/정렬/페이지네이션
|
|
19
|
+
- ✅ PostgREST 임베드 (`related_table(*)`, `!inner`)
|
|
20
|
+
- ✅ Insert/Update/Delete/Upsert (`ignoreDuplicates` 포함)
|
|
21
|
+
- ✅ RPC (`single`/`maybeSingle` 포함)
|
|
22
|
+
- ❌ Auth/Storage/Realtime
|
|
23
|
+
|
|
24
|
+
클라우드 마이그레이션 안내 (GCP/AWS):
|
|
25
|
+
Supabase에서 완전히 분리하려면 SupaLite는 **DB 쿼리 계층만** 대체합니다. Auth/Storage/Realtime은 별도 대안이 필요합니다.
|
|
26
|
+
- Auth: 관리형 인증(AWS Cognito / Google Identity Platform) 또는 자체 호스팅(GoTrue/Keycloak)
|
|
27
|
+
- Storage: 오브젝트 스토리지(S3 / GCS)
|
|
28
|
+
- Realtime: 관리형 pub/sub, WebSocket 서비스, 또는 PostgreSQL LISTEN/NOTIFY + 자체 게이트웨이
|
|
6
29
|
|
|
7
30
|
## 주요 기능
|
|
8
31
|
|
|
@@ -17,6 +40,127 @@
|
|
|
17
40
|
- 🔍 고급 필터링: OR 조건, ILIKE 검색 등 지원
|
|
18
41
|
- 📚 배열 작업: 다중 레코드 삽입 및 배열 데이터 처리 (JSON/JSONB 필드 포함)
|
|
19
42
|
- 🔄 Views, Functions, Enums 지원: Supabase 스타일의 완벽한 타입 지원
|
|
43
|
+
- 🧮 BigInt 대응: JSON 안전 변환 옵션 제공
|
|
44
|
+
|
|
45
|
+
## 프로젝트 범위
|
|
46
|
+
|
|
47
|
+
SupaLite는 Supabase 클라이언트의 **일부 기능(쿼리 빌더, RPC, 트랜잭션)**에 집중합니다. Auth/Storage/Realtime 같은 기능까지 포함하는 전체 호환을 목표로 하지는 않습니다. 지원되는 쿼리 패턴은 아래에 정리되어 있으며, 빠진 패턴이 있으면 이슈로 알려주세요.
|
|
48
|
+
|
|
49
|
+
## 마이그레이션 및 스키마 관리
|
|
50
|
+
|
|
51
|
+
SupaLite는 ORM을 최소화합니다. 마이그레이션/스키마 관리는 전용 도구를 사용하는 것이 현실적입니다.
|
|
52
|
+
- 마이그레이션/스키마 동기화: [pg-schema-sync](https://github.com/genideas-labs/pg-schema-sync)
|
|
53
|
+
- 대안: Atlas, dbmate, Sqitch, Goose, Flyway
|
|
54
|
+
- 타입 생성: `supabase gen types typescript --db-url <postgres_url>` (DB URL만 있어도 가능)
|
|
55
|
+
|
|
56
|
+
ORM 기능(관계 모델링/중첩 쓰기 등)이 꼭 필요하면 Prisma/Drizzle/Kysely를 별도 서비스로 병행하는 방식을 권장합니다. SupaLite를 가볍게 유지하는 것이 핵심 가치입니다.
|
|
57
|
+
|
|
58
|
+
`supabase db pull`에 대해서: 이는 ORM 기능이 아니라 마이그레이션/스키마 동기화 단계입니다. SupaLite 내부에 구현하기보다 “권장 워크플로우”로 문서화하고, 필요하다면 `pg-schema-sync` + 타입 생성기를 묶는 간단한 CLI 래퍼가 현실적입니다.
|
|
59
|
+
|
|
60
|
+
SupaLite는 `supalite gen types`를 포함하며, 기본 출력은 SupaLite 포맷(Supabase CLI 출력의 상위 집합)입니다. Supabase CLI와 1:1로 맞추려면 `--format supabase`를 사용하세요.
|
|
61
|
+
|
|
62
|
+
## SupaLite vs Prisma / Drizzle
|
|
63
|
+
|
|
64
|
+
SupaLite는 SQL에 가까운 가벼운 쿼리 클라이언트입니다. Prisma/Drizzle은 스키마 중심의 ORM과 마이그레이션을 제공합니다.
|
|
65
|
+
|
|
66
|
+
SupaLite가 적합한 경우:
|
|
67
|
+
- 최소한의 추상화로 쿼리 레이어만 얇게 두고 싶을 때
|
|
68
|
+
- Supabase에서 이동하면서 유사한 쿼리 문법을 유지하고 싶을 때
|
|
69
|
+
- 마이그레이션과 스키마 관리는 별도로 하고 있을 때
|
|
70
|
+
|
|
71
|
+
Prisma/Drizzle이 적합한 경우:
|
|
72
|
+
- 스키마 중심 모델링과 내장 마이그레이션이 필요할 때
|
|
73
|
+
- 관계/중첩 쓰기 등 ORM 기능을 적극 활용할 때
|
|
74
|
+
- 스키마 파일 기반의 강한 타입 보장을 원할 때
|
|
75
|
+
|
|
76
|
+
트레이드오프:
|
|
77
|
+
- SupaLite는 간단하고 SQL에 가깝지만 ORM 모델링/마이그레이션 도구는 없습니다.
|
|
78
|
+
- Prisma/Drizzle은 기능이 풍부한 대신 추상화 레이어가 추가됩니다.
|
|
79
|
+
- SupaLite는 BIGINT를 JSON 안전하게 변환하는 옵션을 기본 제공한다는 점이 장점입니다.
|
|
80
|
+
- Prisma/Drizzle은 BIGINT의 JSON 직렬화/정밀도 선택을 호출부에서 처리해야 하는 경우가 많지만, SupaLite는 `bigintTransform`으로 일관되게 설정할 수 있습니다.
|
|
81
|
+
|
|
82
|
+
## 예제 비교 (SupaLite vs Prisma vs Drizzle)
|
|
83
|
+
|
|
84
|
+
SupaLite는 Supabase 스타일 네이밍을 유지해 SQL과 유사하게 읽히도록 설계했습니다. 아래는 동일 쿼리의 비교입니다.
|
|
85
|
+
|
|
86
|
+
작업: `status = 'active'` 사용자 조회, `created_at` 내림차순, 2페이지(페이지당 10건).
|
|
87
|
+
|
|
88
|
+
SupaLite:
|
|
89
|
+
```typescript
|
|
90
|
+
const page = 2;
|
|
91
|
+
const pageSize = 10;
|
|
92
|
+
const { data } = await client
|
|
93
|
+
.from('users')
|
|
94
|
+
.select('id, name, email, created_at')
|
|
95
|
+
.eq('status', 'active')
|
|
96
|
+
.order('created_at', { ascending: false })
|
|
97
|
+
.limit(pageSize)
|
|
98
|
+
.offset((page - 1) * pageSize);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Prisma:
|
|
102
|
+
```typescript
|
|
103
|
+
const page = 2;
|
|
104
|
+
const pageSize = 10;
|
|
105
|
+
const data = await prisma.user.findMany({
|
|
106
|
+
select: { id: true, name: true, email: true, created_at: true },
|
|
107
|
+
where: { status: 'active' },
|
|
108
|
+
orderBy: { created_at: 'desc' },
|
|
109
|
+
take: pageSize,
|
|
110
|
+
skip: (page - 1) * pageSize,
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Drizzle:
|
|
115
|
+
```typescript
|
|
116
|
+
const page = 2;
|
|
117
|
+
const pageSize = 10;
|
|
118
|
+
const data = await db
|
|
119
|
+
.select({ id: users.id, name: users.name, email: users.email, created_at: users.createdAt })
|
|
120
|
+
.from(users)
|
|
121
|
+
.where(eq(users.status, 'active'))
|
|
122
|
+
.orderBy(desc(users.createdAt))
|
|
123
|
+
.limit(pageSize)
|
|
124
|
+
.offset((page - 1) * pageSize);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 로드맵 (단기)
|
|
128
|
+
|
|
129
|
+
- Node/pg 버전별 CI 매트릭스와 통합 테스트
|
|
130
|
+
- 벤치마크 및 성능 가이드
|
|
131
|
+
- Auth/Storage/Realtime 마이그레이션 가이드 (Cognito/GIP, S3/GCS, Realtime 대안)
|
|
132
|
+
- `supalite gen types` (SupaLite 중심 타입 생성기, Supabase 포맷 옵션 제공)
|
|
133
|
+
- 기여 가이드/이슈 템플릿
|
|
134
|
+
|
|
135
|
+
## 성능 노트 (서버리스 Supabase vs 클라우드 Postgres)
|
|
136
|
+
|
|
137
|
+
서버리스 Supabase에서 GCP/AWS의 관리형 Postgres로 이동할 때 일반적으로 기대할 수 있는 차이:
|
|
138
|
+
- 네트워크 hop: Supabase는 edge/API/REST 계층이 추가될 수 있고, 동일 VPC 내 직접 접속은 hop이 줄어듭니다.
|
|
139
|
+
- 콜드스타트/풀링: 서버리스는 cold start나 aggressive pooling이 있을 수 있어, 전용 풀러(pgBouncer/RDS Proxy)가 tail latency를 낮춥니다.
|
|
140
|
+
- 네트워크 경로: 공용망 vs VPC/피어링에 따라 jitter와 p95/p99가 달라집니다.
|
|
141
|
+
- 오버헤드: HTTP/PostgREST 계층 직렬화 비용이 추가되며, 직접 SQL 클라이언트는 이를 줄입니다.
|
|
142
|
+
|
|
143
|
+
벤치마크 수치: **TBD (출처 필요)**. 공개된 벤치마크 링크가 있으면 PR로 공유해 주세요.
|
|
144
|
+
필요한 출처:
|
|
145
|
+
- 서버리스 Postgres vs 관리형 Postgres 지연/풀링 비교에 대한 공개 자료 링크
|
|
146
|
+
|
|
147
|
+
## 벤치마크 방법론 (초안)
|
|
148
|
+
|
|
149
|
+
- 워크로드: 단순 `select`, 필터+정렬 `select`, `insert`, `rpc`
|
|
150
|
+
- warm/cold 구분, p50/p95/p99 측정
|
|
151
|
+
- 동일 리전/인스턴스 크기, DB 버전/풀 설정 기록
|
|
152
|
+
- 가능하면 네트워크/쿼리 시간 분리 측정
|
|
153
|
+
- 스크립트/원본 결과 공개
|
|
154
|
+
|
|
155
|
+
## SupaLite를 선택해야 하는 이유
|
|
156
|
+
|
|
157
|
+
- PostgREST hop 없이 PostgreSQL에 직접 연결해 더 낮은 레이턴시
|
|
158
|
+
- Supabase 스타일의 SQL 유사 API로 마이그레이션이 쉬움
|
|
159
|
+
- native `bigint` 지원 및 변환 옵션 제공
|
|
160
|
+
- Supabase 클라이언트에서 불가능한 트랜잭션/멀티 스텝 플로우 지원
|
|
161
|
+
- 관계/제약/인덱스/함수 시그니처까지 포함 가능한 타입 생성기
|
|
162
|
+
|
|
163
|
+
알려진 트레이드오프는 `docs/limitations.ko.md`를 참고하세요.
|
|
20
164
|
|
|
21
165
|
## 설치 방법
|
|
22
166
|
|
|
@@ -24,13 +168,25 @@
|
|
|
24
168
|
npm install supalite
|
|
25
169
|
```
|
|
26
170
|
|
|
171
|
+
### CLI
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
npm install -g supalite
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
supalite gen types --help
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
전역 설치 없이 `npx supalite ...`로도 사용 가능합니다.
|
|
182
|
+
|
|
27
183
|
## 타입 시스템
|
|
28
184
|
|
|
29
185
|
### 데이터베이스 스키마 정의
|
|
30
186
|
|
|
31
187
|
```typescript
|
|
32
|
-
//
|
|
33
|
-
// 예:
|
|
188
|
+
// SupaLite CLI의 타입 생성기로 생성된 데이터베이스 타입 정의
|
|
189
|
+
// 예: npx supalite gen types --db-url "postgresql://user:pass@localhost:5432/db" --out database.types.ts
|
|
34
190
|
import { Database } from './types/database';
|
|
35
191
|
|
|
36
192
|
// 타입이 적용된 클라이언트 생성
|
|
@@ -91,6 +247,35 @@ interface Database {
|
|
|
91
247
|
}
|
|
92
248
|
```
|
|
93
249
|
|
|
250
|
+
### supalite gen types로 타입 생성
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
npx supalite gen types --db-url "postgresql://user:pass@localhost:5432/db" --schema public,analytics --out database.types.ts --date-as-date
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- `--out -`는 stdout으로 출력합니다.
|
|
257
|
+
- 기본 출력은 SupaLite 포맷(= Supabase CLI의 상위 집합)입니다. Supabase CLI와 1:1로 맞추려면 `--format supabase`를 사용하세요.
|
|
258
|
+
- SupaLite 포맷은 `Constraints`/`Indexes`, `Relationships`의 `referencedSchema`, `bigint` + `Json` bigint 지원, setof RPC용 `SetofOptions`를 추가로 포함합니다.
|
|
259
|
+
- BIGINT 컬럼 타입은 `--bigint-type bigint|number|string`로 제어합니다. (기본: supabase=number, supalite=bigint)
|
|
260
|
+
- `--no-bigint`는 `--bigint-type number`의 간편 옵션입니다.
|
|
261
|
+
- `--json-bigint`는 `Json` 타입에 `bigint`를 포함합니다. (기본: supabase=false, supalite=true)
|
|
262
|
+
- `--no-json-bigint`는 `Json` 타입에서 `bigint`를 제외합니다.
|
|
263
|
+
- `--date-as-date`는 `date`/`timestamp` 컬럼을 `Date`로 생성합니다.
|
|
264
|
+
- `--include-relationships`는 FK 메타데이터를 `Relationships`에 포함합니다. (기본: true)
|
|
265
|
+
- `--include-constraints`는 PK/UNIQUE/CHECK/FK 메타데이터를 포함합니다. (기본: supabase=false, supalite=true)
|
|
266
|
+
- `--include-indexes`는 인덱스 메타데이터(이름/유니크/정의)를 포함합니다. (기본: supabase=false, supalite=true)
|
|
267
|
+
- `--include-composite-types`는 `CompositeTypes` 정의를 포함합니다. (기본: true)
|
|
268
|
+
- `--include-function-signatures`는 `Functions.Args/Returns`를 스키마 메타데이터로 매핑합니다. (기본: true)
|
|
269
|
+
- `Functions`에는 감지된 함수명이 기본 포함되며, 시그니처도 기본 포함됩니다.
|
|
270
|
+
- `--type-case`는 enum/composite 타입 키의 케이스를 제어합니다 (`preserve` | `snake` | `camel` | `pascal`)
|
|
271
|
+
- `--function-case`는 함수 키의 케이스를 제어합니다 (`preserve` | `snake` | `camel` | `pascal`)
|
|
272
|
+
- `--dump-functions-sql [path]`는 `pg_get_functiondef` 기반의 `CREATE FUNCTION/PROCEDURE` 정의를 로컬 파일로 저장합니다.
|
|
273
|
+
- 테스트/개발용 스키마를 제외하려면 `--schema public`을 사용하세요.
|
|
274
|
+
- `--db-url`을 생략하면 `DB_CONNECTION`을 사용합니다.
|
|
275
|
+
|
|
276
|
+
로드맵
|
|
277
|
+
- TODO (AI): 스키마 메타데이터 기반 RPC/함수용 트랜잭션 TypeScript 래퍼 자동 생성
|
|
278
|
+
|
|
94
279
|
## 사용 예시
|
|
95
280
|
|
|
96
281
|
### 데이터베이스 연결
|
|
@@ -933,6 +1118,10 @@ npm test
|
|
|
933
1118
|
npm run build
|
|
934
1119
|
```
|
|
935
1120
|
|
|
1121
|
+
## 기여하기
|
|
1122
|
+
|
|
1123
|
+
이슈와 PR을 환영합니다. 큰 변경은 먼저 이슈로 방향을 맞춰 주세요. 테스트는 로컬 Postgres(또는 `DB_CONNECTION`)가 필요하며, 배포 전 `npm run build`, `npm test`, `npm run lint`를 실행합니다.
|
|
1124
|
+
|
|
936
1125
|
## 라이선스
|
|
937
1126
|
|
|
938
1127
|
MIT 라이선스로 배포됩니다. 자세한 내용은 [LICENSE](LICENSE) 파일을 참조하세요.
|
package/README.md
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
# SupaLite
|
|
2
|
+
If Supabase feels slow due to serverless latency, SupaLite can be a faster alternative for database queries.
|
|
2
3
|
[한국어 README](README.ko.md)
|
|
3
4
|
|
|
4
5
|
[](https://www.npmjs.com/package/supalite)
|
|
6
|
+
[](https://www.npmjs.com/package/supalite)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](https://www.npmjs.com/package/supalite)
|
|
9
|
+
[](https://www.npmjs.com/package/supalite)
|
|
10
|
+
[](https://github.com/genideas-labs/supalite/actions/workflows/ci.yml)
|
|
5
11
|
|
|
6
|
-
A lightweight
|
|
12
|
+
A lightweight PostgreSQL client focused on the Supabase query builder. It keeps the familiar API but trims the surface area so you get a smaller footprint and less overhead in production.
|
|
13
|
+
|
|
14
|
+
In one line: **SupaLite is a slim Supabase client for query builder + RPC + transactions.** If you need full Supabase features (auth/storage/realtime), use `supabase-js`.
|
|
15
|
+
|
|
16
|
+
Used in production by [oqoq.ai](https://oqoq.ai).
|
|
17
|
+
|
|
18
|
+
Compatibility at a glance:
|
|
19
|
+
- ✅ Select/filters/order/pagination
|
|
20
|
+
- ✅ PostgREST-style embeds (`related_table(*)`, `!inner`)
|
|
21
|
+
- ✅ Insert/update/delete/upsert (including `ignoreDuplicates`)
|
|
22
|
+
- ✅ RPC (including `single`/`maybeSingle`)
|
|
23
|
+
- ❌ Auth/Storage/Realtime
|
|
24
|
+
|
|
25
|
+
Cloud migration note (GCP/AWS):
|
|
26
|
+
If you are moving off Supabase, SupaLite replaces only the **DB query layer**. You still need alternatives for Auth/Storage/Realtime. Typical choices are:
|
|
27
|
+
- Auth: managed identity (AWS Cognito / Google Identity Platform) or self-hosted (GoTrue/Keycloak)
|
|
28
|
+
- Storage: object storage (S3 / GCS)
|
|
29
|
+
- Realtime: managed pub/sub, WebSocket services, or PostgreSQL LISTEN/NOTIFY + your own gateway
|
|
7
30
|
|
|
8
31
|
## Key Features
|
|
9
32
|
|
|
@@ -18,6 +41,127 @@ A lightweight and efficient PostgreSQL client library. It mirrors the Supabase A
|
|
|
18
41
|
- Advanced filtering: OR conditions, ILIKE, and more
|
|
19
42
|
- Array support: multi-row inserts and array fields (JSON/JSONB included)
|
|
20
43
|
- Views, Functions, Enums: full Supabase-style typing
|
|
44
|
+
- BigInt handling: configurable transforms for JSON-safe values
|
|
45
|
+
|
|
46
|
+
## Project Scope
|
|
47
|
+
|
|
48
|
+
SupaLite targets a focused subset of the Supabase client: query builder, RPC, and transactions. It does not aim for full Supabase feature parity (auth/storage/realtime). The supported query patterns are documented below; if a pattern is missing, please open an issue so we can prioritize it.
|
|
49
|
+
|
|
50
|
+
## Migrations and schema management
|
|
51
|
+
|
|
52
|
+
SupaLite is intentionally ORM-light. For schema management and migrations, use dedicated tools:
|
|
53
|
+
- Migrations/schema sync: [pg-schema-sync](https://github.com/genideas-labs/pg-schema-sync)
|
|
54
|
+
- Alternatives: Atlas, dbmate, Sqitch, Goose, Flyway
|
|
55
|
+
- Type generation: `supabase gen types typescript --db-url <postgres_url>` (works with just a DB URL)
|
|
56
|
+
|
|
57
|
+
ORM features (relations, nested writes, etc.) are best handled by Prisma/Drizzle/Kysely in a separate service when needed. Keeping SupaLite light is part of the value.
|
|
58
|
+
|
|
59
|
+
About `supabase db pull`: it is a schema/migration sync step, not an ORM feature. Rather than implementing it inside SupaLite, we recommend documenting the workflow and optionally providing a lightweight CLI wrapper that combines `pg-schema-sync` + type generation.
|
|
60
|
+
|
|
61
|
+
SupaLite now includes `supalite gen types`, which defaults to the SupaLite format (a superset of Supabase CLI output). Use `--format supabase` for byte-for-byte Supabase CLI output.
|
|
62
|
+
|
|
63
|
+
## SupaLite vs Prisma / Drizzle
|
|
64
|
+
|
|
65
|
+
SupaLite is a lightweight SQL-first client with a Supabase-style query builder. Prisma and Drizzle are ORMs with schema-first workflows and migrations.
|
|
66
|
+
|
|
67
|
+
When SupaLite fits best:
|
|
68
|
+
- You want a thin query layer with minimal abstraction.
|
|
69
|
+
- You are migrating from Supabase and want similar query ergonomics.
|
|
70
|
+
- You handle migrations and schema management separately.
|
|
71
|
+
|
|
72
|
+
When Prisma or Drizzle fits best:
|
|
73
|
+
- You want schema-first modeling and built-in migrations.
|
|
74
|
+
- You want richer ORM features (relations, nested writes, generated client APIs).
|
|
75
|
+
- You want stronger compile-time guarantees tied to a schema file.
|
|
76
|
+
|
|
77
|
+
Trade-offs:
|
|
78
|
+
- SupaLite is simpler and closer to SQL, but does not provide ORM-level modeling or migration tooling.
|
|
79
|
+
- Prisma/Drizzle add features and structure, with some abstraction overhead.
|
|
80
|
+
- SupaLite includes built-in BIGINT transform options for JSON-safe output.
|
|
81
|
+
- Prisma/Drizzle still require manual decisions for BIGINT (JSON serialization vs precision), while SupaLite centralizes it with `bigintTransform`.
|
|
82
|
+
|
|
83
|
+
## Example comparison (SupaLite vs Prisma vs Drizzle)
|
|
84
|
+
|
|
85
|
+
SupaLite keeps Supabase-style naming so the query reads close to SQL. Below is the same query in each tool:
|
|
86
|
+
|
|
87
|
+
Task: fetch active users, ordered by `created_at` desc, page 2 (10 per page).
|
|
88
|
+
|
|
89
|
+
SupaLite:
|
|
90
|
+
```typescript
|
|
91
|
+
const page = 2;
|
|
92
|
+
const pageSize = 10;
|
|
93
|
+
const { data } = await client
|
|
94
|
+
.from('users')
|
|
95
|
+
.select('id, name, email, created_at')
|
|
96
|
+
.eq('status', 'active')
|
|
97
|
+
.order('created_at', { ascending: false })
|
|
98
|
+
.limit(pageSize)
|
|
99
|
+
.offset((page - 1) * pageSize);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Prisma:
|
|
103
|
+
```typescript
|
|
104
|
+
const page = 2;
|
|
105
|
+
const pageSize = 10;
|
|
106
|
+
const data = await prisma.user.findMany({
|
|
107
|
+
select: { id: true, name: true, email: true, created_at: true },
|
|
108
|
+
where: { status: 'active' },
|
|
109
|
+
orderBy: { created_at: 'desc' },
|
|
110
|
+
take: pageSize,
|
|
111
|
+
skip: (page - 1) * pageSize,
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Drizzle:
|
|
116
|
+
```typescript
|
|
117
|
+
const page = 2;
|
|
118
|
+
const pageSize = 10;
|
|
119
|
+
const data = await db
|
|
120
|
+
.select({ id: users.id, name: users.name, email: users.email, created_at: users.createdAt })
|
|
121
|
+
.from(users)
|
|
122
|
+
.where(eq(users.status, 'active'))
|
|
123
|
+
.orderBy(desc(users.createdAt))
|
|
124
|
+
.limit(pageSize)
|
|
125
|
+
.offset((page - 1) * pageSize);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Roadmap (near-term)
|
|
129
|
+
|
|
130
|
+
- CI matrix for Node/pg versions with integration tests
|
|
131
|
+
- Benchmarks and performance guidance
|
|
132
|
+
- Auth/Storage/Realtime migration guidance (Cognito/GIP, S3/GCS, Realtime options)
|
|
133
|
+
- `supalite gen types` (SupaLite-first generator with Supabase-compatible output)
|
|
134
|
+
- Contribution guide and issue templates
|
|
135
|
+
|
|
136
|
+
## Performance notes (serverless Supabase vs cloud Postgres)
|
|
137
|
+
|
|
138
|
+
General differences you can expect when moving off serverless Supabase to a managed Postgres on GCP/AWS:
|
|
139
|
+
- Network hops: Supabase often adds extra hops (edge/API/REST layer) vs direct Postgres access, especially within the same VPC.
|
|
140
|
+
- Cold starts and pooling: serverless tiers can cold-start or aggressively pool; dedicated poolers (pgBouncer/RDS Proxy) reduce tail latency.
|
|
141
|
+
- Network path: public Internet vs private VPC/peering changes jitter and p95/p99 latency.
|
|
142
|
+
- Overhead: HTTP/PostgREST layers add serialization cost; direct SQL clients minimize that overhead.
|
|
143
|
+
|
|
144
|
+
Benchmarks and numbers: **TBD (source needed)**. If you have public benchmarks, please open a PR with sources.
|
|
145
|
+
Sources needed:
|
|
146
|
+
- Links to public benchmarks/blogs/docs comparing serverless Postgres vs managed Postgres latency and pooling.
|
|
147
|
+
|
|
148
|
+
## Benchmark methodology (draft)
|
|
149
|
+
|
|
150
|
+
- Workloads: simple `select`, filtered `select + order`, `insert`, `rpc`.
|
|
151
|
+
- Measure p50/p95/p99 with warm and cold runs.
|
|
152
|
+
- Keep region and instance size identical; record DB version and pool settings.
|
|
153
|
+
- Separate client latency vs query time when possible.
|
|
154
|
+
- Publish scripts and raw results.
|
|
155
|
+
|
|
156
|
+
## Why SupaLite
|
|
157
|
+
|
|
158
|
+
- Direct PostgreSQL connection (no PostgREST hop) for lower latency and fewer moving parts
|
|
159
|
+
- Supabase-style, SQL-like method names for easy migration
|
|
160
|
+
- Native `bigint` support with configurable transforms
|
|
161
|
+
- Transactions and multi-step flows that Supabase client does not support
|
|
162
|
+
- Type generator that can include relationships/constraints/indexes and function signatures
|
|
163
|
+
|
|
164
|
+
See `docs/limitations.md` for known trade-offs.
|
|
21
165
|
|
|
22
166
|
## Installation
|
|
23
167
|
|
|
@@ -25,13 +169,25 @@ A lightweight and efficient PostgreSQL client library. It mirrors the Supabase A
|
|
|
25
169
|
npm install supalite
|
|
26
170
|
```
|
|
27
171
|
|
|
172
|
+
### CLI
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm install -g supalite
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
supalite gen types --help
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
You can also use `npx supalite ...` without a global install.
|
|
183
|
+
|
|
28
184
|
## Type System
|
|
29
185
|
|
|
30
186
|
### Database schema definition
|
|
31
187
|
|
|
32
188
|
```typescript
|
|
33
|
-
// Database types generated by
|
|
34
|
-
// Example:
|
|
189
|
+
// Database types generated by SupaLite CLI
|
|
190
|
+
// Example: npx supalite gen types --db-url "postgresql://user:pass@localhost:5432/db" --out database.types.ts
|
|
35
191
|
import { Database } from './types/database';
|
|
36
192
|
|
|
37
193
|
// Typed client
|
|
@@ -92,6 +248,35 @@ interface Database {
|
|
|
92
248
|
}
|
|
93
249
|
```
|
|
94
250
|
|
|
251
|
+
### Generate types with supalite gen types
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
npx supalite gen types --db-url "postgresql://user:pass@localhost:5432/db" --schema public,analytics --out database.types.ts --date-as-date
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
- `--out -` prints to stdout
|
|
258
|
+
- Default output is SupaLite format (superset of Supabase CLI). Use `--format supabase` for byte-for-byte Supabase CLI output.
|
|
259
|
+
- SupaLite format also includes `Constraints`/`Indexes`, `referencedSchema` in `Relationships`, `bigint` + `Json` bigint support, and `SetofOptions` for setof RPCs.
|
|
260
|
+
- BIGINT type mapping is controlled by `--bigint-type bigint|number|string` (default: supabase=number, supalite=bigint)
|
|
261
|
+
- `--no-bigint` is a shortcut for `--bigint-type number`
|
|
262
|
+
- `--json-bigint` includes `bigint` in the `Json` union (default: supabase=false, supalite=true)
|
|
263
|
+
- `--no-json-bigint` disables bigint in the `Json` union
|
|
264
|
+
- `--date-as-date` maps `date`/`timestamp` columns to `Date`
|
|
265
|
+
- `--include-relationships` emits foreign-key metadata into `Relationships` (default: true)
|
|
266
|
+
- `--include-constraints` emits primary/unique/check/foreign key metadata (default: supabase=false, supalite=true)
|
|
267
|
+
- `--include-indexes` emits index metadata (name, uniqueness, definition) (default: supabase=false, supalite=true)
|
|
268
|
+
- `--include-composite-types` emits `CompositeTypes` definitions (default: true)
|
|
269
|
+
- `--include-function-signatures` maps `Functions.Args/Returns` from schema metadata (default: true)
|
|
270
|
+
- `Functions` always lists detected function names; signatures are included by default
|
|
271
|
+
- `--type-case` controls enum/composite type key casing (`preserve` | `snake` | `camel` | `pascal`)
|
|
272
|
+
- `--function-case` controls function key casing (`preserve` | `snake` | `camel` | `pascal`)
|
|
273
|
+
- `--dump-functions-sql [path]` writes `CREATE FUNCTION/PROCEDURE` definitions (from `pg_get_functiondef`) to a local file
|
|
274
|
+
- Use `--schema public` to exclude test/dev schemas from generated types
|
|
275
|
+
- Uses `DB_CONNECTION` if `--db-url` is omitted
|
|
276
|
+
|
|
277
|
+
Roadmap
|
|
278
|
+
- TODO (AI): generate transactional TypeScript wrappers for RPC/functions from schema metadata
|
|
279
|
+
|
|
95
280
|
## Usage Examples
|
|
96
281
|
|
|
97
282
|
### Database connection
|
|
@@ -926,6 +1111,10 @@ npm test
|
|
|
926
1111
|
npm run build
|
|
927
1112
|
```
|
|
928
1113
|
|
|
1114
|
+
## Contributing
|
|
1115
|
+
|
|
1116
|
+
Issues and PRs are welcome. For larger changes, please open an issue first to align on scope. Tests expect a local Postgres (or `DB_CONNECTION`), and we run `npm run build`, `npm test`, and `npm run lint` before publishing.
|
|
1117
|
+
|
|
929
1118
|
## License
|
|
930
1119
|
|
|
931
1120
|
Released under the MIT License. See [LICENSE](LICENSE).
|
package/SPEC.md
CHANGED
|
@@ -151,7 +151,28 @@ Notes:
|
|
|
151
151
|
- Some tests require a running PostgreSQL with the right schema and `DB_CONNECTION` env var.
|
|
152
152
|
- Raw SQL tests validate exact SQL generation via the private `buildQuery()`.
|
|
153
153
|
|
|
154
|
-
## 11.
|
|
154
|
+
## 11. Type generation CLI
|
|
155
|
+
- `supalite gen types --db-url <postgres_url> [--schema public,analytics] [--out supalite.types.ts]`
|
|
156
|
+
- Reads schema metadata from `information_schema` and `pg_catalog`.
|
|
157
|
+
- Emits `Json` and a `Database` type with `Tables`, `Views`, `Functions`, `Enums`, and `CompositeTypes`.
|
|
158
|
+
- `--format supalite|supabase` (default: supalite).
|
|
159
|
+
- `--format supabase` matches Supabase CLI output (including formatting).
|
|
160
|
+
- SupaLite format is a superset of Supabase: `Constraints`/`Indexes`, `referencedSchema` in `Relationships`, `bigint` defaults, `Json` bigint, and `SetofOptions` for setof RPCs.
|
|
161
|
+
- `BIGINT` maps to `bigint` by default (`--format supabase` defaults to `number`); `--no-bigint` is a shorthand for `--bigint-type number`.
|
|
162
|
+
- `json/jsonb` map to `Json` with optional `bigint` (`--json-bigint` default: supalite=true, supabase=false; disable via `--no-json-bigint`).
|
|
163
|
+
- `--date-as-date` maps `date`/`timestamp` columns to `Date`.
|
|
164
|
+
- `--include-relationships` emits FK metadata in `Relationships`.
|
|
165
|
+
- `--include-constraints` emits PK/UNIQUE/CHECK/FK metadata per table.
|
|
166
|
+
- `--include-indexes` emits index metadata per table.
|
|
167
|
+
- `--include-composite-types` emits `CompositeTypes` definitions.
|
|
168
|
+
- `--include-function-signatures` maps `Functions.Args/Returns` from schema metadata.
|
|
169
|
+
- `--type-case` controls enum/composite type key casing (`preserve` | `snake` | `camel` | `pascal`).
|
|
170
|
+
- `--function-case` controls function key casing (`preserve` | `snake` | `camel` | `pascal`).
|
|
171
|
+
- `--dump-functions-sql [path]` writes `CREATE FUNCTION/PROCEDURE` definitions from `pg_get_functiondef`.
|
|
172
|
+
- Arrays are mapped to `baseType[]` using the underlying element type.
|
|
173
|
+
- Insert types mark nullable/default/identity/generated columns as optional; Update types are always optional.
|
|
174
|
+
|
|
175
|
+
## 12. Non-goals
|
|
155
176
|
- Full Supabase feature parity (auth, storage, realtime).
|
|
156
177
|
- SQL injection-safe raw SQL DSL beyond the query builder.
|
|
157
178
|
- Advanced query planner hints or server-side caching.
|
package/bin/supalite
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|