github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/json/json_depth.go (about) 1 // Copyright 2024 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package json 16 17 import ( 18 "fmt" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 "github.com/dolthub/go-mysql-server/sql/types" 22 ) 23 24 // JSONDepth (json_doc) 25 // 26 // JSONDepth Returns the maximum depth of a JSON document. Returns NULL if the argument is NULL. An error occurs if the 27 // argument is not a valid JSON document. An empty array, empty object, or scalar value has depth 1. A nonempty array 28 // containing only elements of depth 1 or nonempty object containing only member values of depth 1 has depth 2. 29 // Otherwise, a JSON document has depth greater than 2. 30 // 31 // https://dev.mysql.com/doc/refman/8.0/en/json-attribute-functions.html#function_json-depth 32 type JSONDepth struct { 33 JSON sql.Expression 34 } 35 36 var _ sql.FunctionExpression = &JSONDepth{} 37 38 // NewJSONDepth creates a new JSONDepth function. 39 func NewJSONDepth(args ...sql.Expression) (sql.Expression, error) { 40 if len(args) != 1 { 41 return nil, sql.ErrInvalidArgumentNumber.New("JSON_DEPTH", "1", len(args)) 42 } 43 return &JSONDepth{JSON: args[0]}, nil 44 } 45 46 // FunctionName implements sql.FunctionExpression interface. 47 func (j JSONDepth) FunctionName() string { 48 return "json_depth" 49 } 50 51 // Description implements sql.FunctionExpression interface. 52 func (j JSONDepth) Description() string { 53 return "returns maximum depth of JSON document." 54 } 55 56 // Resolved implements sql.Expression interface. 57 func (j JSONDepth) Resolved() bool { 58 return j.JSON.Resolved() 59 } 60 61 // String implements sql.Expression interface. 62 func (j JSONDepth) String() string { 63 return fmt.Sprintf("%s(%s)", j.FunctionName(), j.JSON.String()) 64 } 65 66 // Type implements sql.Expression interface. 67 func (j JSONDepth) Type() sql.Type { 68 return types.Int64 69 } 70 71 // IsNullable implements sql.Expression interface. 72 func (j JSONDepth) IsNullable() bool { 73 return j.JSON.IsNullable() 74 } 75 76 // depth returns the maximum depth of a JSON document. 77 func depth(obj interface{}) (int, error) { 78 var maxDepth int 79 switch o := obj.(type) { 80 case []interface{}: 81 for _, v := range o { 82 d, err := depth(v) 83 if err != nil { 84 return 0, err 85 } 86 if d > maxDepth { 87 maxDepth = d 88 } 89 } 90 case map[string]interface{}: 91 for _, v := range o { 92 d, err := depth(v) 93 if err != nil { 94 return 0, err 95 } 96 if d > maxDepth { 97 maxDepth = d 98 } 99 } 100 } 101 return maxDepth + 1, nil 102 } 103 104 // Eval implements sql.Expression interface. 105 func (j JSONDepth) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 106 span, ctx := ctx.Span(fmt.Sprintf("function.%s", j.FunctionName())) 107 defer span.End() 108 109 doc, err := getJSONDocumentFromRow(ctx, row, j.JSON) 110 if err != nil { 111 return nil, err 112 } 113 if doc == nil { 114 return nil, nil 115 } 116 117 d, err := depth(doc.Val) 118 if err != nil { 119 return nil, err 120 } 121 122 return d, nil 123 } 124 125 // Children implements sql.Expression interface. 126 func (j JSONDepth) Children() []sql.Expression { 127 return []sql.Expression{j.JSON} 128 } 129 130 // WithChildren implements sql.Expression interface. 131 func (j JSONDepth) WithChildren(children ...sql.Expression) (sql.Expression, error) { 132 return NewJSONDepth(children...) 133 }