github.com/dolthub/go-mysql-server@v0.18.0/sql/expression/function/json/json_object.go (about) 1 // Copyright 2021 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 "strings" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 "github.com/dolthub/go-mysql-server/sql/types" 23 ) 24 25 // JSON_OBJECT([key, val[, key, val] ...]) 26 // https://dev.mysql.com/doc/refman/8.0/en/json-creation-functions.html#function_json-object 27 28 // JSONObject Evaluates a (possibly empty) list of key-value pairs and returns a JSON object containing those pairs. An 29 // error occurs if any key name is NULL or the number of arguments is odd. 30 type JSONObject struct { 31 keyValPairs []sql.Expression 32 } 33 34 var _ sql.FunctionExpression = JSONObject{} 35 var _ sql.CollationCoercible = JSONObject{} 36 37 // NewJSONObject creates a new JSONObject function. 38 func NewJSONObject(exprs ...sql.Expression) (sql.Expression, error) { 39 if len(exprs)%2 != 0 { 40 return nil, sql.ErrInvalidArgumentNumber.New("JSON_OBJECT", "an even number of", len(exprs)) 41 } 42 43 return JSONObject{keyValPairs: exprs}, nil 44 } 45 46 // FunctionName implements sql.FunctionExpression 47 func (j JSONObject) FunctionName() string { 48 return "json_object" 49 } 50 51 // Description implements sql.FunctionExpression 52 func (j JSONObject) Description() string { 53 return "creates JSON object." 54 } 55 56 // IsUnsupported implements sql.UnsupportedFunctionStub 57 func (j JSONObject) IsUnsupported() bool { 58 return false 59 } 60 61 func (j JSONObject) Resolved() bool { 62 for _, child := range j.Children() { 63 if child != nil && !child.Resolved() { 64 return false 65 } 66 } 67 68 return true 69 } 70 71 func (j JSONObject) String() string { 72 children := j.Children() 73 var parts = make([]string, len(children)) 74 75 for i, c := range children { 76 parts[i] = c.String() 77 } 78 79 return fmt.Sprintf("%s(%s)", j.FunctionName(), strings.Join(parts, ",")) 80 } 81 82 func (j JSONObject) Type() sql.Type { 83 return types.JSON 84 } 85 86 // CollationCoercibility implements the interface sql.CollationCoercible. 87 func (JSONObject) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 88 return ctx.GetCharacterSet().BinaryCollation(), 2 89 } 90 91 func (j JSONObject) IsNullable() bool { 92 return false 93 } 94 95 func (j JSONObject) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) { 96 obj := make(map[string]interface{}, len(j.keyValPairs)/2) 97 98 var key string 99 for i, expr := range j.keyValPairs { 100 val, err := expr.Eval(ctx, row) 101 if err != nil { 102 return nil, err 103 } 104 if i%2 == 0 { 105 val, _, err := types.LongText.Convert(val) 106 if err != nil { 107 return nil, err 108 } 109 key = val.(string) 110 } else { 111 if json, ok := val.(sql.JSONWrapper); ok { 112 val = json.ToInterface() 113 } 114 obj[key] = val 115 } 116 } 117 118 return types.JSONDocument{Val: obj}, nil 119 } 120 121 func (j JSONObject) Children() []sql.Expression { 122 return j.keyValPairs 123 } 124 125 func (j JSONObject) WithChildren(children ...sql.Expression) (sql.Expression, error) { 126 if len(j.Children()) != len(children) { 127 return nil, fmt.Errorf("json_object did not receive the correct amount of args") 128 } 129 130 return NewJSONObject(children...) 131 }