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 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
- const { rows: indexRows } = await client.query(`SELECT n.nspname AS schema,
1409
- t.relname AS table,
1410
- i.relname AS name,
1411
- ix.indisunique AS "isUnique",
1412
- pg_get_indexdef(ix.indexrelid) AS definition
1413
- FROM pg_class t
1414
- JOIN pg_namespace n ON n.oid = t.relnamespace
1415
- JOIN pg_index ix ON t.oid = ix.indrelid
1416
- JOIN pg_class i ON i.oid = ix.indexrelid
1417
- WHERE n.nspname = ANY($1)
1418
- AND t.relkind = 'r'
1419
- ORDER BY n.nspname, t.relname, i.relname`, [schemas]);
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) ?? [];
@@ -54,6 +54,7 @@ export declare class SupaLitePG<T extends {
54
54
  private foreignKeyCache;
55
55
  verbose: boolean;
56
56
  private bigintTransform;
57
+ private ownsPool;
57
58
  constructor(config?: SupaliteConfig);
58
59
  begin(): Promise<void>;
59
60
  commit(): Promise<void>;
@@ -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
- let poolConfigOptions = {};
203
- // connectionString이 제공되면 이를 우선 사용
204
- if (config?.connectionString || process.env.DB_CONNECTION) {
205
- try {
206
- const connectionString = config?.connectionString || process.env.DB_CONNECTION || '';
207
- if (!connectionString.startsWith('postgresql://')) {
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
- poolConfigOptions = {
224
- user: config?.user || process.env.DB_USER,
225
- host: config?.host || process.env.DB_HOST,
226
- database: config?.database || process.env.DB_NAME,
227
- password: config?.password || process.env.DB_PASS,
228
- port: config?.port || Number(process.env.DB_PORT) || 5432,
229
- ssl: config?.ssl !== undefined ? config.ssl : process.env.DB_SSL === 'true', // ssl 설정 명시적 처리
230
- };
231
- if (this.verbose) {
232
- console.log('[SupaLite VERBOSE] Database connection using individual parameters:', {
233
- ...poolConfigOptions,
234
- password: '********'
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supalite",
3
- "version": "0.7.2",
3
+ "version": "0.7.5",
4
4
  "description": "A lightweight TypeScript PostgreSQL client with Supabase-style API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",