feat(nodejs): add col() expression builder for camelCase column names

## Summary

Fixes #3211 by exposing the shared Rust/DataFusion expression builder through Node bindings. Case-sensitive references such as `col("firstName")` can be composed and passed to `where()`, while SQL strings remain supported.

The expression-object representation follows [the design requested on #3290](https://github.com/lancedb/lancedb/pull/3290#discussion_r3632371998). That earlier PR remains open; no claim is made that the issue was unclaimed or that maintainers have selected this implementation.

## Review corrections

- Construct the named native struct correctly and parse casts through `arrow_schema::DataType`.
- Preserve numeric values: use Int64 only for JavaScript safe integers; retain Float64 otherwise. Explicit `litInt` rejects unsupported numbers with a documented `RangeError`.
- Correct test syntax/API calls and align SQL assertions with the shared dialect, including reserved and case-sensitive names.
- Use typed, isolated temporary test tables with cleanup, and cover an actual large-number filter threshold.
- Document the public methods and commit generated API documentation.

Synced with current main `0bceaaf3` through a normal merge. The diff is limited to seven Node source/test/config files and eleven generated documentation files; no Rust core change.

## Validation

[Linux validation run](https://github.com/Ganesh1729-ui/lancedb/actions/runs/38244794288) on Node 24 / Rust 1.97.0 with the repository's `ci` profile and `remote,lancedb/metrics-otel` features:

- Rebuilt native addon, TypeScript build, Biome, Rust formatting and native Clippy pass.
- Expression/query/Arrow/table suites: **1,129 passed**; expression suite repeated: **42 passed**.
- Using the original JavaScript numeric dispatch with the rebuilt addon: **8 regressions fail, 2 controls pass**.
- Strict TypeDoc generation passes. Final local typing/docs/lint checks pass; the PR source equals the validated source except for the separate validation workflow, which is excluded from this PR.

Full provider/model/S3, other feature combinations and OS/Node matrices were not run in this follow-up. Upstream checks and maintainer review remain separate.

## AI assistance

AI was used for implementation, review and testing. No prior human review is claimed.
This commit is contained in:
J Ganesh Kumar Reddy
2026-10-29 02:18:16 +08:00
committed by GitHub
parent ece54d8917
commit 12d86ea251
20 changed files with 1406 additions and 34 deletions
+9 -4
View File
@@ -469,29 +469,34 @@ where(predicate): this
A filter statement to be applied to this query.
The filter should be supplied as an SQL query string. For example:
The filter may be an SQL query string or an expression built with `col`,
which preserves case-sensitive column names. For example:
#### Parameters
* **predicate**: `string`
* **predicate**: `string` \| [`Expr`](Expr.md)
#### Returns
`this`
#### Example
#### Examples
```ts
x > 10
y > 0 AND y < 100
x > 5 OR y = 'test'
```
```ts
table.query().where(col("firstName").eq("Alice"));
```
Filtering performance can often be improved by creating a scalar index
on the filter column(s).
Calling this multiple times combines the filters with a logical AND rather
than replacing the previous filter.
```
#### Inherited from
+365
View File
@@ -0,0 +1,365 @@
[**@lancedb/lancedb**](../README.md) • **Docs**
***
[@lancedb/lancedb](../globals.md) / Expr
# Class: Expr
A SQL expression backed by the shared LanceDB expression builder.
## Example
```ts
table.query().where(col("firstName").eq("Alice")).toArray();
```
## Constructors
### new Expr()
```ts
new Expr(inner): Expr
```
#### Parameters
* **inner**: `Expr`
#### Returns
[`Expr`](Expr.md)
## Properties
### inner
```ts
inner: Expr;
```
## Methods
### add()
```ts
add(other): Expr
```
Add a value.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### and()
```ts
and(other): Expr
```
Combine two predicates with AND.
#### Parameters
* **other**: [`Expr`](Expr.md)
#### Returns
[`Expr`](Expr.md)
***
### cast()
```ts
cast(dataType): Expr
```
Cast to an Arrow data type, such as "Int64".
#### Parameters
* **dataType**: `string`
#### Returns
[`Expr`](Expr.md)
***
### contains()
```ts
contains(substr): Expr
```
Test whether a string contains a substring.
#### Parameters
* **substr**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### div()
```ts
div(other): Expr
```
Divide by a value.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### eq()
```ts
eq(other): Expr
```
Compare for equality.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### gt()
```ts
gt(other): Expr
```
Compare for greater than.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### gte()
```ts
gte(other): Expr
```
Compare for greater than or equal to.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### isIn()
```ts
isIn(values): Expr
```
Test membership in a list of values.
#### Parameters
* **values**: [`ExprLike`](../type-aliases/ExprLike.md)[]
#### Returns
[`Expr`](Expr.md)
***
### lower()
```ts
lower(): Expr
```
Convert a string to lowercase.
#### Returns
[`Expr`](Expr.md)
***
### lt()
```ts
lt(other): Expr
```
Compare for less than.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### lte()
```ts
lte(other): Expr
```
Compare for less than or equal to.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### mul()
```ts
mul(other): Expr
```
Multiply by a value.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### ne()
```ts
ne(other): Expr
```
Compare for inequality.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### not()
```ts
not(): Expr
```
Negate this predicate.
#### Returns
[`Expr`](Expr.md)
***
### or()
```ts
or(other): Expr
```
Combine two predicates with OR.
#### Parameters
* **other**: [`Expr`](Expr.md)
#### Returns
[`Expr`](Expr.md)
***
### sub()
```ts
sub(other): Expr
```
Subtract a value.
#### Parameters
* **other**: [`ExprLike`](../type-aliases/ExprLike.md)
#### Returns
[`Expr`](Expr.md)
***
### toSql()
```ts
toSql(): string
```
Serialize with the LanceDB SQL dialect, preserving column case.
#### Returns
`string`
***
### upper()
```ts
upper(): Expr
```
Convert a string to uppercase.
#### Returns
[`Expr`](Expr.md)
+9 -4
View File
@@ -543,29 +543,34 @@ where(predicate): this
A filter statement to be applied to this query.
The filter should be supplied as an SQL query string. For example:
The filter may be an SQL query string or an expression built with `col`,
which preserves case-sensitive column names. For example:
#### Parameters
* **predicate**: `string`
* **predicate**: `string` \| [`Expr`](Expr.md)
#### Returns
`this`
#### Example
#### Examples
```ts
x > 10
y > 0 AND y < 100
x > 5 OR y = 'test'
```
```ts
table.query().where(col("firstName").eq("Alice"));
```
Filtering performance can often be improved by creating a scalar index
on the filter column(s).
Calling this multiple times combines the filters with a logical AND rather
than replacing the previous filter.
```
#### Inherited from
+9 -4
View File
@@ -825,29 +825,34 @@ where(predicate): this
A filter statement to be applied to this query.
The filter should be supplied as an SQL query string. For example:
The filter may be an SQL query string or an expression built with `col`,
which preserves case-sensitive column names. For example:
#### Parameters
* **predicate**: `string`
* **predicate**: `string` \| [`Expr`](Expr.md)
#### Returns
`this`
#### Example
#### Examples
```ts
x > 10
y > 0 AND y < 100
x > 5 OR y = 'test'
```
```ts
table.query().where(col("firstName").eq("Alice"));
```
Filtering performance can often be improved by creating a scalar index
on the filter column(s).
Calling this multiple times combines the filters with a logical AND rather
than replacing the previous filter.
```
#### Inherited from
+21
View File
@@ -0,0 +1,21 @@
[**@lancedb/lancedb**](../README.md) • **Docs**
***
[@lancedb/lancedb](../globals.md) / col
# Function: col()
```ts
function col(name): Expr
```
Reference a column by its exact, case-sensitive name.
## Parameters
* **name**: `string`
## Returns
[`Expr`](../classes/Expr.md)
+23
View File
@@ -0,0 +1,23 @@
[**@lancedb/lancedb**](../README.md) • **Docs**
***
[@lancedb/lancedb](../globals.md) / func
# Function: func()
```ts
function func(name, ...args): Expr
```
Call a registered SQL function, such as `func("lower", col("firstName"))`.
## Parameters
* **name**: `string`
* ...**args**: [`ExprLike`](../type-aliases/ExprLike.md)[]
## Returns
[`Expr`](../classes/Expr.md)
+21
View File
@@ -0,0 +1,21 @@
[**@lancedb/lancedb**](../README.md) • **Docs**
***
[@lancedb/lancedb](../globals.md) / lit
# Function: lit()
```ts
function lit(value): Expr
```
Create a string or numeric literal. Unsafe integers are represented as Float64.
## Parameters
* **value**: `string` \| `number`
## Returns
[`Expr`](../classes/Expr.md)
+21
View File
@@ -0,0 +1,21 @@
[**@lancedb/lancedb**](../README.md) • **Docs**
***
[@lancedb/lancedb](../globals.md) / litBool
# Function: litBool()
```ts
function litBool(value): Expr
```
Create a boolean literal.
## Parameters
* **value**: `boolean`
## Returns
[`Expr`](../classes/Expr.md)
+21
View File
@@ -0,0 +1,21 @@
[**@lancedb/lancedb**](../README.md) • **Docs**
***
[@lancedb/lancedb](../globals.md) / litInt
# Function: litInt()
```ts
function litInt(value): Expr
```
Create an Int64 literal from a JavaScript safe integer. Other numbers throw RangeError.
## Parameters
* **value**: `number`
## Returns
[`Expr`](../classes/Expr.md)
+7
View File
@@ -28,6 +28,7 @@
- [Catalog](classes/Catalog.md)
- [Connection](classes/Connection.md)
- [DatabaseNames](classes/DatabaseNames.md)
- [Expr](classes/Expr.md)
- [HeaderProvider](classes/HeaderProvider.md)
- [Index](classes/Index.md)
- [Job](classes/Job.md)
@@ -165,6 +166,7 @@
- [Data](type-aliases/Data.md)
- [DataLike](type-aliases/DataLike.md)
- [DataTypeLike](type-aliases/DataTypeLike.md)
- [ExprLike](type-aliases/ExprLike.md)
- [FieldLike](type-aliases/FieldLike.md)
- [IntoSql](type-aliases/IntoSql.md)
- [IntoVector](type-aliases/IntoVector.md)
@@ -179,11 +181,16 @@
- [RecordBatchIterator](functions/RecordBatchIterator.md)
- [blob](functions/blob.md)
- [col](functions/col.md)
- [connect](functions/connect.md)
- [connectCatalog](functions/connectCatalog.md)
- [connectNamespace](functions/connectNamespace.md)
- [func](functions/func.md)
- [instrumentLanceDbMetrics](functions/instrumentLanceDbMetrics.md)
- [isBlobField](functions/isBlobField.md)
- [lit](functions/lit.md)
- [litBool](functions/litBool.md)
- [litInt](functions/litInt.md)
- [makeArrowTable](functions/makeArrowTable.md)
- [makeJsonField](functions/makeJsonField.md)
- [packBits](functions/packBits.md)
+13
View File
@@ -0,0 +1,13 @@
[**@lancedb/lancedb**](../README.md) • **Docs**
***
[@lancedb/lancedb](../globals.md) / ExprLike
# Type Alias: ExprLike
```ts
type ExprLike: Expr | string | number | boolean;
```
Values accepted by expression operators.