From 039b4c13d457735814b2b13aea3d40141ac45985 Mon Sep 17 00:00:00 2001 From: Nezar Abdennur Date: Wed, 25 Mar 2026 05:34:42 -0400 Subject: [PATCH] Upgrade to sqlglot >=30 compatibility sqlglot 30.x split the expression hierarchy: Expr is now a base trait with _set_parent raising NotImplementedError, while Expression is the concrete class that implements it. Trait classes (Binary, Func) inherit from Expr, so custom expression classes must now inherit from both Expression and their trait class. Additionally, Parser.expression() now expects a pre-constructed instance instead of class + kwargs. Changes: - Add exp.Expression to SpatialPredicate, GIQLCluster, GIQLMerge, GIQLDistance, and GIQLNearest base classes - Construct expression instances before passing to self.expression() in the parser - Pin sqlglot >=30.0.0 --- pyproject.toml | 4 ++-- src/giql/dialect.py | 13 +++++++------ src/giql/expressions.py | 10 +++++----- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1875420..788c525 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ authors = [ { name = "Conrad Bzura", email = "conradbzura@gmail.com" }, ] dependencies = [ - "sqlglot>=20.0.0", + "sqlglot>=30.0.0", ] description = "Genomic Interval Query Language - SQL dialect for genomic range queries" dynamic = ["version"] @@ -84,6 +84,6 @@ pytest = ">=7.0.0" pytest-cov = ">=4.0.0" duckdb = ">=1.4.0" pandas = ">=2.0.0" -sqlglot = ">=20.0.0" +sqlglot = ">=30.0.0" pip = "*" hypothesis = ">=6.148.2,<7" diff --git a/src/giql/dialect.py b/src/giql/dialect.py index 6c70104..b1f5e1b 100644 --- a/src/giql/dialect.py +++ b/src/giql/dialect.py @@ -118,13 +118,14 @@ def _parse_spatial_predicate(self, left, operator, expr_class): self._match_r_paren() return self.expression( - SpatialSetPredicate, - this=left, - operator=operator, - quantifier=quantifier, - ranges=ranges, + SpatialSetPredicate( + this=left, + operator=operator, + quantifier=quantifier, + ranges=ranges, + ) ) else: # Simple spatial predicate right = self._parse_term() - return self.expression(expr_class, this=left, expression=right) + return self.expression(expr_class(this=left, expression=right)) diff --git a/src/giql/expressions.py b/src/giql/expressions.py index 940dbc0..d119b38 100644 --- a/src/giql/expressions.py +++ b/src/giql/expressions.py @@ -24,7 +24,7 @@ class GenomicRange(exp.Expression): } -class SpatialPredicate(exp.Binary): +class SpatialPredicate(exp.Expression, exp.Binary): """Base class for spatial predicates.""" pass @@ -88,7 +88,7 @@ def _split_named_and_positional(args): return kwargs, positional_args -class GIQLCluster(exp.Func): +class GIQLCluster(exp.Expression, exp.Func): """CLUSTER window function for assigning cluster IDs to overlapping intervals. Implicitly partitions by chromosome and orders by start position. @@ -116,7 +116,7 @@ def from_arg_list(cls, args): return cls(**kwargs) -class GIQLMerge(exp.Func): +class GIQLMerge(exp.Expression, exp.Func): """MERGE aggregate function for combining overlapping intervals. Merges overlapping or bookended intervals into single intervals. @@ -144,7 +144,7 @@ def from_arg_list(cls, args): return cls(**kwargs) -class GIQLDistance(exp.Func): +class GIQLDistance(exp.Expression, exp.Func): """DISTANCE function for calculating genomic distances between intervals. Generates SQL CASE expression that computes distance between two genomic @@ -175,7 +175,7 @@ def from_arg_list(cls, args): return cls(**kwargs) -class GIQLNearest(exp.Func): +class GIQLNearest(exp.Expression, exp.Func): """NEAREST function for finding k-nearest genomic features. Generates SQL for k-nearest neighbor queries using LATERAL joins