DEV Community

Cover image for UQL v0.3: the first TypeScript ORM with native Vector Search
Roger
Roger

Posted on • Originally published at uql-orm.dev

UQL v0.3: the first TypeScript ORM with native Vector Search

AI-powered search is everywhere, but if you use an ORM, you've probably hit this wall: the moment you need vector similarity, you're forced to use raw SQL. Hand-written distance expressions, and dialect-specific quirks — all outside your type-safe query API.

UQL 0.3 changes that. Semantic search can now be used as a first-class citizen, all within a unified API.

What It Looks Like

const results = await querier.findMany(Article, {
  $select: { id: true, title: true },
  $sort: { embedding: { $vector: queryEmbedding, $distance: 'cosine' } },
  $limit: 10,
});
Enter fullscreen mode Exit fullscreen mode

UQL generates the right SQL for your database:

SELECT "id", "title" FROM "Article"
ORDER BY "embedding" <=> $1::vector
LIMIT 10
Enter fullscreen mode Exit fullscreen mode
SELECT `id`, `title` FROM `Article`
ORDER BY VEC_DISTANCE_COSINE(`embedding`, ?)
LIMIT 10
Enter fullscreen mode Exit fullscreen mode
SELECT `id`, `title` FROM `Article`
ORDER BY vec_distance_cosine(`embedding`, ?)
LIMIT 10
Enter fullscreen mode Exit fullscreen mode

No raw SQL. No dialect checks. Same query everywhere.

For MongoDB, UQL translates into an Atlas $vectorSearch pipeline — same API, zero config:

[
  { "$vectorSearch": { "index": "embedding_index", "path": "embedding", "queryVector": ["..."], "numCandidates": 100, "limit": 10 } }
]
Enter fullscreen mode Exit fullscreen mode

Entity Setup

Define your vector field and index — UQL handles schema generation, extension creation, and index building:

import { Entity, Id, Field, Index } from 'uql-orm';

@Entity()
@Index(['embedding'], { type: 'hnsw', distance: 'cosine', m: 16, efConstruction: 64 })
export class Article {
  @Id() id?: number;
  @Field() title?: string;

  @Field({ type: 'vector', dimensions: 1536 })
  embedding?: number[];
}
Enter fullscreen mode Exit fullscreen mode

For Postgres, UQL automatically emits CREATE EXTENSION IF NOT EXISTS vector. MariaDB and SQLite just work — no extensions needed.

Key Features

Distance Projection

Project the computed distance into your results with $project — no duplicate computation:

import type { WithDistance } from 'uql-orm';

const results = await querier.findMany(Article, {
  $select: { id: true, title: true },
  $sort: { embedding: { $vector: queryVec, $distance: 'cosine', $project: 'similarity' } },
  $limit: 10,
}) as WithDistance<Article, 'similarity'>[];

results[0].similarity; // autocomplete works ✓
Enter fullscreen mode Exit fullscreen mode

WithDistance<E, K> adds a typed distance property to each result — your IDE autocompletes it, and typos are caught at compile time.

5 Distance Metrics

Metric Postgres MariaDB SQLite MongoDB Atlas
cosine <=> ✅ (index-defined)
l2 <-> ✅ (index-defined)
inner <#> ✅ (index-defined)
l1 <+>
hamming <~>

3 Vector Types

Type Storage Use Case
'vector' 32-bit float Standard embeddings (OpenAI, etc.)
'halfvec' 16-bit float 50% storage savings, near-identical accuracy
'sparsevec' Sparse SPLADE, BM25-style sparse retrieval

halfvec and sparsevec are Postgres-only. MariaDB and SQLite transparently map them to their native VECTOR type — your entities work everywhere.

Vector Indexes

Type Postgres MariaDB MongoDB Atlas
HNSW ✅ with m, efConstruction
IVFFlat ✅ with lists
Native VECTOR INDEX $vectorSearch

Why $sort?

Vector similarity search is fundamentally sorting by distance. UQL reuses the existing $sort API, which composes naturally with $where, $select, $limit, and regular sort fields:

const results = await querier.findMany(Article, {
  $where: { category: 'science' },
  $sort: { embedding: { $vector: queryVec, $distance: 'cosine' }, title: 'asc' },
  $limit: 10,
});
Enter fullscreen mode Exit fullscreen mode

No new concepts to learn. The query API you already know now handles AI search.

Get Started

npm i uql-orm
Enter fullscreen mode Exit fullscreen mode

We'd love to hear how you're using vector search in your projects — join the Discord and let us know!

Top comments (0)