mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-09-12 19:32:36 +00:00
feat: add JSON/JSONB sub-field select, filter and sort
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.
This commit is contained in:
@@ -91,3 +91,9 @@ func IsVectorType(t reflect.Type) bool {
|
||||
n, ok := SQLTypeName(t)
|
||||
return ok && (n == "vector" || n == "halfvec" || n == "sparsevec")
|
||||
}
|
||||
|
||||
// IsJSONType reports whether t is a spectypes JSON/JSONB wrapper.
|
||||
func IsJSONType(t reflect.Type) bool {
|
||||
n, ok := SQLTypeName(t)
|
||||
return ok && (n == "jsonb" || n == "json")
|
||||
}
|
||||
|
||||
@@ -51,6 +51,20 @@ func TestIsSpatialType(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsJSONType(t *testing.T) {
|
||||
if !IsJSONType(reflect.TypeOf(SqlJSONB{})) {
|
||||
t.Error("SqlJSONB should be a JSON type")
|
||||
}
|
||||
if !IsJSONType(reflect.TypeOf(&SqlJSONB{})) {
|
||||
t.Error("*SqlJSONB should be a JSON type (pointer unwrapped)")
|
||||
}
|
||||
for _, v := range []any{SqlGeometry{}, SqlVector{}, SqlString{}, SqlStringArray{}, ""} {
|
||||
if IsJSONType(reflect.TypeOf(v)) {
|
||||
t.Errorf("%T should not be a JSON type", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsVectorType(t *testing.T) {
|
||||
for _, v := range []any{SqlVector{}, SqlHalfVector{}, SqlSparseVector{}} {
|
||||
if !IsVectorType(reflect.TypeOf(v)) {
|
||||
|
||||
Reference in New Issue
Block a user