MCPcopy Create free account
hub / github.com/PostHog/duckgres / looksJSON

Function looksJSON

transpiler/transform/operators.go:656–693  ·  view source on GitHub ↗

looksJSON reports whether a node is syntactically JSON: a cast to json/jsonb, a JSON-returning json* function call (including the json_extract calls this transform produces from -> / ->>), a JSON-producing conversion function (to_json/to_jsonb/row_to_json/array_to_json), or a `->` A_Expr (which this

(node *pg_query.Node)

Source from the content-addressed store, hash-verified

654// `json_extract_string(d,'a') || 'x'` is plain text concat in Postgres and
655// must stay that way (likewise `->>`, which yields text, does not count).
656func looksJSON(node *pg_query.Node) bool {
657 if node == nil {
658 return false
659 }
660 if tc := node.GetTypeCast(); tc != nil && tc.TypeName != nil && len(tc.TypeName.Names) > 0 {
661 if last := tc.TypeName.Names[len(tc.TypeName.Names)-1].GetString_(); last != nil {
662 switch strings.ToLower(last.Sval) {
663 case "json", "jsonb":
664 return true
665 }
666 }
667 }
668 if fc := node.GetFuncCall(); fc != nil && len(fc.Funcname) > 0 {
669 if last := fc.Funcname[len(fc.Funcname)-1].GetString_(); last != nil {
670 name := strings.ToLower(last.Sval)
671 if strings.HasPrefix(name, "json") && !jsonFuncReturnsNonJSON(name) {
672 return true
673 }
674 // JSON-producing conversions whose names don't start with "json".
675 // FunctionTransform (which runs earlier) maps to_jsonb -> to_json,
676 // but cover the Postgres spellings too for direct/standalone use.
677 switch name {
678 case "to_json", "to_jsonb", "row_to_json", "array_to_json":
679 return true
680 }
681 }
682 }
683 // A bare `d -> 'a'` operand (no cast, not yet rewritten): the arrow always
684 // becomes json_extract, which returns JSON. Without this, `(d->'a') ||
685 // (d->'b')` would fall through to DuckDB string concat of two JSON values.
686 if ae := node.GetAExpr(); ae != nil && ae.Kind == pg_query.A_Expr_Kind_AEXPR_OP &&
687 ae.Lexpr != nil && ae.Rexpr != nil && len(ae.Name) == 1 {
688 if s := ae.Name[0].GetString_(); s != nil && s.Sval == "->" {
689 return true
690 }
691 }
692 return false
693}
694
695// jsonFuncReturnsNonJSON reports whether a json*-named function returns a
696// non-JSON value (VARCHAR, BIGINT, BOOLEAN, ...), so its result concatenated

Callers 1

transformExpressionMethod · 0.85

Calls 1

jsonFuncReturnsNonJSONFunction · 0.85

Tested by

no test coverage detected