@@ -1487,3 +1487,179 @@ describe('Edge cases', () => {
14871487 assert . ok ( names . some ( n => n === 'ws_test' ) ) ;
14881488 } ) ;
14891489} ) ;
1490+
1491+ // ============================================================
1492+ // Vector support
1493+ // ============================================================
1494+
1495+ describe ( 'Vector support' , ( ) => {
1496+ let db ;
1497+
1498+ before ( async ( ) => {
1499+ db = await Database . open ( ':memory:' ) ;
1500+ } ) ;
1501+
1502+ after ( async ( ) => {
1503+ await db . close ( ) ;
1504+ } ) ;
1505+
1506+ it ( 'should create table with VECTOR column' , async ( ) => {
1507+ await db . exec ( 'CREATE TABLE embeddings (id INTEGER PRIMARY KEY, embedding VECTOR(3))' ) ;
1508+ const tables = await db . query ( 'SHOW TABLES' ) ;
1509+ const names = tables . map ( t => t . table_name || t . Tables ) ;
1510+ assert . ok ( names . some ( n => n === 'embeddings' ) ) ;
1511+ } ) ;
1512+
1513+ it ( 'should insert vectors via SQL string literals' , async ( ) => {
1514+ const result = await db . execute (
1515+ "INSERT INTO embeddings (id, embedding) VALUES (1, '[0.1, 0.2, 0.3]')"
1516+ ) ;
1517+ assert . equal ( result . changes , 1 ) ;
1518+ } ) ;
1519+
1520+ it ( 'should insert multiple vectors' , async ( ) => {
1521+ await db . execute ( "INSERT INTO embeddings (id, embedding) VALUES (2, '[0.4, 0.5, 0.6]')" ) ;
1522+ await db . execute ( "INSERT INTO embeddings (id, embedding) VALUES (3, '[0.7, 0.8, 0.9]')" ) ;
1523+ const rows = await db . query ( 'SELECT id FROM embeddings ORDER BY id' ) ;
1524+ assert . equal ( rows . length , 3 ) ;
1525+ } ) ;
1526+
1527+ it ( 'should return vectors as Float32Array' , async ( ) => {
1528+ const row = await db . queryOne ( 'SELECT embedding FROM embeddings WHERE id = 1' ) ;
1529+ assert . ok ( row . embedding instanceof Float32Array , 'embedding should be Float32Array' ) ;
1530+ assert . equal ( row . embedding . length , 3 ) ;
1531+ assert . ok ( Math . abs ( row . embedding [ 0 ] - 0.1 ) < 0.001 ) ;
1532+ assert . ok ( Math . abs ( row . embedding [ 1 ] - 0.2 ) < 0.001 ) ;
1533+ assert . ok ( Math . abs ( row . embedding [ 2 ] - 0.3 ) < 0.001 ) ;
1534+ } ) ;
1535+
1536+ it ( 'should return vectors in query() results' , async ( ) => {
1537+ const rows = await db . query ( 'SELECT * FROM embeddings ORDER BY id' ) ;
1538+ assert . equal ( rows . length , 3 ) ;
1539+ for ( const row of rows ) {
1540+ assert . ok ( row . embedding instanceof Float32Array ) ;
1541+ assert . equal ( row . embedding . length , 3 ) ;
1542+ }
1543+ } ) ;
1544+
1545+ it ( 'should return vectors in querySync() results' , ( ) => {
1546+ const rows = db . querySync ( 'SELECT * FROM embeddings ORDER BY id' ) ;
1547+ assert . equal ( rows . length , 3 ) ;
1548+ assert . ok ( rows [ 0 ] . embedding instanceof Float32Array ) ;
1549+ } ) ;
1550+
1551+ it ( 'should return vectors in queryOneSync() results' , ( ) => {
1552+ const row = db . queryOneSync ( 'SELECT embedding FROM embeddings WHERE id = 2' ) ;
1553+ assert . ok ( row . embedding instanceof Float32Array ) ;
1554+ assert . ok ( Math . abs ( row . embedding [ 0 ] - 0.4 ) < 0.001 ) ;
1555+ } ) ;
1556+
1557+ it ( 'should return vectors in queryRaw() results' , async ( ) => {
1558+ const raw = await db . queryRaw ( 'SELECT id, embedding FROM embeddings ORDER BY id' ) ;
1559+ assert . ok ( raw . columns . includes ( 'embedding' ) ) ;
1560+ assert . equal ( raw . rows . length , 3 ) ;
1561+ const embIdx = raw . columns . indexOf ( 'embedding' ) ;
1562+ assert . ok ( raw . rows [ 0 ] [ embIdx ] instanceof Float32Array ) ;
1563+ } ) ;
1564+
1565+ it ( 'should return vectors in queryRawSync() results' , ( ) => {
1566+ const raw = db . queryRawSync ( 'SELECT id, embedding FROM embeddings ORDER BY id' ) ;
1567+ const embIdx = raw . columns . indexOf ( 'embedding' ) ;
1568+ assert . ok ( raw . rows [ 0 ] [ embIdx ] instanceof Float32Array ) ;
1569+ } ) ;
1570+
1571+ it ( 'should handle NULL vectors' , async ( ) => {
1572+ await db . execute ( "INSERT INTO embeddings (id, embedding) VALUES (4, NULL)" ) ;
1573+ const row = await db . queryOne ( 'SELECT embedding FROM embeddings WHERE id = 4' ) ;
1574+ assert . equal ( row . embedding , null ) ;
1575+ } ) ;
1576+
1577+ it ( 'should compute L2 distance' , async ( ) => {
1578+ const rows = await db . query (
1579+ "SELECT id, VEC_DISTANCE_L2(embedding, '[0.1, 0.2, 0.3]') AS dist FROM embeddings WHERE id <= 3 ORDER BY dist"
1580+ ) ;
1581+ assert . equal ( rows . length , 3 ) ;
1582+ // id=1 has the same vector, distance should be ~0
1583+ assert . equal ( rows [ 0 ] . id , 1 ) ;
1584+ assert . ok ( rows [ 0 ] . dist < 0.001 ) ;
1585+ } ) ;
1586+
1587+ it ( 'should compute cosine distance' , async ( ) => {
1588+ const rows = await db . query (
1589+ "SELECT id, VEC_DISTANCE_COSINE(embedding, '[0.1, 0.2, 0.3]') AS dist FROM embeddings WHERE id <= 3 ORDER BY dist"
1590+ ) ;
1591+ assert . equal ( rows . length , 3 ) ;
1592+ assert . equal ( rows [ 0 ] . id , 1 ) ;
1593+ assert . ok ( rows [ 0 ] . dist < 0.001 ) ;
1594+ } ) ;
1595+
1596+ it ( 'should support k-NN search with ORDER BY + LIMIT' , async ( ) => {
1597+ const rows = await db . query (
1598+ "SELECT id, VEC_DISTANCE_L2(embedding, '[0.4, 0.5, 0.6]') AS dist FROM embeddings WHERE id <= 3 ORDER BY dist LIMIT 2"
1599+ ) ;
1600+ assert . equal ( rows . length , 2 ) ;
1601+ // id=2 has exact match [0.4, 0.5, 0.6]
1602+ assert . equal ( rows [ 0 ] . id , 2 ) ;
1603+ } ) ;
1604+
1605+ it ( 'should work with higher-dimensional vectors' , async ( ) => {
1606+ await db . exec ( 'CREATE TABLE hd_vecs (id INTEGER PRIMARY KEY, vec VECTOR(128))' ) ;
1607+ const dims = 128 ;
1608+ const values = Array . from ( { length : dims } , ( _ , i ) => ( i / dims ) . toFixed ( 6 ) ) ;
1609+ const vecStr = `[${ values . join ( ', ' ) } ]` ;
1610+ await db . execute ( `INSERT INTO hd_vecs (id, vec) VALUES (1, '${ vecStr } ')` ) ;
1611+ const row = await db . queryOne ( 'SELECT vec FROM hd_vecs WHERE id = 1' ) ;
1612+ assert . ok ( row . vec instanceof Float32Array ) ;
1613+ assert . equal ( row . vec . length , dims ) ;
1614+ } ) ;
1615+
1616+ it ( 'should accept Float32Array as bind parameter' , async ( ) => {
1617+ await db . exec ( 'CREATE TABLE vec_params (id INTEGER PRIMARY KEY, vec VECTOR(3))' ) ;
1618+ const vec = new Float32Array ( [ 1.0 , 2.0 , 3.0 ] ) ;
1619+ await db . execute ( "INSERT INTO vec_params (id, vec) VALUES (1, '[1.0, 2.0, 3.0]')" ) ;
1620+ // Use Float32Array in distance computation param
1621+ const row = db . queryOneSync (
1622+ "SELECT VEC_DISTANCE_L2(vec, '[1.0, 2.0, 3.0]') AS dist FROM vec_params WHERE id = 1"
1623+ ) ;
1624+ assert . ok ( row . dist < 0.001 ) ;
1625+ } ) ;
1626+
1627+ it ( 'should support vectors in transactions' , async ( ) => {
1628+ await db . exec ( 'CREATE TABLE tx_vecs (id INTEGER PRIMARY KEY, vec VECTOR(3))' ) ;
1629+ const tx = await db . begin ( ) ;
1630+ await tx . execute ( "INSERT INTO tx_vecs (id, vec) VALUES (1, '[1.0, 2.0, 3.0]')" ) ;
1631+ await tx . execute ( "INSERT INTO tx_vecs (id, vec) VALUES (2, '[4.0, 5.0, 6.0]')" ) ;
1632+ const rows = await tx . query ( 'SELECT * FROM tx_vecs ORDER BY id' ) ;
1633+ assert . equal ( rows . length , 2 ) ;
1634+ assert . ok ( rows [ 0 ] . vec instanceof Float32Array ) ;
1635+ await tx . commit ( ) ;
1636+
1637+ const afterCommit = await db . query ( 'SELECT * FROM tx_vecs ORDER BY id' ) ;
1638+ assert . equal ( afterCommit . length , 2 ) ;
1639+ } ) ;
1640+
1641+ it ( 'should support VEC_DIMS utility function' , async ( ) => {
1642+ const row = await db . queryOne ( 'SELECT VEC_DIMS(embedding) AS dims FROM embeddings WHERE id = 1' ) ;
1643+ assert . equal ( row . dims , 3 ) ;
1644+ } ) ;
1645+
1646+ it ( 'should reject wrong dimension count on insert' , async ( ) => {
1647+ await assert . rejects (
1648+ db . execute ( "INSERT INTO embeddings (id, embedding) VALUES (99, '[0.1, 0.2]')" ) ,
1649+ / d i m e n s i o n | m i s m a t c h | e x p e c t e d / i
1650+ ) ;
1651+ } ) ;
1652+
1653+ it ( 'should support HNSW index creation' , async ( ) => {
1654+ await db . exec ( 'CREATE TABLE hnsw_test (id INTEGER PRIMARY KEY, vec VECTOR(3))' ) ;
1655+ await db . execute ( "INSERT INTO hnsw_test (id, vec) VALUES (1, '[0.1, 0.2, 0.3]')" ) ;
1656+ await db . execute ( "INSERT INTO hnsw_test (id, vec) VALUES (2, '[0.4, 0.5, 0.6]')" ) ;
1657+ await db . execute ( "INSERT INTO hnsw_test (id, vec) VALUES (3, '[0.7, 0.8, 0.9]')" ) ;
1658+ await db . exec ( 'CREATE INDEX idx_hnsw ON hnsw_test(vec) USING HNSW' ) ;
1659+ const rows = await db . query (
1660+ "SELECT id, VEC_DISTANCE_L2(vec, '[0.4, 0.5, 0.6]') AS dist FROM hnsw_test ORDER BY dist LIMIT 2"
1661+ ) ;
1662+ assert . equal ( rows . length , 2 ) ;
1663+ assert . equal ( rows [ 0 ] . id , 2 ) ;
1664+ } ) ;
1665+ } ) ;
0 commit comments