@prisma-next/extension-pgvector 0.0.1
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 +171 -0
- package/dist/exports/codec-types.d.ts +12 -0
- package/dist/exports/codec-types.js +1 -0
- package/dist/exports/codec-types.js.map +1 -0
- package/dist/exports/control.d.ts +93 -0
- package/dist/exports/control.js +54 -0
- package/dist/exports/control.js.map +1 -0
- package/dist/exports/operation-types.d.ts +32 -0
- package/dist/exports/operation-types.js +1 -0
- package/dist/exports/operation-types.js.map +1 -0
- package/dist/exports/runtime.d.ts +15 -0
- package/dist/exports/runtime.js +82 -0
- package/dist/exports/runtime.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# @prisma-next/extension-pgvector
|
|
2
|
+
|
|
3
|
+
PostgreSQL pgvector extension pack for Prisma Next.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This extension pack adds support for the `vector` data type and vector similarity operations (e.g., cosine distance) for PostgreSQL databases with the pgvector extension installed.
|
|
8
|
+
|
|
9
|
+
## Responsibilities
|
|
10
|
+
|
|
11
|
+
- **Vector Codec**: Provides codec for `pg/vector@1` type ID mapping to `number[]` JavaScript type
|
|
12
|
+
- **Vector Operations**: Registers vector similarity operations (e.g., `cosineDistance`) for use in queries
|
|
13
|
+
- **CLI Integration**: Provides extension descriptor for `prisma-next.config.ts` configuration
|
|
14
|
+
- **Runtime Extension**: Registers codecs and operations at runtime for vector column operations
|
|
15
|
+
|
|
16
|
+
## Dependencies
|
|
17
|
+
|
|
18
|
+
- **`@prisma-next/cli`**: CLI config types and extension descriptor interface
|
|
19
|
+
- **`@prisma-next/sql-operations`**: SQL operation signature types
|
|
20
|
+
- **`@prisma-next/sql-relational-core`**: Codec registry and AST types
|
|
21
|
+
- **`arktype`**: Schema validation for manifest structure
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add @prisma-next/extension-pgvector
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Database Setup
|
|
30
|
+
|
|
31
|
+
Before using this extension, ensure the pgvector extension is installed in your PostgreSQL database:
|
|
32
|
+
|
|
33
|
+
```sql
|
|
34
|
+
CREATE EXTENSION IF NOT EXISTS vector;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
Add the extension to your `prisma-next.config.ts`:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { defineConfig } from '@prisma-next/cli/config-types';
|
|
43
|
+
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
44
|
+
import sql from '@prisma-next/family-sql/cli';
|
|
45
|
+
import postgres from '@prisma-next/targets-postgres/control';
|
|
46
|
+
import pgvector from '@prisma-next/extension-pgvector/control';
|
|
47
|
+
|
|
48
|
+
export default defineConfig({
|
|
49
|
+
family: sql,
|
|
50
|
+
target: postgres,
|
|
51
|
+
adapter: postgresAdapter,
|
|
52
|
+
extensions: [pgvector],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
### Contract Definition
|
|
59
|
+
|
|
60
|
+
Add vector columns to your contract:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { defineContract } from '@prisma-next/sql-contract-ts/contract-builder';
|
|
64
|
+
import type { CodecTypes } from '@prisma-next/adapter-postgres/codec-types';
|
|
65
|
+
import type { CodecTypes as PgVectorCodecTypes } from '@prisma-next/extension-pgvector/codec-types';
|
|
66
|
+
|
|
67
|
+
type AllCodecTypes = CodecTypes & PgVectorCodecTypes;
|
|
68
|
+
|
|
69
|
+
export const contract = defineContract<AllCodecTypes>()
|
|
70
|
+
.target('postgres')
|
|
71
|
+
.table('post', (t) =>
|
|
72
|
+
t
|
|
73
|
+
.column('id', { type: 'pg/int4@1', nullable: false })
|
|
74
|
+
.column('title', { type: 'pg/text@1', nullable: false })
|
|
75
|
+
.column('embedding', { type: 'pg/vector@1', nullable: true })
|
|
76
|
+
.primaryKey(['id']),
|
|
77
|
+
)
|
|
78
|
+
.build();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Runtime Setup
|
|
82
|
+
|
|
83
|
+
Register the extension when creating your runtime context:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { createRuntimeContext } from '@prisma-next/sql-runtime';
|
|
87
|
+
import { createPostgresAdapter } from '@prisma-next/adapter-postgres/runtime';
|
|
88
|
+
import pgvector from '@prisma-next/extension-pgvector/runtime';
|
|
89
|
+
|
|
90
|
+
const adapter = createPostgresAdapter();
|
|
91
|
+
const context = createRuntimeContext({
|
|
92
|
+
contract,
|
|
93
|
+
adapter,
|
|
94
|
+
extensions: [pgvector()],
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Query Usage
|
|
99
|
+
|
|
100
|
+
Use vector similarity operations in your queries:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { sql, tables } from '../prisma/query';
|
|
104
|
+
import { param } from '@prisma-next/sql-query/param';
|
|
105
|
+
import type { ResultType } from '@prisma-next/sql-query/types';
|
|
106
|
+
|
|
107
|
+
const queryVector = [0.1, 0.2, 0.3, /* ... */];
|
|
108
|
+
|
|
109
|
+
const plan = sql
|
|
110
|
+
.from(tables.post)
|
|
111
|
+
.select({
|
|
112
|
+
id: tables.post.columns.id,
|
|
113
|
+
title: tables.post.columns.title,
|
|
114
|
+
distance: tables.post.columns.embedding.cosineDistance(param('queryVector')),
|
|
115
|
+
})
|
|
116
|
+
.orderBy(tables.post.columns.embedding.cosineDistance(param('queryVector')).asc())
|
|
117
|
+
.limit(10)
|
|
118
|
+
.build({ params: { queryVector } });
|
|
119
|
+
|
|
120
|
+
type Row = ResultType<typeof plan>;
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Types
|
|
124
|
+
|
|
125
|
+
### Codec Types
|
|
126
|
+
|
|
127
|
+
The extension provides a `CodecTypes` export mapping the `pg/vector@1` type ID to `number[]`:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
import type { CodecTypes } from '@prisma-next/extension-pgvector/codec-types';
|
|
131
|
+
|
|
132
|
+
// CodecTypes['pg/vector@1']['output'] = number[]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Operation Types
|
|
136
|
+
|
|
137
|
+
The extension provides an `OperationTypes` export for vector operations:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import type { OperationTypes } from '@prisma-next/extension-pgvector/operation-types';
|
|
141
|
+
|
|
142
|
+
// OperationTypes['pg/vector@1']['cosineDistance'] = (rhs: number[] | vector) => number
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Operations
|
|
146
|
+
|
|
147
|
+
### cosineDistance
|
|
148
|
+
|
|
149
|
+
Computes the cosine distance between two vectors.
|
|
150
|
+
|
|
151
|
+
**Signature**: `cosineDistance(rhs: number[] | vector): number`
|
|
152
|
+
|
|
153
|
+
**SQL**: Uses the pgvector `<=>` operator: `1 - (vector1 <=> vector2)`
|
|
154
|
+
|
|
155
|
+
**Example**:
|
|
156
|
+
```typescript
|
|
157
|
+
const distance = tables.post.columns.embedding.cosineDistance(param('queryVector'));
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Capabilities
|
|
161
|
+
|
|
162
|
+
The extension declares the following capabilities:
|
|
163
|
+
|
|
164
|
+
- `pgvector/cosine`: Indicates support for cosine distance operations
|
|
165
|
+
|
|
166
|
+
## References
|
|
167
|
+
|
|
168
|
+
- [pgvector documentation](https://github.com/pgvector/pgvector)
|
|
169
|
+
- [Prisma Next Architecture Overview](../../../docs/Architecture%20Overview.md)
|
|
170
|
+
- [Extension Packs Guide](../../../docs/reference/Extension-Packs-Naming-and-Layout.md)
|
|
171
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as _prisma_next_sql_relational_core_ast from '@prisma-next/sql-relational-core/ast';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Vector codec implementation for pgvector extension.
|
|
5
|
+
*
|
|
6
|
+
* Provides encoding/decoding for the `vector` PostgreSQL type.
|
|
7
|
+
* Wire format is a string like `[1,2,3]` (PostgreSQL vector text format).
|
|
8
|
+
*/
|
|
9
|
+
declare const codecs: _prisma_next_sql_relational_core_ast.CodecDefBuilder<{} & Record<"vector", _prisma_next_sql_relational_core_ast.Codec<"pg/vector@1", string, number[]>>>;
|
|
10
|
+
type CodecTypes = typeof codecs.CodecTypes;
|
|
11
|
+
|
|
12
|
+
export type { CodecTypes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=codec-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specifies how to import TypeScript types from a package.
|
|
3
|
+
* Used in extension pack manifests to declare codec and operation type imports.
|
|
4
|
+
*/
|
|
5
|
+
interface TypesImportSpec {
|
|
6
|
+
readonly package: string;
|
|
7
|
+
readonly named: string;
|
|
8
|
+
readonly alias: string;
|
|
9
|
+
}
|
|
10
|
+
type ArgSpecManifest = {
|
|
11
|
+
readonly kind: 'typeId';
|
|
12
|
+
readonly type: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: 'param';
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'literal';
|
|
17
|
+
};
|
|
18
|
+
type ReturnSpecManifest = {
|
|
19
|
+
readonly kind: 'typeId';
|
|
20
|
+
readonly type: string;
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: 'builtin';
|
|
23
|
+
readonly type: 'number' | 'boolean' | 'string';
|
|
24
|
+
};
|
|
25
|
+
interface LoweringSpecManifest {
|
|
26
|
+
readonly targetFamily: 'sql';
|
|
27
|
+
readonly strategy: 'infix' | 'function';
|
|
28
|
+
readonly template: string;
|
|
29
|
+
}
|
|
30
|
+
interface OperationManifest {
|
|
31
|
+
readonly for: string;
|
|
32
|
+
readonly method: string;
|
|
33
|
+
readonly args: ReadonlyArray<ArgSpecManifest>;
|
|
34
|
+
readonly returns: ReturnSpecManifest;
|
|
35
|
+
readonly lowering: LoweringSpecManifest;
|
|
36
|
+
readonly capabilities?: ReadonlyArray<string>;
|
|
37
|
+
}
|
|
38
|
+
interface ExtensionPackManifest {
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly version: string;
|
|
41
|
+
readonly targets?: Record<string, {
|
|
42
|
+
readonly minVersion?: string;
|
|
43
|
+
}>;
|
|
44
|
+
readonly capabilities?: Record<string, unknown>;
|
|
45
|
+
readonly types?: {
|
|
46
|
+
readonly codecTypes?: {
|
|
47
|
+
readonly import: TypesImportSpec;
|
|
48
|
+
};
|
|
49
|
+
readonly operationTypes?: {
|
|
50
|
+
readonly import: TypesImportSpec;
|
|
51
|
+
};
|
|
52
|
+
readonly storage?: readonly {
|
|
53
|
+
readonly typeId: string;
|
|
54
|
+
readonly familyId: string;
|
|
55
|
+
readonly targetId: string;
|
|
56
|
+
readonly nativeType?: string;
|
|
57
|
+
}[];
|
|
58
|
+
};
|
|
59
|
+
readonly operations?: ReadonlyArray<OperationManifest>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Base interface for control-plane extension instances.
|
|
64
|
+
*
|
|
65
|
+
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
66
|
+
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
67
|
+
*/
|
|
68
|
+
interface ControlExtensionInstance<TFamilyId extends string = string, TTargetId extends string = string> {
|
|
69
|
+
readonly familyId: TFamilyId;
|
|
70
|
+
readonly targetId: TTargetId;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Descriptor for a control-plane extension pack (e.g., pgvector).
|
|
74
|
+
*
|
|
75
|
+
* @template TFamilyId - The family ID (e.g., 'sql', 'document')
|
|
76
|
+
* @template TTargetId - The target ID (e.g., 'postgres', 'mysql')
|
|
77
|
+
* @template TExtensionInstance - The extension instance type
|
|
78
|
+
*/
|
|
79
|
+
interface ControlExtensionDescriptor<TFamilyId extends string, TTargetId extends string, TExtensionInstance extends ControlExtensionInstance<TFamilyId, TTargetId> = ControlExtensionInstance<TFamilyId, TTargetId>> {
|
|
80
|
+
readonly kind: 'extension';
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly familyId: TFamilyId;
|
|
83
|
+
readonly targetId: TTargetId;
|
|
84
|
+
readonly manifest: ExtensionPackManifest;
|
|
85
|
+
create(): TExtensionInstance;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* pgvector extension descriptor for CLI config.
|
|
90
|
+
*/
|
|
91
|
+
declare const pgvectorExtensionDescriptor: ControlExtensionDescriptor<'sql', 'postgres'>;
|
|
92
|
+
|
|
93
|
+
export { pgvectorExtensionDescriptor as default };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/exports/control.ts
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { type } from "arktype";
|
|
6
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
var __dirname = dirname(__filename);
|
|
8
|
+
var TypesImportSpecSchema = type({
|
|
9
|
+
package: "string",
|
|
10
|
+
named: "string",
|
|
11
|
+
alias: "string"
|
|
12
|
+
});
|
|
13
|
+
var ExtensionPackManifestSchema = type({
|
|
14
|
+
id: "string",
|
|
15
|
+
version: "string",
|
|
16
|
+
"targets?": type({ "[string]": type({ "minVersion?": "string" }) }),
|
|
17
|
+
"capabilities?": "Record<string, unknown>",
|
|
18
|
+
"types?": type({
|
|
19
|
+
"codecTypes?": type({
|
|
20
|
+
import: TypesImportSpecSchema
|
|
21
|
+
}),
|
|
22
|
+
"operationTypes?": type({
|
|
23
|
+
import: TypesImportSpecSchema
|
|
24
|
+
})
|
|
25
|
+
}),
|
|
26
|
+
"operations?": "unknown[]"
|
|
27
|
+
});
|
|
28
|
+
function loadExtensionManifest() {
|
|
29
|
+
const manifestPath = join(__dirname, "../../packs/manifest.json");
|
|
30
|
+
const manifestJson = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
31
|
+
const result = ExtensionPackManifestSchema(manifestJson);
|
|
32
|
+
if (result instanceof type.errors) {
|
|
33
|
+
const messages = result.map((p) => p.message).join("; ");
|
|
34
|
+
throw new Error(`Invalid extension manifest structure at ${manifestPath}: ${messages}`);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
var pgvectorExtensionDescriptor = {
|
|
39
|
+
kind: "extension",
|
|
40
|
+
familyId: "sql",
|
|
41
|
+
targetId: "postgres",
|
|
42
|
+
// pgvector is postgres-specific
|
|
43
|
+
id: "pgvector",
|
|
44
|
+
manifest: loadExtensionManifest(),
|
|
45
|
+
create: () => ({
|
|
46
|
+
familyId: "sql",
|
|
47
|
+
targetId: "postgres"
|
|
48
|
+
})
|
|
49
|
+
};
|
|
50
|
+
var control_default = pgvectorExtensionDescriptor;
|
|
51
|
+
export {
|
|
52
|
+
control_default as default
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/exports/control.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExtensionPackManifest } from '@prisma-next/contract/pack-manifest-types';\nimport type { ControlExtensionDescriptor } from '@prisma-next/core-control-plane/types';\nimport { type } from 'arktype';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst TypesImportSpecSchema = type({\n package: 'string',\n named: 'string',\n alias: 'string',\n});\n\nconst ExtensionPackManifestSchema = type({\n id: 'string',\n version: 'string',\n 'targets?': type({ '[string]': type({ 'minVersion?': 'string' }) }),\n 'capabilities?': 'Record<string, unknown>',\n 'types?': type({\n 'codecTypes?': type({\n import: TypesImportSpecSchema,\n }),\n 'operationTypes?': type({\n import: TypesImportSpecSchema,\n }),\n }),\n 'operations?': 'unknown[]',\n});\n\n/**\n * Loads the extension pack manifest from packs/manifest.json.\n */\nfunction loadExtensionManifest(): ExtensionPackManifest {\n const manifestPath = join(__dirname, '../../packs/manifest.json');\n const manifestJson = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n\n const result = ExtensionPackManifestSchema(manifestJson);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Invalid extension manifest structure at ${manifestPath}: ${messages}`);\n }\n\n return result as ExtensionPackManifest;\n}\n\n/**\n * pgvector extension descriptor for CLI config.\n */\nconst pgvectorExtensionDescriptor: ControlExtensionDescriptor<'sql', 'postgres'> = {\n kind: 'extension',\n familyId: 'sql',\n targetId: 'postgres', // pgvector is postgres-specific\n id: 'pgvector',\n manifest: loadExtensionManifest(),\n create: () => ({\n familyId: 'sql' as const,\n targetId: 'postgres' as const,\n }),\n};\n\nexport default pgvectorExtensionDescriptor;\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAG9B,SAAS,YAAY;AAErB,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AAEpC,IAAM,wBAAwB,KAAK;AAAA,EACjC,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AACT,CAAC;AAED,IAAM,8BAA8B,KAAK;AAAA,EACvC,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,YAAY,KAAK,EAAE,YAAY,KAAK,EAAE,eAAe,SAAS,CAAC,EAAE,CAAC;AAAA,EAClE,iBAAiB;AAAA,EACjB,UAAU,KAAK;AAAA,IACb,eAAe,KAAK;AAAA,MAClB,QAAQ;AAAA,IACV,CAAC;AAAA,IACD,mBAAmB,KAAK;AAAA,MACtB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AAAA,EACD,eAAe;AACjB,CAAC;AAKD,SAAS,wBAA+C;AACtD,QAAM,eAAe,KAAK,WAAW,2BAA2B;AAChE,QAAM,eAAe,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAEnE,QAAM,SAAS,4BAA4B,YAAY;AACvD,MAAI,kBAAkB,KAAK,QAAQ;AACjC,UAAM,WAAW,OAAO,IAAI,CAAC,MAA2B,EAAE,OAAO,EAAE,KAAK,IAAI;AAC5E,UAAM,IAAI,MAAM,2CAA2C,YAAY,KAAK,QAAQ,EAAE;AAAA,EACxF;AAEA,SAAO;AACT;AAKA,IAAM,8BAA6E;AAAA,EACjF,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AAAA;AAAA,EACV,IAAI;AAAA,EACJ,UAAU,sBAAsB;AAAA,EAChC,QAAQ,OAAO;AAAA,IACb,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAEA,IAAO,kBAAQ;","names":[]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operation type definitions for pgvector extension.
|
|
3
|
+
*
|
|
4
|
+
* This file exports type-only definitions for operation method signatures.
|
|
5
|
+
* These types are imported by contract.d.ts files for compile-time type inference.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Operation types for pgvector extension.
|
|
9
|
+
* Maps typeId to operation methods.
|
|
10
|
+
*/
|
|
11
|
+
type OperationTypes = {
|
|
12
|
+
readonly 'pg/vector@1': {
|
|
13
|
+
readonly cosineDistance: {
|
|
14
|
+
readonly args: readonly [
|
|
15
|
+
{
|
|
16
|
+
readonly kind: 'param';
|
|
17
|
+
}
|
|
18
|
+
];
|
|
19
|
+
readonly returns: {
|
|
20
|
+
readonly kind: 'builtin';
|
|
21
|
+
readonly type: 'number';
|
|
22
|
+
};
|
|
23
|
+
readonly lowering: {
|
|
24
|
+
readonly targetFamily: 'sql';
|
|
25
|
+
readonly strategy: 'function';
|
|
26
|
+
readonly template: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type { OperationTypes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=operation-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SqlOperationSignature } from '@prisma-next/sql-operations';
|
|
2
|
+
import { CodecRegistry } from '@prisma-next/sql-relational-core/ast';
|
|
3
|
+
|
|
4
|
+
interface Extension {
|
|
5
|
+
codecs?(): CodecRegistry;
|
|
6
|
+
operations?(): ReadonlyArray<SqlOperationSignature>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a pgvector extension instance for runtime registration.
|
|
11
|
+
* Provides codecs and operations for vector data type and similarity operations.
|
|
12
|
+
*/
|
|
13
|
+
declare function pgvector(): Extension;
|
|
14
|
+
|
|
15
|
+
export { pgvector as default };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// src/exports/runtime.ts
|
|
2
|
+
import { createCodecRegistry } from "@prisma-next/sql-relational-core/ast";
|
|
3
|
+
|
|
4
|
+
// src/core/codecs.ts
|
|
5
|
+
import { codec, defineCodecs } from "@prisma-next/sql-relational-core/ast";
|
|
6
|
+
var pgVectorCodec = codec({
|
|
7
|
+
typeId: "pg/vector@1",
|
|
8
|
+
targetTypes: ["vector"],
|
|
9
|
+
encode: (value) => {
|
|
10
|
+
if (!Array.isArray(value)) {
|
|
11
|
+
throw new Error("Vector value must be an array of numbers");
|
|
12
|
+
}
|
|
13
|
+
if (!value.every((v) => typeof v === "number")) {
|
|
14
|
+
throw new Error("Vector value must contain only numbers");
|
|
15
|
+
}
|
|
16
|
+
return `[${value.join(",")}]`;
|
|
17
|
+
},
|
|
18
|
+
decode: (wire) => {
|
|
19
|
+
if (typeof wire !== "string") {
|
|
20
|
+
throw new Error("Vector wire value must be a string");
|
|
21
|
+
}
|
|
22
|
+
if (!wire.startsWith("[") || !wire.endsWith("]")) {
|
|
23
|
+
throw new Error(`Invalid vector format: expected "[...]", got "${wire}"`);
|
|
24
|
+
}
|
|
25
|
+
const content = wire.slice(1, -1).trim();
|
|
26
|
+
if (content === "") {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
const values = content.split(",").map((v) => {
|
|
30
|
+
const num = Number.parseFloat(v.trim());
|
|
31
|
+
if (Number.isNaN(num)) {
|
|
32
|
+
throw new Error(`Invalid vector value: "${v}" is not a number`);
|
|
33
|
+
}
|
|
34
|
+
return num;
|
|
35
|
+
});
|
|
36
|
+
return values;
|
|
37
|
+
},
|
|
38
|
+
meta: {
|
|
39
|
+
db: {
|
|
40
|
+
sql: {
|
|
41
|
+
postgres: {
|
|
42
|
+
nativeType: "vector"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
var codecs = defineCodecs().add("vector", pgVectorCodec);
|
|
49
|
+
var codecDefinitions = codecs.codecDefinitions;
|
|
50
|
+
var dataTypes = codecs.dataTypes;
|
|
51
|
+
|
|
52
|
+
// src/exports/runtime.ts
|
|
53
|
+
function pgvector() {
|
|
54
|
+
return {
|
|
55
|
+
codecs() {
|
|
56
|
+
const registry = createCodecRegistry();
|
|
57
|
+
for (const def of Object.values(codecDefinitions)) {
|
|
58
|
+
registry.register(def.codec);
|
|
59
|
+
}
|
|
60
|
+
return registry;
|
|
61
|
+
},
|
|
62
|
+
operations() {
|
|
63
|
+
return [
|
|
64
|
+
{
|
|
65
|
+
forTypeId: "pg/vector@1",
|
|
66
|
+
method: "cosineDistance",
|
|
67
|
+
args: [{ kind: "param" }],
|
|
68
|
+
returns: { kind: "builtin", type: "number" },
|
|
69
|
+
lowering: {
|
|
70
|
+
targetFamily: "sql",
|
|
71
|
+
strategy: "function",
|
|
72
|
+
template: "1 - ({{self}} <=> {{arg0}})"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
pgvector as default
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/exports/runtime.ts","../../src/core/codecs.ts"],"sourcesContent":["import type { SqlOperationSignature } from '@prisma-next/sql-operations';\nimport type { CodecRegistry } from '@prisma-next/sql-relational-core/ast';\nimport { createCodecRegistry } from '@prisma-next/sql-relational-core/ast';\nimport type { Extension } from '@prisma-next/sql-runtime';\nimport { codecDefinitions } from '../core/codecs';\n\n/**\n * Creates a pgvector extension instance for runtime registration.\n * Provides codecs and operations for vector data type and similarity operations.\n */\nexport default function pgvector(): Extension {\n return {\n codecs(): CodecRegistry {\n const registry = createCodecRegistry();\n // Register all codecs from codecDefinitions\n for (const def of Object.values(codecDefinitions)) {\n registry.register(def.codec);\n }\n return registry;\n },\n operations(): ReadonlyArray<SqlOperationSignature> {\n return [\n {\n forTypeId: 'pg/vector@1',\n method: 'cosineDistance',\n args: [{ kind: 'param' }],\n returns: { kind: 'builtin', type: 'number' },\n lowering: {\n targetFamily: 'sql',\n strategy: 'function',\n template: '1 - ({{self}} <=> {{arg0}})',\n },\n },\n ];\n },\n };\n}\n","/**\n * Vector codec implementation for pgvector extension.\n *\n * Provides encoding/decoding for the `vector` PostgreSQL type.\n * Wire format is a string like `[1,2,3]` (PostgreSQL vector text format).\n */\n\nimport { codec, defineCodecs } from '@prisma-next/sql-relational-core/ast';\n\nconst pgVectorCodec = codec<'pg/vector@1', string, number[]>({\n typeId: 'pg/vector@1',\n targetTypes: ['vector'],\n encode: (value: number[]): string => {\n // Validate that value is an array of numbers\n if (!Array.isArray(value)) {\n throw new Error('Vector value must be an array of numbers');\n }\n if (!value.every((v) => typeof v === 'number')) {\n throw new Error('Vector value must contain only numbers');\n }\n // Format as PostgreSQL vector text format: [1,2,3]\n // PostgreSQL's pg library requires the vector format string\n return `[${value.join(',')}]`;\n },\n decode: (wire: string): number[] => {\n // Handle string format from PostgreSQL: [1,2,3]\n if (typeof wire !== 'string') {\n throw new Error('Vector wire value must be a string');\n }\n // Parse PostgreSQL vector format: [1,2,3]\n if (!wire.startsWith('[') || !wire.endsWith(']')) {\n throw new Error(`Invalid vector format: expected \"[...]\", got \"${wire}\"`);\n }\n const content = wire.slice(1, -1).trim();\n if (content === '') {\n return [];\n }\n const values = content.split(',').map((v) => {\n const num = Number.parseFloat(v.trim());\n if (Number.isNaN(num)) {\n throw new Error(`Invalid vector value: \"${v}\" is not a number`);\n }\n return num;\n });\n return values;\n },\n meta: {\n db: {\n sql: {\n postgres: {\n nativeType: 'vector',\n },\n },\n },\n },\n});\n\n// Build codec definitions using the builder DSL\nconst codecs = defineCodecs().add('vector', pgVectorCodec);\n\n// Export derived structures directly from codecs builder\nexport const codecDefinitions = codecs.codecDefinitions;\nexport const dataTypes = codecs.dataTypes;\n\n// Export types derived from codecs builder\nexport type CodecTypes = typeof codecs.CodecTypes;\n"],"mappings":";AAEA,SAAS,2BAA2B;;;ACKpC,SAAS,OAAO,oBAAoB;AAEpC,IAAM,gBAAgB,MAAuC;AAAA,EAC3D,QAAQ;AAAA,EACR,aAAa,CAAC,QAAQ;AAAA,EACtB,QAAQ,CAAC,UAA4B;AAEnC,QAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AACA,QAAI,CAAC,MAAM,MAAM,CAAC,MAAM,OAAO,MAAM,QAAQ,GAAG;AAC9C,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAGA,WAAO,IAAI,MAAM,KAAK,GAAG,CAAC;AAAA,EAC5B;AAAA,EACA,QAAQ,CAAC,SAA2B;AAElC,QAAI,OAAO,SAAS,UAAU;AAC5B,YAAM,IAAI,MAAM,oCAAoC;AAAA,IACtD;AAEA,QAAI,CAAC,KAAK,WAAW,GAAG,KAAK,CAAC,KAAK,SAAS,GAAG,GAAG;AAChD,YAAM,IAAI,MAAM,iDAAiD,IAAI,GAAG;AAAA,IAC1E;AACA,UAAM,UAAU,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK;AACvC,QAAI,YAAY,IAAI;AAClB,aAAO,CAAC;AAAA,IACV;AACA,UAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM;AAC3C,YAAM,MAAM,OAAO,WAAW,EAAE,KAAK,CAAC;AACtC,UAAI,OAAO,MAAM,GAAG,GAAG;AACrB,cAAM,IAAI,MAAM,0BAA0B,CAAC,mBAAmB;AAAA,MAChE;AACA,aAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,IACJ,IAAI;AAAA,MACF,KAAK;AAAA,QACH,UAAU;AAAA,UACR,YAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAGD,IAAM,SAAS,aAAa,EAAE,IAAI,UAAU,aAAa;AAGlD,IAAM,mBAAmB,OAAO;AAChC,IAAM,YAAY,OAAO;;;ADpDjB,SAAR,WAAuC;AAC5C,SAAO;AAAA,IACL,SAAwB;AACtB,YAAM,WAAW,oBAAoB;AAErC,iBAAW,OAAO,OAAO,OAAO,gBAAgB,GAAG;AACjD,iBAAS,SAAS,IAAI,KAAK;AAAA,MAC7B;AACA,aAAO;AAAA,IACT;AAAA,IACA,aAAmD;AACjD,aAAO;AAAA,QACL;AAAA,UACE,WAAW;AAAA,UACX,QAAQ;AAAA,UACR,MAAM,CAAC,EAAE,MAAM,QAAQ,CAAC;AAAA,UACxB,SAAS,EAAE,MAAM,WAAW,MAAM,SAAS;AAAA,UAC3C,UAAU;AAAA,YACR,cAAc;AAAA,YACd,UAAU;AAAA,YACV,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prisma-next/extension-pgvector",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"arktype": "^2.0.0",
|
|
8
|
+
"@prisma-next/cli": "0.0.1",
|
|
9
|
+
"@prisma-next/sql-operations": "0.0.1",
|
|
10
|
+
"@prisma-next/sql-relational-core": "0.0.1"
|
|
11
|
+
},
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"tsup": "^8.3.0",
|
|
14
|
+
"typescript": "^5.9.3",
|
|
15
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
16
|
+
"vitest": "^2.1.1",
|
|
17
|
+
"@prisma-next/test-utils": "0.0.1"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"exports": {
|
|
23
|
+
"./control": {
|
|
24
|
+
"types": "./dist/exports/control.d.ts",
|
|
25
|
+
"import": "./dist/exports/control.js"
|
|
26
|
+
},
|
|
27
|
+
"./runtime": {
|
|
28
|
+
"types": "./dist/exports/runtime.d.ts",
|
|
29
|
+
"import": "./dist/exports/runtime.js"
|
|
30
|
+
},
|
|
31
|
+
"./codec-types": {
|
|
32
|
+
"types": "./dist/exports/codec-types.d.ts",
|
|
33
|
+
"import": "./dist/exports/codec-types.js"
|
|
34
|
+
},
|
|
35
|
+
"./operation-types": {
|
|
36
|
+
"types": "./dist/exports/operation-types.d.ts",
|
|
37
|
+
"import": "./dist/exports/operation-types.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup --config tsup.config.ts",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:coverage": "vitest run --coverage",
|
|
44
|
+
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
45
|
+
"lint": "biome check . --config-path ../../../biome.json --error-on-warnings",
|
|
46
|
+
"clean": "node ../../../scripts/clean.mjs"
|
|
47
|
+
}
|
|
48
|
+
}
|