@nuxodin/item 0.6.14 → 0.6.16
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/package.json +1 -1
- package/tools/schema/db/mysql/from-field.js +7 -1
- package/tools/schema/db/mysql/to-db.js +3 -1
- package/tools/schema/db/mysql/to-field.js +3 -0
- package/tools/schema/db/pg/from-field.js +4 -0
- package/tools/schema/db/pg/to-db.js +6 -0
- package/tools/schema/db/pg/to-field.js +1 -0
- package/tools/schema/db/sqlite/from-field.js +1 -0
- package/tools/schema/db/sqlite/to-db.js +1 -0
- package/tools/schema/db/sqlite/to-field.js +1 -0
package/package.json
CHANGED
|
@@ -52,7 +52,8 @@ export function schemaFromField(row) {
|
|
|
52
52
|
prop.maxLength = len;
|
|
53
53
|
} else if (type in textBytes) {
|
|
54
54
|
prop.type = "string";
|
|
55
|
-
|
|
55
|
+
// also for TEXT: without its bound, a wider declaration would never widen it
|
|
56
|
+
prop.maxLength = Math.floor(textBytes[type] / B);
|
|
56
57
|
} else if (type === "binary") {
|
|
57
58
|
prop.type = "string";
|
|
58
59
|
prop.contentEncoding = "base64";
|
|
@@ -78,6 +79,11 @@ export function schemaFromField(row) {
|
|
|
78
79
|
prop.type = "integer";
|
|
79
80
|
prop.minimum = 1901;
|
|
80
81
|
prop.maximum = 2155;
|
|
82
|
+
} else if (type === "vector") {
|
|
83
|
+
// the length belongs to the application, not the schema — see to-field.js
|
|
84
|
+
prop.type = "array";
|
|
85
|
+
prop.items = { type: "number" };
|
|
86
|
+
prop["x-vector"] = true;
|
|
81
87
|
} else if (type === "json") prop.type = "object";
|
|
82
88
|
else if (type === "enum") {
|
|
83
89
|
prop.type = "string";
|
|
@@ -34,7 +34,7 @@ function setEqual(a, b) {
|
|
|
34
34
|
function secondaryIndexKind(prop) {
|
|
35
35
|
if (prop["x-index"] === "unique") return "UNIQUE KEY";
|
|
36
36
|
if (prop["x-index"] === "fulltext") return "FULLTEXT KEY";
|
|
37
|
-
if (prop["x-index"] === true) return "KEY";
|
|
37
|
+
if (prop["x-index"] === true) return prop["x-vector"] ? "VECTOR INDEX" : "KEY";
|
|
38
38
|
return null;
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -233,6 +233,8 @@ async function indexStatements(query, table, nextFields, currFields, { patch = f
|
|
|
233
233
|
const currentKind = current
|
|
234
234
|
? current.indexType === "FULLTEXT"
|
|
235
235
|
? "FULLTEXT KEY"
|
|
236
|
+
: current.indexType === "VECTOR"
|
|
237
|
+
? "VECTOR INDEX"
|
|
236
238
|
: current.nonUnique
|
|
237
239
|
? "KEY"
|
|
238
240
|
: "UNIQUE KEY"
|
|
@@ -15,6 +15,9 @@ export function toFieldDef(name, prop, { required = false } = {}) {
|
|
|
15
15
|
if (schemaType === "boolean") type = "TINYINT(1)";
|
|
16
16
|
else if (schemaType === "integer") ({ type, unsigned } = integerType(prop));
|
|
17
17
|
else if (schemaType === "number") type = prop.multipleOf ? "DECIMAL" : "DOUBLE";
|
|
18
|
+
// `x-vector: true` leaves the length to the application (MariaDB needs one: it starts at 1 and
|
|
19
|
+
// widens with MODIFY, padding existing vectors with zeros); a number fixes it.
|
|
20
|
+
else if (prop["x-vector"]) type = `VECTOR(${prop["x-vector"] === true ? 1 : prop["x-vector"]})`;
|
|
18
21
|
else if (schemaType === "object" || schemaType === "array") type = "JSON";
|
|
19
22
|
else type = stringType(prop);
|
|
20
23
|
|
|
@@ -43,6 +43,10 @@ export function schemaFromField(row) {
|
|
|
43
43
|
} else if (type.startsWith('time') || dataType.startsWith('time')) {
|
|
44
44
|
prop.type = 'string'
|
|
45
45
|
prop.format = 'time'
|
|
46
|
+
} else if (type === 'vector') {
|
|
47
|
+
prop.type = 'array'
|
|
48
|
+
prop.items = { type: 'number' }
|
|
49
|
+
prop['x-vector'] = true
|
|
46
50
|
} else if (type === 'json' || type === 'jsonb') prop.type = 'object'
|
|
47
51
|
else prop.type = 'string'
|
|
48
52
|
|
|
@@ -33,6 +33,8 @@ function preserveDefault(prop, currProp) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function secondaryIndexKind(table, name, prop) {
|
|
36
|
+
// hnsw needs a fixed length and an operator class; the application builds vector indexes
|
|
37
|
+
if (prop['x-vector']) return null
|
|
36
38
|
if (prop['x-index'] === 'unique') return 'UNIQUE INDEX'
|
|
37
39
|
if (prop['x-index'] === true) return 'INDEX'
|
|
38
40
|
if (prop['x-index'] === 'fulltext')
|
|
@@ -171,6 +173,10 @@ export async function schemaToDb(schema, query, { force = false, patch = false }
|
|
|
171
173
|
}
|
|
172
174
|
}
|
|
173
175
|
|
|
176
|
+
// x-vector columns are pgvector's type; the extension has to exist before they do
|
|
177
|
+
const vectors = nextTables.some(t => tableData(schema.properties[t]).fields.some(([, f]) => f['x-vector']))
|
|
178
|
+
if (vectors && stmts.length) stmts.unshift('CREATE EXTENSION IF NOT EXISTS vector;')
|
|
179
|
+
|
|
174
180
|
for (const stmt of stmts) {
|
|
175
181
|
console.log(stmt)
|
|
176
182
|
await query(stmt)
|
|
@@ -17,6 +17,7 @@ export function typeSql(prop) {
|
|
|
17
17
|
if (t === 'boolean') return 'BOOLEAN'
|
|
18
18
|
if (t === 'integer') return integerType(prop)
|
|
19
19
|
if (t === 'number') return prop.multipleOf ? 'NUMERIC' : 'DOUBLE PRECISION'
|
|
20
|
+
if (prop['x-vector']) return prop['x-vector'] === true ? 'vector' : `vector(${prop['x-vector']})` // pgvector
|
|
20
21
|
if (t === 'object' || t === 'array') return 'JSONB'
|
|
21
22
|
if (prop.format in formats) return formats[prop.format]
|
|
22
23
|
if (prop.contentEncoding === 'base64') return 'BYTEA'
|
|
@@ -32,6 +32,7 @@ export function schemaFromField(row) {
|
|
|
32
32
|
} else if (type === 'date') { prop.type = 'string'; prop.format = 'date'
|
|
33
33
|
} else if (type === 'time') { prop.type = 'string'; prop.format = 'time'
|
|
34
34
|
} else if (type === 'datetime' || type === 'timestamp') { prop.type = 'string'; prop.format = 'date-time'
|
|
35
|
+
} else if (type === 'vector') { prop.type = 'array'; prop.items = { type: 'number' }; prop['x-vector'] = true
|
|
35
36
|
} else if (type === 'json') { prop.type = 'object'
|
|
36
37
|
} else {
|
|
37
38
|
prop.type = 'string'
|
|
@@ -47,6 +47,7 @@ function createBody(table, fields, primaries) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function indexKind(table, name, prop) {
|
|
50
|
+
if (prop['x-vector']) return null // sqlite-vec scans; a B-tree over vectors helps nothing
|
|
50
51
|
if (prop['x-index'] === 'unique') return 'UNIQUE INDEX'
|
|
51
52
|
if (prop['x-index'] === true) return 'INDEX'
|
|
52
53
|
if (prop['x-index'] === 'fulltext')
|
|
@@ -15,6 +15,7 @@ export function toFieldDef(name, prop) {
|
|
|
15
15
|
if (t === 'boolean') type = 'BOOLEAN'
|
|
16
16
|
else if (t === 'integer') type = 'INTEGER'
|
|
17
17
|
else if (t === 'number') type = 'REAL'
|
|
18
|
+
else if (prop['x-vector']) type = 'VECTOR' // blobs keep their bytes; the name round-trips
|
|
18
19
|
else if (t === 'object' || t === 'array') type = 'TEXT' // JSON as text
|
|
19
20
|
else {
|
|
20
21
|
// Same reasoning as BOOLEAN: the declared name is the only carrier of the format, and
|