postgresdk 0.15.5 → 0.16.0
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.md +124 -5
- package/dist/cli.js +413 -96
- package/dist/index.js +379 -68
- package/dist/introspect.d.ts +1 -0
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,6 +54,7 @@ const filtered = await sdk.users.list({
|
|
|
54
54
|
- 🔒 **Type Safety** - Full TypeScript types derived from your database schema (including enum types)
|
|
55
55
|
- ✅ **Runtime Validation** - Zod schemas for request/response validation
|
|
56
56
|
- 🔗 **Smart Relationships** - Automatic handling of 1:N and M:N relationships with eager loading
|
|
57
|
+
- 🔍 **Vector Search** - Built-in pgvector support for similarity search with multiple distance metrics
|
|
57
58
|
- 🔐 **Built-in Auth** - API key and JWT authentication
|
|
58
59
|
- 🎯 **Zero Config** - Works out of the box with sensible defaults
|
|
59
60
|
- 📦 **Lightweight** - Minimal dependencies, optimized bundle size
|
|
@@ -157,7 +158,8 @@ export default {
|
|
|
157
158
|
jwt: { // JWT with multi-service support
|
|
158
159
|
services: [
|
|
159
160
|
{ issuer: "my-app", secret: "env:JWT_SECRET" } // Use "env:" prefix!
|
|
160
|
-
]
|
|
161
|
+
],
|
|
162
|
+
audience: "my-api" // Optional: validate aud claim
|
|
161
163
|
}
|
|
162
164
|
},
|
|
163
165
|
|
|
@@ -284,7 +286,6 @@ const sdk = new SDK({
|
|
|
284
286
|
export default {
|
|
285
287
|
connectionString: "...",
|
|
286
288
|
auth: {
|
|
287
|
-
strategy: "jwt-hs256",
|
|
288
289
|
jwt: {
|
|
289
290
|
services: [
|
|
290
291
|
{ issuer: "my-app", secret: "env:JWT_SECRET" } // Use "env:" prefix!
|
|
@@ -298,7 +299,6 @@ export default {
|
|
|
298
299
|
export default {
|
|
299
300
|
connectionString: "...",
|
|
300
301
|
auth: {
|
|
301
|
-
strategy: "jwt-hs256",
|
|
302
302
|
jwt: {
|
|
303
303
|
services: [
|
|
304
304
|
{ issuer: "web-app", secret: "env:WEB_APP_SECRET" },
|
|
@@ -340,7 +340,6 @@ const token = sign({
|
|
|
340
340
|
export default {
|
|
341
341
|
connectionString: process.env.DATABASE_URL,
|
|
342
342
|
auth: {
|
|
343
|
-
strategy: "jwt-hs256",
|
|
344
343
|
jwt: {
|
|
345
344
|
services: [
|
|
346
345
|
{ issuer: "web-app", secret: "env:WEB_SECRET" },
|
|
@@ -602,6 +601,8 @@ result.limit; // number - page size used
|
|
|
602
601
|
result.offset; // number - offset used
|
|
603
602
|
result.hasMore; // boolean - more pages available
|
|
604
603
|
|
|
604
|
+
// Note: Maximum limit is 1000 records per request
|
|
605
|
+
|
|
605
606
|
// Calculate pagination info
|
|
606
607
|
const totalPages = Math.ceil(result.total / result.limit);
|
|
607
608
|
const currentPage = Math.floor(result.offset / result.limit) + 1;
|
|
@@ -670,9 +671,127 @@ do {
|
|
|
670
671
|
offset += limit;
|
|
671
672
|
if (!page.hasMore) break;
|
|
672
673
|
} while (true);
|
|
674
|
+
|
|
675
|
+
// JSONB queries
|
|
676
|
+
const products = await sdk.products.list({
|
|
677
|
+
where: {
|
|
678
|
+
metadata: { $jsonbContains: { tags: ["premium"] } }, // Contains check
|
|
679
|
+
settings: { $jsonbHasKey: "theme" }, // Key exists
|
|
680
|
+
$and: [
|
|
681
|
+
{ config: { $jsonbPath: { path: ["price"], operator: "$gte", value: 100 } } }, // Nested value
|
|
682
|
+
{ config: { $jsonbPath: { path: ["category"], value: "electronics" } } }
|
|
683
|
+
]
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
// Type-safe JSONB with generics
|
|
688
|
+
type Metadata = { tags: string[]; stats: { views: number } };
|
|
689
|
+
const users = await sdk.users.list<{ metadata: Metadata }>({
|
|
690
|
+
where: {
|
|
691
|
+
metadata: { $jsonbContains: { tags: ["vip"] } } // Fully typed!
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
users.data[0].metadata.stats.views; // TypeScript knows this is a number
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
#### Vector Search (pgvector)
|
|
698
|
+
|
|
699
|
+
PostgreSDK automatically detects `vector` columns and enables similarity search using [pgvector](https://github.com/pgvector/pgvector). Requires pgvector extension installed.
|
|
700
|
+
|
|
701
|
+
```sql
|
|
702
|
+
-- Example schema with vector columns
|
|
703
|
+
CREATE EXTENSION vector;
|
|
704
|
+
|
|
705
|
+
CREATE TABLE video_sections (
|
|
706
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
707
|
+
title TEXT NOT NULL,
|
|
708
|
+
vision_embedding vector(1536), -- Image/video embeddings
|
|
709
|
+
text_embedding vector(1536), -- Text embeddings
|
|
710
|
+
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
711
|
+
);
|
|
673
712
|
```
|
|
674
713
|
|
|
675
|
-
|
|
714
|
+
```typescript
|
|
715
|
+
// Basic vector similarity search
|
|
716
|
+
const results = await sdk.video_sections.list({
|
|
717
|
+
vector: {
|
|
718
|
+
field: "vision_embedding",
|
|
719
|
+
query: visionEmbeddingArray, // number[] - your embedding vector
|
|
720
|
+
metric: "cosine" // "cosine" (default), "l2", or "inner"
|
|
721
|
+
},
|
|
722
|
+
limit: 10
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
// Returns records ordered by similarity, with distance included
|
|
726
|
+
results.data.forEach(section => {
|
|
727
|
+
console.log(section.title, section._distance); // _distance auto-included
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
// Distance threshold filtering
|
|
731
|
+
const closeMatches = await sdk.video_sections.list({
|
|
732
|
+
vector: {
|
|
733
|
+
field: "vision_embedding",
|
|
734
|
+
query: embedding,
|
|
735
|
+
metric: "cosine",
|
|
736
|
+
maxDistance: 0.5 // Only return results within this distance
|
|
737
|
+
},
|
|
738
|
+
limit: 50
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
// Hybrid search: combine vector similarity with traditional filters
|
|
742
|
+
const results = await sdk.video_sections.list({
|
|
743
|
+
vector: {
|
|
744
|
+
field: "vision_embedding",
|
|
745
|
+
query: embedding,
|
|
746
|
+
maxDistance: 0.6
|
|
747
|
+
},
|
|
748
|
+
where: {
|
|
749
|
+
status: "published",
|
|
750
|
+
vision_embedding: { $isNot: null } // Ensure embedding exists
|
|
751
|
+
},
|
|
752
|
+
limit: 20
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
// Parallel multi-modal search (vision + text)
|
|
756
|
+
const [visionResults, textResults] = await Promise.all([
|
|
757
|
+
sdk.video_sections.list({
|
|
758
|
+
vector: {
|
|
759
|
+
field: "vision_embedding",
|
|
760
|
+
query: visionQueryEmbedding,
|
|
761
|
+
metric: "cosine",
|
|
762
|
+
maxDistance: 0.6
|
|
763
|
+
},
|
|
764
|
+
where: { vision_embedding: { $isNot: null } },
|
|
765
|
+
limit: 50
|
|
766
|
+
}),
|
|
767
|
+
|
|
768
|
+
sdk.video_sections.list({
|
|
769
|
+
vector: {
|
|
770
|
+
field: "text_embedding",
|
|
771
|
+
query: textQueryEmbedding,
|
|
772
|
+
metric: "cosine",
|
|
773
|
+
maxDistance: 0.5
|
|
774
|
+
},
|
|
775
|
+
where: { text_embedding: { $isNot: null } },
|
|
776
|
+
limit: 50
|
|
777
|
+
})
|
|
778
|
+
]);
|
|
779
|
+
|
|
780
|
+
// Merge and deduplicate results
|
|
781
|
+
const allResults = [...visionResults.data, ...textResults.data];
|
|
782
|
+
const uniqueResults = Array.from(
|
|
783
|
+
new Map(allResults.map(r => [r.id, r])).values()
|
|
784
|
+
);
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
**Distance Metrics:**
|
|
788
|
+
- `cosine`: Cosine distance (best for normalized embeddings, range 0-2)
|
|
789
|
+
- `l2`: Euclidean distance (L2 norm)
|
|
790
|
+
- `inner`: Inner product (negative for similarity)
|
|
791
|
+
|
|
792
|
+
**Note:** Vector columns are auto-detected during introspection. Rows with `NULL` embeddings are excluded from vector search results.
|
|
793
|
+
|
|
794
|
+
See the generated SDK documentation for all available operators: `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$like`, `$ilike`, `$is`, `$isNot`, `$or`, `$and`, `$jsonbContains`, `$jsonbContainedBy`, `$jsonbHasKey`, `$jsonbHasAnyKeys`, `$jsonbHasAllKeys`, `$jsonbPath`.
|
|
676
795
|
|
|
677
796
|
---
|
|
678
797
|
|