supalite 0.7.2 → 0.7.5
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/README.ko.md +24 -1
- package/README.md +23 -0
- package/SPEC.md +2 -1
- package/dist/gen-types.js +36 -13
- package/dist/postgres-client.d.ts +1 -0
- package/dist/postgres-client.js +46 -33
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -21,6 +21,12 @@ Supabase 쿼리 빌더에 집중한 가벼운 PostgreSQL 클라이언트입니
|
|
|
21
21
|
- ✅ RPC (`single`/`maybeSingle` 포함)
|
|
22
22
|
- ❌ Auth/Storage/Realtime
|
|
23
23
|
|
|
24
|
+
## 0.7.2 하이라이트
|
|
25
|
+
|
|
26
|
+
- `supalite gen types --format supabase`가 Supabase CLI 출력과 바이트까지 완전히 일치합니다. (정렬/포맷 포함)
|
|
27
|
+
- 기본값인 `--format supalite`는 Supabase 포맷을 확장한 상위 호환 출력으로, 제약/인덱스, 관계의 `referencedSchema`, SETOF 반환 RPC 옵션을 제공합니다.
|
|
28
|
+
- 타입 생성 BigInt 옵션을 추가했습니다: `--no-bigint`, `--no-json-bigint`.
|
|
29
|
+
|
|
24
30
|
클라우드 마이그레이션 안내 (GCP/AWS):
|
|
25
31
|
Supabase에서 완전히 분리하려면 SupaLite는 **DB 쿼리 계층만** 대체합니다. Auth/Storage/Realtime은 별도 대안이 필요합니다.
|
|
26
32
|
- Auth: 관리형 인증(AWS Cognito / Google Identity Platform) 또는 자체 호스팅(GoTrue/Keycloak)
|
|
@@ -129,6 +135,7 @@ const data = await db
|
|
|
129
135
|
- Node/pg 버전별 CI 매트릭스와 통합 테스트
|
|
130
136
|
- 벤치마크 및 성능 가이드
|
|
131
137
|
- Auth/Storage/Realtime 마이그레이션 가이드 (Cognito/GIP, S3/GCS, Realtime 대안)
|
|
138
|
+
- `pg-schema-sync` 기반 `supalite db pull` 스키마 동기화 래퍼
|
|
132
139
|
- `supalite gen types` (SupaLite 중심 타입 생성기, Supabase 포맷 옵션 제공)
|
|
133
140
|
- 기여 가이드/이슈 템플릿
|
|
134
141
|
|
|
@@ -307,6 +314,21 @@ const client = new SupaliteClient<Database>({
|
|
|
307
314
|
});
|
|
308
315
|
```
|
|
309
316
|
|
|
317
|
+
```typescript
|
|
318
|
+
import { Pool } from 'pg';
|
|
319
|
+
import { SupaLitePG } from 'supalite';
|
|
320
|
+
import { Database } from './types/database';
|
|
321
|
+
|
|
322
|
+
const pool = new Pool({
|
|
323
|
+
connectionString: process.env.DB_CONNECTION || 'postgresql://user:pass@localhost:5432/db',
|
|
324
|
+
max: 5,
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const client = new SupaLitePG<Database>({
|
|
328
|
+
pool,
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
310
332
|
### 기본 CRUD 작업
|
|
311
333
|
|
|
312
334
|
```typescript
|
|
@@ -1031,7 +1053,7 @@ await client.close();
|
|
|
1031
1053
|
### 클라이언트 메소드
|
|
1032
1054
|
|
|
1033
1055
|
- `testConnection()`: 데이터베이스 연결 확인
|
|
1034
|
-
- `close()`: 커넥션 풀 종료
|
|
1056
|
+
- `close()`: 내부 커넥션 풀 종료 (외부 `pool` 사용 시 no-op)
|
|
1035
1057
|
|
|
1036
1058
|
## 환경 변수 설정
|
|
1037
1059
|
|
|
@@ -1051,6 +1073,7 @@ DB_SSL=true
|
|
|
1051
1073
|
|
|
1052
1074
|
`SupaLitePG` 생성자는 다음 옵션을 받을 수 있습니다:
|
|
1053
1075
|
|
|
1076
|
+
- `pool?: Pool`: 외부 `pg` Pool 인스턴스를 사용합니다. 이 경우 다른 연결 옵션은 무시되고, 풀의 생성/종료는 호출자가 관리합니다.
|
|
1054
1077
|
- `connectionString?: string`: PostgreSQL 연결 문자열 (예: `postgresql://user:password@host:port/database`). 제공되면 다른 연결 매개변수보다 우선합니다.
|
|
1055
1078
|
- `user?: string`: 데이터베이스 사용자 이름 (환경 변수: `DB_USER`).
|
|
1056
1079
|
- `host?: string`: 데이터베이스 호스트 (환경 변수: `DB_HOST`).
|
package/README.md
CHANGED
|
@@ -22,6 +22,12 @@ Compatibility at a glance:
|
|
|
22
22
|
- ✅ RPC (including `single`/`maybeSingle`)
|
|
23
23
|
- ❌ Auth/Storage/Realtime
|
|
24
24
|
|
|
25
|
+
## 0.7.2 Highlights
|
|
26
|
+
|
|
27
|
+
- `supalite gen types --format supabase` now matches Supabase CLI output byte-for-byte (ordering + formatting).
|
|
28
|
+
- Default `--format supalite` is a superset with extra schema metadata (constraints/indexes, referenced schema in relationships, set-returning RPC options).
|
|
29
|
+
- New BigInt controls for generated types: `--no-bigint` and `--no-json-bigint`.
|
|
30
|
+
|
|
25
31
|
Cloud migration note (GCP/AWS):
|
|
26
32
|
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
33
|
- Auth: managed identity (AWS Cognito / Google Identity Platform) or self-hosted (GoTrue/Keycloak)
|
|
@@ -130,6 +136,7 @@ const data = await db
|
|
|
130
136
|
- CI matrix for Node/pg versions with integration tests
|
|
131
137
|
- Benchmarks and performance guidance
|
|
132
138
|
- Auth/Storage/Realtime migration guidance (Cognito/GIP, S3/GCS, Realtime options)
|
|
139
|
+
- `supalite db pull` wrapper around `pg-schema-sync` for schema sync
|
|
133
140
|
- `supalite gen types` (SupaLite-first generator with Supabase-compatible output)
|
|
134
141
|
- Contribution guide and issue templates
|
|
135
142
|
|
|
@@ -307,6 +314,21 @@ const client = new SupaliteClient<Database>({
|
|
|
307
314
|
});
|
|
308
315
|
```
|
|
309
316
|
|
|
317
|
+
```typescript
|
|
318
|
+
import { Pool } from 'pg';
|
|
319
|
+
import { SupaLitePG } from 'supalite';
|
|
320
|
+
import { Database } from './types/database';
|
|
321
|
+
|
|
322
|
+
const pool = new Pool({
|
|
323
|
+
connectionString: process.env.DB_CONNECTION || 'postgresql://user:pass@localhost:5432/db',
|
|
324
|
+
max: 5,
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
const client = new SupaLitePG<Database>({
|
|
328
|
+
pool,
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
310
332
|
### Basic CRUD
|
|
311
333
|
|
|
312
334
|
```typescript
|
|
@@ -1047,6 +1069,7 @@ DB_SSL=true
|
|
|
1047
1069
|
|
|
1048
1070
|
### SupaLitePG constructor options
|
|
1049
1071
|
|
|
1072
|
+
- `pool?: Pool`: use an external `pg` Pool instance (other connection options are ignored; pool lifecycle is managed by the caller)
|
|
1050
1073
|
- `connectionString?: string`: connection string (e.g. `postgresql://user:password@host:port/database`)
|
|
1051
1074
|
- `user?: string`: DB user (env: `DB_USER`)
|
|
1052
1075
|
- `host?: string`: DB host (env: `DB_HOST`)
|
package/SPEC.md
CHANGED
|
@@ -13,6 +13,7 @@ SupaLite is a lightweight TypeScript PostgreSQL client that mirrors a subset of
|
|
|
13
13
|
|
|
14
14
|
#### Construction
|
|
15
15
|
- Accepts either `connectionString` or discrete connection params.
|
|
16
|
+
- Optional `pool` lets callers inject an existing `pg` Pool (SupaLite does not create or close the pool).
|
|
16
17
|
- Env vars supported: `DB_CONNECTION`, `DB_USER`, `DB_HOST`, `DB_NAME`, `DB_PASS`, `DB_PORT`, `DB_SSL`.
|
|
17
18
|
- `bigintTransform`: `'bigint' | 'string' | 'number'` controls how BIGINT values are parsed.
|
|
18
19
|
- `verbose`: logs SQL, values, and warnings for risky bigint-to-number conversions.
|
|
@@ -40,7 +41,7 @@ Notes:
|
|
|
40
41
|
|
|
41
42
|
### 2.4 Utilities
|
|
42
43
|
- `testConnection()` to validate connectivity.
|
|
43
|
-
- `close()` to shut down the pool.
|
|
44
|
+
- `close()` to shut down the internal pool (no-op when using an external `pool`).
|
|
44
45
|
|
|
45
46
|
## 3. Result Shapes
|
|
46
47
|
|
package/dist/gen-types.js
CHANGED
|
@@ -590,7 +590,7 @@ const renderIndexesProperty = (indexes, level, style) => {
|
|
|
590
590
|
const items = indexes.map((index) => [
|
|
591
591
|
`name: ${style.quote}${escapeStringLiteral(index.name, style.quote)}${style.quote}`,
|
|
592
592
|
`isUnique: ${index.isUnique ? 'true' : 'false'}`,
|
|
593
|
-
`definition: ${style.quote}${escapeStringLiteral(index.definition, style.quote)}${style.quote}`,
|
|
593
|
+
`definition: ${style.quote}${escapeStringLiteral(index.definition ?? '', style.quote)}${style.quote}`,
|
|
594
594
|
]);
|
|
595
595
|
return renderObjectArrayProperty('Indexes', items, level, style);
|
|
596
596
|
};
|
|
@@ -1405,18 +1405,41 @@ const generateTypes = async (options) => {
|
|
|
1405
1405
|
});
|
|
1406
1406
|
}
|
|
1407
1407
|
if (includeIndexes) {
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1408
|
+
let indexRows = [];
|
|
1409
|
+
try {
|
|
1410
|
+
const { rows } = await client.query(`SELECT n.nspname AS schema,
|
|
1411
|
+
t.relname AS table,
|
|
1412
|
+
i.relname AS name,
|
|
1413
|
+
ix.indisunique AS "isUnique",
|
|
1414
|
+
pg_get_indexdef(ix.indexrelid) AS definition
|
|
1415
|
+
FROM pg_class t
|
|
1416
|
+
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
1417
|
+
JOIN pg_index ix ON t.oid = ix.indrelid
|
|
1418
|
+
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
1419
|
+
WHERE n.nspname = ANY($1)
|
|
1420
|
+
AND t.relkind = 'r'
|
|
1421
|
+
ORDER BY n.nspname, t.relname, i.relname`, [schemas]);
|
|
1422
|
+
indexRows = rows;
|
|
1423
|
+
}
|
|
1424
|
+
catch (err) {
|
|
1425
|
+
const message = String(err?.message ?? '');
|
|
1426
|
+
if (!message.includes('could not open relation')) {
|
|
1427
|
+
throw err;
|
|
1428
|
+
}
|
|
1429
|
+
const { rows } = await client.query(`SELECT n.nspname AS schema,
|
|
1430
|
+
t.relname AS table,
|
|
1431
|
+
i.relname AS name,
|
|
1432
|
+
ix.indisunique AS "isUnique",
|
|
1433
|
+
NULL::text AS definition
|
|
1434
|
+
FROM pg_class t
|
|
1435
|
+
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
1436
|
+
JOIN pg_index ix ON t.oid = ix.indrelid
|
|
1437
|
+
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
1438
|
+
WHERE n.nspname = ANY($1)
|
|
1439
|
+
AND t.relkind = 'r'
|
|
1440
|
+
ORDER BY n.nspname, t.relname, i.relname`, [schemas]);
|
|
1441
|
+
indexRows = rows;
|
|
1442
|
+
}
|
|
1420
1443
|
indexRows.forEach((row) => {
|
|
1421
1444
|
const tableKey = `${row.schema}.${row.table}`;
|
|
1422
1445
|
const existing = indexesByTable.get(tableKey) ?? [];
|
package/dist/postgres-client.js
CHANGED
|
@@ -172,6 +172,7 @@ class SupaLitePG {
|
|
|
172
172
|
this.schemaCache = new Map(); // schemaName.tableName -> Map<columnName, pgDataType>
|
|
173
173
|
this.foreignKeyCache = new Map();
|
|
174
174
|
this.verbose = false;
|
|
175
|
+
this.ownsPool = true;
|
|
175
176
|
this.verbose = config?.verbose || process.env.SUPALITE_VERBOSE === 'true' || false;
|
|
176
177
|
this.bigintTransform = config?.bigintTransform || 'bigint'; // 기본값 'bigint'
|
|
177
178
|
if (this.verbose) {
|
|
@@ -199,44 +200,53 @@ class SupaLitePG {
|
|
|
199
200
|
pg_1.types.setTypeParser(20, (val) => val === null ? null : BigInt(val));
|
|
200
201
|
break;
|
|
201
202
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
throw new Error('Invalid PostgreSQL connection string format. Must start with postgresql://');
|
|
209
|
-
}
|
|
210
|
-
poolConfigOptions.connectionString = connectionString;
|
|
211
|
-
poolConfigOptions.ssl = config?.ssl !== undefined ? config.ssl : process.env.DB_SSL === 'true';
|
|
212
|
-
if (this.verbose) {
|
|
213
|
-
console.log('[SupaLite VERBOSE] Database connection using connection string');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
catch (err) {
|
|
217
|
-
console.error('[SupaLite ERROR] Database connection error:', err.message);
|
|
218
|
-
throw new Error(`Failed to establish database connection: ${err.message}`);
|
|
203
|
+
this.schema = config?.schema || 'public';
|
|
204
|
+
if (config?.pool) {
|
|
205
|
+
this.pool = config.pool;
|
|
206
|
+
this.ownsPool = false;
|
|
207
|
+
if (this.verbose) {
|
|
208
|
+
console.log('[SupaLite VERBOSE] Using external Pool instance');
|
|
219
209
|
}
|
|
220
210
|
}
|
|
221
211
|
else {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
212
|
+
let poolConfigOptions = {};
|
|
213
|
+
// connectionString이 제공되면 이를 우선 사용
|
|
214
|
+
if (config?.connectionString || process.env.DB_CONNECTION) {
|
|
215
|
+
try {
|
|
216
|
+
const connectionString = config?.connectionString || process.env.DB_CONNECTION || '';
|
|
217
|
+
if (!connectionString.startsWith('postgresql://')) {
|
|
218
|
+
throw new Error('Invalid PostgreSQL connection string format. Must start with postgresql://');
|
|
219
|
+
}
|
|
220
|
+
poolConfigOptions.connectionString = connectionString;
|
|
221
|
+
poolConfigOptions.ssl = config?.ssl !== undefined ? config.ssl : process.env.DB_SSL === 'true';
|
|
222
|
+
if (this.verbose) {
|
|
223
|
+
console.log('[SupaLite VERBOSE] Database connection using connection string');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
console.error('[SupaLite ERROR] Database connection error:', err.message);
|
|
228
|
+
throw new Error(`Failed to establish database connection: ${err.message}`);
|
|
229
|
+
}
|
|
236
230
|
}
|
|
231
|
+
else {
|
|
232
|
+
// 기존 코드: 개별 매개변수 사용
|
|
233
|
+
poolConfigOptions = {
|
|
234
|
+
user: config?.user || process.env.DB_USER,
|
|
235
|
+
host: config?.host || process.env.DB_HOST,
|
|
236
|
+
database: config?.database || process.env.DB_NAME,
|
|
237
|
+
password: config?.password || process.env.DB_PASS,
|
|
238
|
+
port: config?.port || Number(process.env.DB_PORT) || 5432,
|
|
239
|
+
ssl: config?.ssl !== undefined ? config.ssl : process.env.DB_SSL === 'true', // ssl 설정 명시적 처리
|
|
240
|
+
};
|
|
241
|
+
if (this.verbose) {
|
|
242
|
+
console.log('[SupaLite VERBOSE] Database connection using individual parameters:', {
|
|
243
|
+
...poolConfigOptions,
|
|
244
|
+
password: '********'
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this.pool = new pg_1.Pool(poolConfigOptions);
|
|
237
249
|
}
|
|
238
|
-
this.pool = new pg_1.Pool(poolConfigOptions);
|
|
239
|
-
this.schema = config?.schema || 'public';
|
|
240
250
|
// Error handling
|
|
241
251
|
this.pool.on('error', (err) => {
|
|
242
252
|
console.error('[SupaLite ERROR] Unexpected error on idle client', err);
|
|
@@ -415,6 +425,9 @@ class SupaLitePG {
|
|
|
415
425
|
}
|
|
416
426
|
}
|
|
417
427
|
async close() {
|
|
428
|
+
if (!this.ownsPool) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
418
431
|
await this.pool.end();
|
|
419
432
|
}
|
|
420
433
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Pool } from 'pg';
|
|
1
2
|
import { PostgresError } from './errors';
|
|
2
3
|
export type Json = string | number | bigint | boolean | null | {
|
|
3
4
|
[key: string]: Json | undefined;
|
|
@@ -46,6 +47,7 @@ export type UpdateRow<T extends DatabaseSchema, S extends SchemaName<T>, K exten
|
|
|
46
47
|
export type EnumType<T extends DatabaseSchema, S extends SchemaName<T>, E extends keyof NonNullable<T[S]['Enums']>> = NonNullable<T[S]['Enums']>[E];
|
|
47
48
|
export type BigintTransformType = 'bigint' | 'string' | 'number';
|
|
48
49
|
export interface SupaliteConfig {
|
|
50
|
+
pool?: Pool;
|
|
49
51
|
connectionString?: string;
|
|
50
52
|
bigintTransform?: BigintTransformType;
|
|
51
53
|
user?: string;
|