Support column references that traverse into JSON/JSONB values —
data->>'x', data#>>'{a,b}', data->'a'->>'b', and the dotted data.a.b
shorthand — in SELECT column lists, WHERE filters and ORDER BY, across
the restheadspec, resolvespec, websocketspec and mqttspec handlers.
- pkg/common/json_column.go: canonical ParseColumnRef + ColumnRef.SQL()
builder. JSON path segments are bound as a single ?::text[] parameter,
never interpolated; cast targets are whitelisted via NormalizeCastTarget.
- pkg/common/json_condition.go: shared entry points mirroring
BuildSpatialCondition - ResolveJSONColumnExpr (select/sort),
BuildJSONFilterCondition (where, full operator set; infers ::numeric for
ordered comparisons on numeric values when no explicit cast is given),
and the ApplySelectColumns helper.
- pkg/reflection.IsJSONColumn / pkg/spectypes.IsJSONType: disambiguate the
dotted shorthand (data.city is JSON only when the base is a JSON column).
- pkg/common/validation.go: ColumnValidator accepts JSON tokens.
- Handlers: thread model through the filter call chains and wire the
select/sort paths.
funcspec (raw-SQL string builder, no param binding or model) and the
FetchRowNumber raw-SQL builders are left as follow-ups, as is OpenAPI
reporting of JSON sub-field columns.
MarshalJSON and Value now emit time.RFC3339 instead of a naive
YYYY-MM-DDTHH:MM:SS layout, so timezone offset is preserved in JSON
and DB writes. UnmarshalJSON zero-check made offset-agnostic.
RefreshToken() hardcoded LoginResponse{Token: userCtx.SessionID, ExpiresIn: 24h}
and silently discarded anything else resolvespec_refresh_token returned. An
implementation that issues its own independent, rotating refresh token (not
just reusing the session/access token as its own refresh token) has nowhere
else to put the new refresh token and real access-token expiry than
UserContext.Claims, since UserContext has no dedicated fields for either.
Now reads claims.refresh_token/claims.expires_in when present and surfaces
them into LoginResponse.RefreshToken/ExpiresIn. Implementations that don't
set these claims keep today's behavior unchanged (empty RefreshToken, 24h
ExpiresIn default) — purely additive, no breaking change.
* Implemented 'contains' operator using BuildArrayOverlapCondition for real array containment.
* Updated documentation to clarify differences between text-cast ILIKE and array overlap.
* Add tryLock and tryRLock methods to manage mutex access
* Update Register, Clear, and Execute methods to handle locked state
* Log errors when registry operations fail due to locking
Add client_secret_basic/client_secret_post client authentication, the
client_credentials grant (RFC 6749 §4.4, backed by a synthetic
service-account user so it reuses the existing session/introspection/RLS
pipeline unchanged), RFC 9728 protected resource metadata, and OIDC
discovery + JWKS + id_token/userinfo support.
Remove plan_oauth.md, which was only meant as a working handoff doc.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a BeforeOp HookType across resolvespec, restheadspec, websocketspec,
mqttspec, and funcspec that fires before every SQL operation (read,
create, update, delete, scan/query) via a new ExecuteBeforeOp helper.
Also closes a row-level-security gap: resolvespec registered a BeforeScan
hook for ApplyRowSecurity but never fired it, and websocketspec/mqttspec
had no BeforeScan hook point at all, so row security was never applied
to their queries. BeforeScan now fires right before the actual scan in
all three, with the (possibly hook-modified) query used for execution.
BeforeRead/BeforeCreate hooks (used to set session-scoped RLS GUCs) were
firing against the pooled db handle while the actual queries ran as
separate calls to the same pool. Under connection pooling these could
land on different physical connections, silently bypassing row-level
security on creates and reads. handleUpdate already did this correctly;
handleRead/handleCreate in both resolvespec and restheadspec now wrap
hook execution and queries in a single RunInTransaction call.
BeforeScan (restheadspec handleUpdate) and BeforeResponse (funcspec
list/single query handlers) fire after RunInTransaction commits, but
hookCtx.Tx still pointed at the now-dead transaction. Any hook that
executed a query against Tx (e.g. setUserViaContext) failed with
"sql: transaction has already been committed or rolled back".
* Introduced QueryMode to select between stored procedure and direct SQL execution.
* Implemented dbCapability to probe for stored procedure existence.
* Added table names configuration for direct SQL operations.
* Updated DatabaseTwoFactorProvider to support query mode and table names.
* Implemented direct SQL methods mirroring stored procedures for TOTP operations.
* Added tests for query mode logic and table names validation.
* Reflect request origin for Access-Control-Allow-Origin
* Set Vary header for caching based on origin
* Allow specific headers from preflight requests
* Enable credentials only for specific origins
* change Content-Range format to include 'items'
* add X-Api-Range-From and X-Api-Modelname headers
* add X-Api-Range-Etotal header for total filtered items
* Add support for BETWEEN-aware AND detection
* Ensure AND inside single-quoted strings does not cause splits
* Update tests to cover new BETWEEN and quote scenarios
* added checks for valid _request values in single and multiple relations
* introduced isValidNestedRequest function to encapsulate validation logic
fix(crud): expand operation handling for nested CUD
* added "add" to insert operations and "modify" to update operations
* included "remove" in delete operations