Skip to content

Value types and helpers

Dart types for Postgres values that have no built-in Dart equivalent, plus two small helpers. All are exported from package:gisila_orm/gisila.dart.

import 'package:gisila_orm/gisila.dart';
final v = Vector([0.1, 0.2, 0.3]);
final p = Point(52.52, 13.40);
class Vector {
Vector(List<double> values);
factory Vector.fromList(List<num> values);
factory Vector.zeros(int dimensions);
factory Vector.parse(String text);
}

An immutable list of doubles matching pgvector’s vector(n). The field type of type: vector columns, and the argument to the vector operators.

When to use: storing embeddings and querying them by similarity. Requires the pgvector extension on the server.

Member Type Description
Vector(values) constructor Copies values into an unmodifiable list.
Vector.fromList(values) factory Accepts any numbers (for example decoded JSON).
Vector.zeros(n) factory n zeros. Throws ArgumentError for negative n.
Vector.parse(text) factory Parses [0.1,0.2], tolerating whitespace, surrounding single quotes and a trailing ::vector. Throws FormatException otherwise.
values List<double> The components (unmodifiable).
dimensions int Length.
toSqlLiteral() String [v1,v2,...], the form bound as a parameter.
l2Norm double Euclidean length.
normalized Vector Unit-length copy; a zero vector is returned unchanged.
dot(other) double Dot product. Throws ArgumentError when dimensions differ.
cosineSimilarityTo(other) double Similarity in [-1, 1]; 0 if either is zero. pgvector’s <=> returns distance, 1 - similarity.

== and hashCode compare component-wise. When bound, a Vector is sent as text with a ::vector cast.

await documents().insert({'title': 'Intro', 'embedding': Vector.fromList(embeddingFromApi)}).run(ctx);
final hits = await documents()
.orderBy(DocumentTable.embedding.cosineDistance(queryVector))
.limit(5)
.all(ctx);
enum VectorDistance { l2, cosine, innerProduct }
Value op opclass alias (schema YAML)
l2 <-> vector_l2_ops l2
cosine <=> vector_cosine_ops cosine
innerProduct <#> vector_ip_ops ip

VectorDistance.fromAlias(String) accepts the alias or the enum name (case-insensitive) and returns null for anything else.

enum VectorIndexMethod { hnsw, ivfflat }

Index method for vector indexes. fromAlias(String) parses the name or returns null. HNSW is the schema default; it needs no training data and is usually the better choice. IVFFlat builds faster but should be created after the table has data.

Dart values for Postgres’s built-in geometric types. Each has const constructors, value equality, toSqlLiteral() (also used by toString()) and a static fromString that throws FormatException on bad input.

Class Constructor Postgres Text form
Point const Point(double x, double y) point (x,y)
Box const Box(Point corner1, Point corner2) box ((x1,y1),(x2,y2))
Circle const Circle(Point center, double radius) circle <(x,y),r>
Lseg const Lseg(Point start, Point end) lseg [(x1,y1),(x2,y2)]

When to use: simple planar geometry stored in core Postgres. There are no geometric operators in the query builder beyond equality and null checks; use RawSql for <@, <-> and friends. For geographic data, PostGIS is a better fit (not supported by the schema).

When bound, each is sent as its text form with a matching cast ($1::point).

await places().insert({'name': 'Office', 'location': const Point(52.52, 13.40)}).run(ctx);
final near = await places()
.where(RawSql<bool>('"places"."location" <-> \$1::point < 0.5', ['(52.5,13.4)']))
.all(ctx);
String? encodeJsonColumn(Object? value)

jsonEncodes a value for a json column, passing null through.

When to use: when you write a JSON column through an insert or update map. The driver can bind a Dart Map as JSON on its own, but a list would be turned into a Postgres array literal and a string or boolean wouldn’t be parsed as JSON. Generated toRow() already uses it.

await users().where(UserTable.id.eq(id)).update({
'preferences': encodeJsonColumn({'theme': 'dark', 'langs': ['en', 'de']}),
}).run(ctx);
extension SafeString on String {
String get safeTk; // "identifier"
String get safe; // 'literal'
}
Getter Result Description
safeTk "foo" Quotes an identifier, doubling inner ". Returns an already well-formed quoted identifier unchanged.
safe 'foo' Quotes a string literal, doubling inner '. Returns an already well-formed literal unchanged.

When to use: safeTk when you build SQL that needs a table or column name known only at runtime (for example a sort column picked from an allow-list). For values, use bound parameters rather than safe.

const sortable = {'title', 'published_at'};
final col = sortable.contains(requested) ? requested : 'published_at';
final rows = await db.execute('SELECT * FROM "posts" ORDER BY ${col.safeTk} DESC LIMIT 20');

See also: Schema YAML format, Expressions and operators.