@jarenjs/linq 0.43.1 → 0.46.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/docs/LINQ-FORMAT.md +26 -1
- package/package.json +3 -3
- package/src/expression.js +5 -0
package/README.md
CHANGED
|
@@ -52,6 +52,12 @@ played by the provider seam below.
|
|
|
52
52
|
spatial measurements are `geoArea`/`geoLength` because `length` on
|
|
53
53
|
this surface is already `$string-length` — the mapping table says so
|
|
54
54
|
in its own row.
|
|
55
|
+
- **Meaning is spellable too.** `m.embedding.similarity(query)` emits
|
|
56
|
+
§8.15's `$similarity`, and k-nearest is the chain it already looks
|
|
57
|
+
like — `.orderByDescending(..., { empty: 'least' }).thenBy(m => m.id)
|
|
58
|
+
.take(10)` — because ordering and windowing are stages, not a `knn`
|
|
59
|
+
method. `.params({ query })` binds the query vector at call time, so
|
|
60
|
+
one compiled document serves every question.
|
|
55
61
|
- **The provider contract.** Any object with
|
|
56
62
|
`execute(queryDocument, { externals })` is a provider.
|
|
57
63
|
`@jarenjs/db` implements it — a chain over a SQLite-backed
|
package/docs/LINQ-FORMAT.md
CHANGED
|
@@ -116,6 +116,7 @@ is part of THIS design.
|
|
|
116
116
|
| `Zip` | — no positional co-iteration in the grammar | unsupported (`JL0006`) | — |
|
|
117
117
|
| expression methods | `eq ne lt le gt ge` → `$eq…$ge`; `and or not`; `add sub mul div idiv mod neg`; `startsWith endsWith contains matches upper lower length concat substring replace` → §8.7; `count sum avg min max` → §8.8 (aggregates as expressions, e.g. over a group); `year month day epoch` → §8.13; `exists isEmpty`; `at all get` | native | on `Expr<…>`, per the typed-surface order |
|
|
118
118
|
| spatial family (§8.14) | `bbox geoArea geoLength centroid` → `$bbox $area $length $centroid`; `distance within bboxIntersects` → `$distance $within $bbox-intersects`; `geohash(precision?)` → `$geohash` (optional arity, like `substring`); `geoParse geoText geohashBounds geohashNeighbours` → the conversion family; `geoSimplify(tolerance)` → `$geo-simplify`. A plain JSON polygon embeds as a literal (`p.at.within(poly)`); `.params({ region })` makes it an external instead | native | on `Expr<…>`, per the typed-surface order |
|
|
119
|
+
| vector family (§8.15) | `similarity(other)` → `$similarity`. The other operand is an array of numbers: a captured one embeds as a literal, `.params({ query })` binds it at call time. There is no `knn` method — k-nearest is `orderByDescending(...).take(k)`, which is the composition the emitted document already is | native | on `Expr<…>`, per the typed-surface order |
|
|
119
120
|
|
|
120
121
|
Two spatial names are deliberately not the obvious ones, and the reason
|
|
121
122
|
is the same one that made §8.14's `$length` and §8.7's `$string-length`
|
|
@@ -130,7 +131,31 @@ names the family the way `geoParse`/`geoText` already do.
|
|
|
130
131
|
Every method name shadows a data member of the same name — that is what
|
|
131
132
|
the null prototype on the method table is for, and what `get(name)`
|
|
132
133
|
escapes. A position stored as `at` is the case that bites: `p.at` is the
|
|
133
|
-
index method, so it reads `p.get('at').within(region)`.
|
|
134
|
+
index method, so it reads `p.get('at').within(region)`. A stored score
|
|
135
|
+
named `similarity` is the same bite with a worse error — `r.similarity`
|
|
136
|
+
is the *method*, so calling it as a member yields a `TypeError` about a
|
|
137
|
+
function rather than a coded build error, because the surface never sees
|
|
138
|
+
a member access at all. `r.get('similarity')` reads the data.
|
|
139
|
+
|
|
140
|
+
**k-nearest is a chain, not a method.** `similarity()` is one operator
|
|
141
|
+
and the ordering and the window are stages that already exist, so the
|
|
142
|
+
top k reads as what it is:
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
from(memories)
|
|
146
|
+
.params({ query })
|
|
147
|
+
.orderByDescending((m, p) => m.embedding.similarity(p.query), { empty: 'least' })
|
|
148
|
+
.thenBy((m) => m.id)
|
|
149
|
+
.take(10)
|
|
150
|
+
.select((m) => m.text)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`{ empty: 'least' }` under a descending sort puts the rows whose key is
|
|
154
|
+
empty — no vector, or one of the wrong width — **last**, and `thenBy` on
|
|
155
|
+
the identity breaks ties, so the chain answers the same rows in the same
|
|
156
|
+
order every time it runs. `.params({ query })` rather than a captured
|
|
157
|
+
array is what makes the emitted document one query for every question,
|
|
158
|
+
which is the shape a provider can push down.
|
|
134
159
|
|
|
135
160
|
## 5. Deferred execution and re-enumeration
|
|
136
161
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jarenjs/linq",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.46.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"types": "./types/index.d.ts",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"prepack": "npm run build:types"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@jarenjs/core": "^0.
|
|
51
|
-
"@jarenjs/json": "^0.
|
|
50
|
+
"@jarenjs/core": "^0.46.4",
|
|
51
|
+
"@jarenjs/json": "^0.46.4"
|
|
52
52
|
}
|
|
53
53
|
}
|
package/src/expression.js
CHANGED
|
@@ -231,6 +231,11 @@ const METHODS = {
|
|
|
231
231
|
geohashBounds: unary('$geohash-bounds'),
|
|
232
232
|
geohashNeighbours: unary('$geohash-neighbours'),
|
|
233
233
|
geoSimplify: binary('$geo-simplify'),
|
|
234
|
+
// §8.15 vectors. One method for one operator: the metric is cosine
|
|
235
|
+
// and there is no distance spelling to choose between. A member
|
|
236
|
+
// literally named `similarity` is read with `get('similarity')`, the
|
|
237
|
+
// same escape every method name needs.
|
|
238
|
+
similarity: binary('$similarity'),
|
|
234
239
|
geohash(record, precision) {
|
|
235
240
|
const args = precision === undefined
|
|
236
241
|
? record.doc
|