postgresdk 0.16.0 → 0.16.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/dist/cli.js CHANGED
@@ -1051,6 +1051,8 @@ function postgresTypeToTsType(column, enums) {
1051
1051
  case "_int8":
1052
1052
  case "_integer":
1053
1053
  return "number[]";
1054
+ case "vector":
1055
+ return "number[]";
1054
1056
  default:
1055
1057
  return "string";
1056
1058
  }
@@ -1204,6 +1206,8 @@ function postgresTypeToJsonType(pgType, enums) {
1204
1206
  case "_int8":
1205
1207
  case "_integer":
1206
1208
  return "number[]";
1209
+ case "vector":
1210
+ return "number[]";
1207
1211
  default:
1208
1212
  return "string";
1209
1213
  }
@@ -1397,6 +1401,12 @@ function generateUnifiedContractMarkdown(contract) {
1397
1401
  lines.push("| `$ilike` | Pattern match (case-insensitive) | `{ email: { $ilike: '%@GMAIL%' } }` | String |");
1398
1402
  lines.push("| `$is` | IS NULL | `{ deleted_at: { $is: null } }` | Nullable fields |");
1399
1403
  lines.push("| `$isNot` | IS NOT NULL | `{ created_by: { $isNot: null } }` | Nullable fields |");
1404
+ lines.push("| `$jsonbContains` | JSONB contains | `{ metadata: { $jsonbContains: { tags: ['premium'] } } }` | JSONB/JSON |");
1405
+ lines.push("| `$jsonbContainedBy` | JSONB contained by | `{ metadata: { $jsonbContainedBy: {...} } }` | JSONB/JSON |");
1406
+ lines.push("| `$jsonbHasKey` | JSONB has key | `{ settings: { $jsonbHasKey: 'theme' } }` | JSONB/JSON |");
1407
+ lines.push("| `$jsonbHasAnyKeys` | JSONB has any keys | `{ settings: { $jsonbHasAnyKeys: ['dark', 'light'] } }` | JSONB/JSON |");
1408
+ lines.push("| `$jsonbHasAllKeys` | JSONB has all keys | `{ config: { $jsonbHasAllKeys: ['api', 'db'] } }` | JSONB/JSON |");
1409
+ lines.push("| `$jsonbPath` | JSONB nested value | `{ meta: { $jsonbPath: { path: ['user', 'age'], operator: '$gte', value: 18 } } }` | JSONB/JSON |");
1400
1410
  lines.push("");
1401
1411
  lines.push("### Logical Operators");
1402
1412
  lines.push("");
@@ -1505,6 +1515,43 @@ function generateUnifiedContractMarkdown(contract) {
1505
1515
  lines.push("");
1506
1516
  lines.push("**Note:** Column names are validated by Zod schemas. Only valid table columns are accepted, preventing SQL injection.");
1507
1517
  lines.push("");
1518
+ lines.push("## Vector Search");
1519
+ lines.push("");
1520
+ lines.push("For tables with `vector` columns (requires pgvector extension), use the `vector` parameter for similarity search:");
1521
+ lines.push("");
1522
+ lines.push("```typescript");
1523
+ lines.push("// Basic similarity search");
1524
+ lines.push("const results = await sdk.embeddings.list({");
1525
+ lines.push(" vector: {");
1526
+ lines.push(" field: 'embedding',");
1527
+ lines.push(" query: [0.1, 0.2, 0.3, ...], // Your embedding vector");
1528
+ lines.push(" metric: 'cosine' // 'cosine' (default), 'l2', or 'inner'");
1529
+ lines.push(" },");
1530
+ lines.push(" limit: 10");
1531
+ lines.push("});");
1532
+ lines.push("");
1533
+ lines.push("// Results include _distance field");
1534
+ lines.push("results.data[0]._distance; // Similarity distance");
1535
+ lines.push("");
1536
+ lines.push("// Distance threshold filtering");
1537
+ lines.push("const closeMatches = await sdk.embeddings.list({");
1538
+ lines.push(" vector: {");
1539
+ lines.push(" field: 'embedding',");
1540
+ lines.push(" query: queryVector,");
1541
+ lines.push(" maxDistance: 0.5 // Only return results within this distance");
1542
+ lines.push(" }");
1543
+ lines.push("});");
1544
+ lines.push("");
1545
+ lines.push("// Hybrid search: vector + WHERE filters");
1546
+ lines.push("const filtered = await sdk.embeddings.list({");
1547
+ lines.push(" vector: { field: 'embedding', query: queryVector },");
1548
+ lines.push(" where: {");
1549
+ lines.push(" status: 'published',");
1550
+ lines.push(" embedding: { $isNot: null }");
1551
+ lines.push(" }");
1552
+ lines.push("});");
1553
+ lines.push("```");
1554
+ lines.push("");
1508
1555
  lines.push("## Resources");
1509
1556
  lines.push("");
1510
1557
  for (const resource of contract.resources) {
@@ -2534,7 +2581,8 @@ async function introspect(connectionString, schema) {
2534
2581
  nullable: r.is_nullable === "YES",
2535
2582
  hasDefault: r.column_default != null
2536
2583
  };
2537
- if (pgType === "vector" && r.atttypmod != null && r.atttypmod !== -1) {
2584
+ const isVectorType = pgType === "vector" || pgType === "halfvec" || pgType === "sparsevec" || pgType === "bit";
2585
+ if (isVectorType && r.atttypmod != null && r.atttypmod !== -1) {
2538
2586
  col.vectorDimension = r.atttypmod - 4;
2539
2587
  }
2540
2588
  t.columns.push(col);
@@ -2892,9 +2940,14 @@ export interface PaginatedResponse<T> {
2892
2940
 
2893
2941
  // src/emit-routes-hono.ts
2894
2942
  init_utils();
2943
+ function isVectorType(pgType) {
2944
+ const t = pgType.toLowerCase();
2945
+ return t === "vector" || t === "halfvec" || t === "sparsevec" || t === "bit";
2946
+ }
2895
2947
  function emitHonoRoutes(table, _graph, opts) {
2896
2948
  const fileTableName = table.name;
2897
2949
  const Type = pascal(table.name);
2950
+ const hasVectorColumns = table.columns.some((c) => isVectorType(c.pgType));
2898
2951
  const rawPk = table.pk;
2899
2952
  const pkCols = Array.isArray(rawPk) ? rawPk : rawPk ? [rawPk] : [];
2900
2953
  const safePkCols = pkCols.length ? pkCols : ["id"];
@@ -2930,13 +2983,13 @@ const listSchema = z.object({
2930
2983
  limit: z.number().int().positive().max(1000).optional(),
2931
2984
  offset: z.number().int().min(0).optional(),
2932
2985
  orderBy: z.union([columnEnum, z.array(columnEnum)]).optional(),
2933
- order: z.union([z.enum(["asc", "desc"]), z.array(z.enum(["asc", "desc"]))]).optional(),
2986
+ order: z.union([z.enum(["asc", "desc"]), z.array(z.enum(["asc", "desc"]))]).optional(),${hasVectorColumns ? `
2934
2987
  vector: z.object({
2935
2988
  field: z.string(),
2936
2989
  query: z.array(z.number()),
2937
2990
  metric: z.enum(["cosine", "l2", "inner"]).optional(),
2938
2991
  maxDistance: z.number().optional()
2939
- }).optional()
2992
+ }).optional()` : ""}
2940
2993
  });
2941
2994
 
2942
2995
  /**
@@ -3118,9 +3171,20 @@ ${hasAuth ? `
3118
3171
  // src/emit-client.ts
3119
3172
  init_utils();
3120
3173
  init_emit_include_methods();
3174
+ function isVectorType2(pgType) {
3175
+ const t = pgType.toLowerCase();
3176
+ return t === "vector" || t === "halfvec" || t === "sparsevec" || t === "bit";
3177
+ }
3121
3178
  function emitClient(table, graph, opts, model) {
3122
3179
  const Type = pascal(table.name);
3123
3180
  const ext = opts.useJsExtensions ? ".js" : "";
3181
+ const hasVectorColumns = table.columns.some((c) => isVectorType2(c.pgType));
3182
+ if (process.env.SDK_DEBUG) {
3183
+ const vectorCols = table.columns.filter((c) => isVectorType2(c.pgType));
3184
+ if (vectorCols.length > 0) {
3185
+ console.log(`[DEBUG] Table ${table.name}: Found ${vectorCols.length} vector columns:`, vectorCols.map((c) => `${c.name} (${c.pgType})`));
3186
+ }
3187
+ }
3124
3188
  const pkCols = Array.isArray(table.pk) ? table.pk : table.pk ? [table.pk] : [];
3125
3189
  const safePk = pkCols.length ? pkCols : ["id"];
3126
3190
  const hasCompositePk = safePk.length > 1;
@@ -3271,7 +3335,7 @@ export class ${Type}Client extends BaseClient {
3271
3335
  where?: Where<Select${Type}>;
3272
3336
  orderBy?: string | string[];
3273
3337
  order?: "asc" | "desc" | ("asc" | "desc")[];
3274
- }): Promise<PaginatedResponse<Select${Type}>>;
3338
+ }): Promise<PaginatedResponse<Select${Type}>>;${hasVectorColumns ? `
3275
3339
  /**
3276
3340
  * List ${table.name} records with vector similarity search
3277
3341
  * @param params - Query parameters with vector search enabled
@@ -3291,7 +3355,7 @@ export class ${Type}Client extends BaseClient {
3291
3355
  };
3292
3356
  orderBy?: string | string[];
3293
3357
  order?: "asc" | "desc" | ("asc" | "desc")[];
3294
- }): Promise<PaginatedResponse<Select${Type} & { _distance: number }>>;
3358
+ }): Promise<PaginatedResponse<Select${Type} & { _distance: number }>>;` : ""}
3295
3359
  /**
3296
3360
  * List ${table.name} records with pagination and filtering, with JSONB type overrides
3297
3361
  * @param params - Query parameters with typed JSONB fields in where clause
@@ -3301,13 +3365,13 @@ export class ${Type}Client extends BaseClient {
3301
3365
  include?: any;
3302
3366
  limit?: number;
3303
3367
  offset?: number;
3304
- where?: Where<MergeJsonb<Select${Type}, TJsonb>>;
3368
+ where?: Where<MergeJsonb<Select${Type}, TJsonb>>;${hasVectorColumns ? `
3305
3369
  vector?: {
3306
3370
  field: string;
3307
3371
  query: number[];
3308
3372
  metric?: "cosine" | "l2" | "inner";
3309
3373
  maxDistance?: number;
3310
- };
3374
+ };` : ""}
3311
3375
  orderBy?: string | string[];
3312
3376
  order?: "asc" | "desc" | ("asc" | "desc")[];
3313
3377
  }): Promise<PaginatedResponse<MergeJsonb<Select${Type}, TJsonb>>>;
package/dist/index.js CHANGED
@@ -1050,6 +1050,8 @@ function postgresTypeToTsType(column, enums) {
1050
1050
  case "_int8":
1051
1051
  case "_integer":
1052
1052
  return "number[]";
1053
+ case "vector":
1054
+ return "number[]";
1053
1055
  default:
1054
1056
  return "string";
1055
1057
  }
@@ -1203,6 +1205,8 @@ function postgresTypeToJsonType(pgType, enums) {
1203
1205
  case "_int8":
1204
1206
  case "_integer":
1205
1207
  return "number[]";
1208
+ case "vector":
1209
+ return "number[]";
1206
1210
  default:
1207
1211
  return "string";
1208
1212
  }
@@ -1396,6 +1400,12 @@ function generateUnifiedContractMarkdown(contract) {
1396
1400
  lines.push("| `$ilike` | Pattern match (case-insensitive) | `{ email: { $ilike: '%@GMAIL%' } }` | String |");
1397
1401
  lines.push("| `$is` | IS NULL | `{ deleted_at: { $is: null } }` | Nullable fields |");
1398
1402
  lines.push("| `$isNot` | IS NOT NULL | `{ created_by: { $isNot: null } }` | Nullable fields |");
1403
+ lines.push("| `$jsonbContains` | JSONB contains | `{ metadata: { $jsonbContains: { tags: ['premium'] } } }` | JSONB/JSON |");
1404
+ lines.push("| `$jsonbContainedBy` | JSONB contained by | `{ metadata: { $jsonbContainedBy: {...} } }` | JSONB/JSON |");
1405
+ lines.push("| `$jsonbHasKey` | JSONB has key | `{ settings: { $jsonbHasKey: 'theme' } }` | JSONB/JSON |");
1406
+ lines.push("| `$jsonbHasAnyKeys` | JSONB has any keys | `{ settings: { $jsonbHasAnyKeys: ['dark', 'light'] } }` | JSONB/JSON |");
1407
+ lines.push("| `$jsonbHasAllKeys` | JSONB has all keys | `{ config: { $jsonbHasAllKeys: ['api', 'db'] } }` | JSONB/JSON |");
1408
+ lines.push("| `$jsonbPath` | JSONB nested value | `{ meta: { $jsonbPath: { path: ['user', 'age'], operator: '$gte', value: 18 } } }` | JSONB/JSON |");
1399
1409
  lines.push("");
1400
1410
  lines.push("### Logical Operators");
1401
1411
  lines.push("");
@@ -1504,6 +1514,43 @@ function generateUnifiedContractMarkdown(contract) {
1504
1514
  lines.push("");
1505
1515
  lines.push("**Note:** Column names are validated by Zod schemas. Only valid table columns are accepted, preventing SQL injection.");
1506
1516
  lines.push("");
1517
+ lines.push("## Vector Search");
1518
+ lines.push("");
1519
+ lines.push("For tables with `vector` columns (requires pgvector extension), use the `vector` parameter for similarity search:");
1520
+ lines.push("");
1521
+ lines.push("```typescript");
1522
+ lines.push("// Basic similarity search");
1523
+ lines.push("const results = await sdk.embeddings.list({");
1524
+ lines.push(" vector: {");
1525
+ lines.push(" field: 'embedding',");
1526
+ lines.push(" query: [0.1, 0.2, 0.3, ...], // Your embedding vector");
1527
+ lines.push(" metric: 'cosine' // 'cosine' (default), 'l2', or 'inner'");
1528
+ lines.push(" },");
1529
+ lines.push(" limit: 10");
1530
+ lines.push("});");
1531
+ lines.push("");
1532
+ lines.push("// Results include _distance field");
1533
+ lines.push("results.data[0]._distance; // Similarity distance");
1534
+ lines.push("");
1535
+ lines.push("// Distance threshold filtering");
1536
+ lines.push("const closeMatches = await sdk.embeddings.list({");
1537
+ lines.push(" vector: {");
1538
+ lines.push(" field: 'embedding',");
1539
+ lines.push(" query: queryVector,");
1540
+ lines.push(" maxDistance: 0.5 // Only return results within this distance");
1541
+ lines.push(" }");
1542
+ lines.push("});");
1543
+ lines.push("");
1544
+ lines.push("// Hybrid search: vector + WHERE filters");
1545
+ lines.push("const filtered = await sdk.embeddings.list({");
1546
+ lines.push(" vector: { field: 'embedding', query: queryVector },");
1547
+ lines.push(" where: {");
1548
+ lines.push(" status: 'published',");
1549
+ lines.push(" embedding: { $isNot: null }");
1550
+ lines.push(" }");
1551
+ lines.push("});");
1552
+ lines.push("```");
1553
+ lines.push("");
1507
1554
  lines.push("## Resources");
1508
1555
  lines.push("");
1509
1556
  for (const resource of contract.resources) {
@@ -1705,7 +1752,8 @@ async function introspect(connectionString, schema) {
1705
1752
  nullable: r.is_nullable === "YES",
1706
1753
  hasDefault: r.column_default != null
1707
1754
  };
1708
- if (pgType === "vector" && r.atttypmod != null && r.atttypmod !== -1) {
1755
+ const isVectorType = pgType === "vector" || pgType === "halfvec" || pgType === "sparsevec" || pgType === "bit";
1756
+ if (isVectorType && r.atttypmod != null && r.atttypmod !== -1) {
1709
1757
  col.vectorDimension = r.atttypmod - 4;
1710
1758
  }
1711
1759
  t.columns.push(col);
@@ -2063,9 +2111,14 @@ export interface PaginatedResponse<T> {
2063
2111
 
2064
2112
  // src/emit-routes-hono.ts
2065
2113
  init_utils();
2114
+ function isVectorType(pgType) {
2115
+ const t = pgType.toLowerCase();
2116
+ return t === "vector" || t === "halfvec" || t === "sparsevec" || t === "bit";
2117
+ }
2066
2118
  function emitHonoRoutes(table, _graph, opts) {
2067
2119
  const fileTableName = table.name;
2068
2120
  const Type = pascal(table.name);
2121
+ const hasVectorColumns = table.columns.some((c) => isVectorType(c.pgType));
2069
2122
  const rawPk = table.pk;
2070
2123
  const pkCols = Array.isArray(rawPk) ? rawPk : rawPk ? [rawPk] : [];
2071
2124
  const safePkCols = pkCols.length ? pkCols : ["id"];
@@ -2101,13 +2154,13 @@ const listSchema = z.object({
2101
2154
  limit: z.number().int().positive().max(1000).optional(),
2102
2155
  offset: z.number().int().min(0).optional(),
2103
2156
  orderBy: z.union([columnEnum, z.array(columnEnum)]).optional(),
2104
- order: z.union([z.enum(["asc", "desc"]), z.array(z.enum(["asc", "desc"]))]).optional(),
2157
+ order: z.union([z.enum(["asc", "desc"]), z.array(z.enum(["asc", "desc"]))]).optional(),${hasVectorColumns ? `
2105
2158
  vector: z.object({
2106
2159
  field: z.string(),
2107
2160
  query: z.array(z.number()),
2108
2161
  metric: z.enum(["cosine", "l2", "inner"]).optional(),
2109
2162
  maxDistance: z.number().optional()
2110
- }).optional()
2163
+ }).optional()` : ""}
2111
2164
  });
2112
2165
 
2113
2166
  /**
@@ -2289,9 +2342,20 @@ ${hasAuth ? `
2289
2342
  // src/emit-client.ts
2290
2343
  init_utils();
2291
2344
  init_emit_include_methods();
2345
+ function isVectorType2(pgType) {
2346
+ const t = pgType.toLowerCase();
2347
+ return t === "vector" || t === "halfvec" || t === "sparsevec" || t === "bit";
2348
+ }
2292
2349
  function emitClient(table, graph, opts, model) {
2293
2350
  const Type = pascal(table.name);
2294
2351
  const ext = opts.useJsExtensions ? ".js" : "";
2352
+ const hasVectorColumns = table.columns.some((c) => isVectorType2(c.pgType));
2353
+ if (process.env.SDK_DEBUG) {
2354
+ const vectorCols = table.columns.filter((c) => isVectorType2(c.pgType));
2355
+ if (vectorCols.length > 0) {
2356
+ console.log(`[DEBUG] Table ${table.name}: Found ${vectorCols.length} vector columns:`, vectorCols.map((c) => `${c.name} (${c.pgType})`));
2357
+ }
2358
+ }
2295
2359
  const pkCols = Array.isArray(table.pk) ? table.pk : table.pk ? [table.pk] : [];
2296
2360
  const safePk = pkCols.length ? pkCols : ["id"];
2297
2361
  const hasCompositePk = safePk.length > 1;
@@ -2442,7 +2506,7 @@ export class ${Type}Client extends BaseClient {
2442
2506
  where?: Where<Select${Type}>;
2443
2507
  orderBy?: string | string[];
2444
2508
  order?: "asc" | "desc" | ("asc" | "desc")[];
2445
- }): Promise<PaginatedResponse<Select${Type}>>;
2509
+ }): Promise<PaginatedResponse<Select${Type}>>;${hasVectorColumns ? `
2446
2510
  /**
2447
2511
  * List ${table.name} records with vector similarity search
2448
2512
  * @param params - Query parameters with vector search enabled
@@ -2462,7 +2526,7 @@ export class ${Type}Client extends BaseClient {
2462
2526
  };
2463
2527
  orderBy?: string | string[];
2464
2528
  order?: "asc" | "desc" | ("asc" | "desc")[];
2465
- }): Promise<PaginatedResponse<Select${Type} & { _distance: number }>>;
2529
+ }): Promise<PaginatedResponse<Select${Type} & { _distance: number }>>;` : ""}
2466
2530
  /**
2467
2531
  * List ${table.name} records with pagination and filtering, with JSONB type overrides
2468
2532
  * @param params - Query parameters with typed JSONB fields in where clause
@@ -2472,13 +2536,13 @@ export class ${Type}Client extends BaseClient {
2472
2536
  include?: any;
2473
2537
  limit?: number;
2474
2538
  offset?: number;
2475
- where?: Where<MergeJsonb<Select${Type}, TJsonb>>;
2539
+ where?: Where<MergeJsonb<Select${Type}, TJsonb>>;${hasVectorColumns ? `
2476
2540
  vector?: {
2477
2541
  field: string;
2478
2542
  query: number[];
2479
2543
  metric?: "cosine" | "l2" | "inner";
2480
2544
  maxDistance?: number;
2481
- };
2545
+ };` : ""}
2482
2546
  orderBy?: string | string[];
2483
2547
  order?: "asc" | "desc" | ("asc" | "desc")[];
2484
2548
  }): Promise<PaginatedResponse<MergeJsonb<Select${Type}, TJsonb>>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postgresdk",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "description": "Generate a typed server/client SDK from a Postgres schema (includes, Zod, Hono).",
5
5
  "type": "module",
6
6
  "bin": {