Implements `filter(where <cond>)` for aggregate functions in LIQ
queries which allows per-row conditional filtering within grouped
aggregates. Also extends test suite and documentation.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
The new null-aware ordering in `orderByCompare` changed the default
placement of undefined values for descending sorts to `nulls first` (SQL
standard). This caused Space Lua scripts without a `-- priority:`
comment to load before the `Std` library scripts and breaking the boot
sequence for user scripts ran before `schema`, `config`, `widget` and
other core definitions were available.
Add explicit `nulls: "last"` to the reload query so scripts without
priority always load last, matching the documented behavior.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
Extend the `order by` clause with optional `nulls first` and `nulls
last` modifiers following standard SQL semantics. Each sort key can
independently specify where `nil` values should appear in the result. By
default, ascending sorts place nulls last and descending sorts place
nulls first. An explicit nulls first or nulls last overrides this
default. The `asc` keyword is also now accepted as an explicit
alternative to the default ascending direction. Documentation and tests
were updated accordingly.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
Check for already-queryable objects (e.g. `DataStoreQueryCollection`)
before `LuaTable` extraction or `luaValueToJS` conversion, preventing
them from being destroyed by the collection normalization pipeline.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
- Fix `group by` key building: populate array indices from
`keyParts` instead of only from `keyRecord`, which was empty for
some expressions (e.g. `tags[1]`).
- Fix collection handling: treat record-like `LuaTables` (no array part)
as items instead of extracting zero items.
- Update test suite.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
* Fix `LUA_SQL_NULL` leaking into `order by` comparisons
Note: SQL `NULLS LAST` is now default behaviour!
* Fix `objectVariable` unset for empty groups
* Fix non-grouped `having` used wrong environment builder
Note: Queries similar to the following one now works correctly:
```sql
${query[[
from
tags.page
having
name == 'index'
]]}
```
* Fix `generateKey` did not handle `LUA_SQL_NULL`
* Refactor/deduplicate duplicated `order by` comparator
* Add `isSqlNull` helper
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
1. Fix `order by` inability to access `select` output aliases and
aggregate functions after `group by`.
2. Introduce `LUA_SQL_NULL` sentinel to preserve column ordering when
`select` expressions evaluate to `nil`.
Note: In Lua, setting a table key to `nil` deletes it so rows with
`nil` values lose those keys and produced inconsistent insertion
order across result tables.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
The `select` part operates not over a single record, but over each group
(i.e., the set of records sharing the same group key). The `select`
clause's environment is generally:
* `name` (the group key)
* `group` (the table of records in the group)
Note: no `p` is bound (`p` is not set; it was the row variable during scan, but we are now at the group level).
In the `select { name = name }` the name refers to the group key (what
we `group by`-ed).
We typically use:
* `name = name` (group key, as in the query), or
* if we want data from the first record (say all grouped `p.name` are
the same and non-`nil`) then `name = group[1].name`.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
* [LIQ] Extend with `group by` and `having` support
Also update documentation with extensive examples and add some parser
tests.
Note: `make generate` JS files included.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
* Merge `liq-add-support-for-aggregators` branch
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
* Fix link, remove `_` example
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
* Wrap example LIQ queries inside `query [[ .. ]]` and replace `sql` code block type to `lua`
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
* Example self-consistency fix
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
* Fixed some queries
* Add experimental tags to LIQ aggregation/grouping
---------
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
Co-authored-by: Zef Hemel <zef@zef.me>
* Trim user input from prompts where appropriate
* Run formatter
* Use "page title" language instead of "page name" in notifications.
Existing language in prompt asks for a "page title".
* Use const for prefix inputs as they are never trimmed
The three binary-packing functions from Lua are now implemented in
a dedicated `string_pack.ts` module and wired into `stringApi`.
Format parsing follows the exact option set of Lua:
* signed and unsigned integers of configurable width
(`b`/`B`/`h`/`H`/`l`/`L`/`j`/`J`/`T`/`i`/`I`),
* IEEE 754 single and double precision floats (`f`/`d`/`n`),
* fixed-length strings (`c`),
* length-prefixed strings (`s`),
* zero-terminated strings (`z`),
* padding bytes (`x`),
* alignment padding (`X`), and
* endianness/alignment modifiers (`<`/`>`/`=`/`!`).
`string.packsize` rejects variable-length formats (`s` and `z`) as Lua
requires.
`string.unpack` returns all unpacked values followed by the
next position integer, matching the Lua contract exactly.
Test suite extended in separates `string_pack_test.lua` file. Passes
both Lua and Space Lua execution.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
`table.pack` now routes element writes through `luaSet` so `__newindex`
metamethods are honoured, matching the exact Lua 5.4 semantics. The `n`
field is still written with `rawSet`, also matching Lua.
`table.unpack` now returns an empty `LuaMultiRes` instead of `null` for
an empty range `(i > j)`. Returning `null` would inject a single `nil`
argument at the call site; an empty `LuaMultiRes` correctly contributes
zero values, matching the exact Lua semantics.
The global `unpack` shim (for Lua 5.1 compatibility) has been removed
from `luaBuildStandardEnv`. Users who need the short alias can set it up
in `space-script` with a single line stating `unpack = table.unpack`.
Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>