// Find implements the charlatan.Record interface func (r *JSONRecord) Find(field *ch.Field) (*ch.Const, error) { var ok bool var partial *json.RawMessage var name string if name = field.Name(); len(name) == 0 { return nil, errEmptyField } // support for "SELECT *" if name == "*" { b, err := json.Marshal(r.attrs) if err != nil { return nil, err } return ch.StringConst(string(b)), nil } attrs := r.attrs parts := strings.Split(name, ".") for i, k := range parts { partial, ok = attrs[k] if !ok { if r.SoftMatching { return ch.NullConst(), nil } return nil, fmt.Errorf("Unknown '%s' field (in '%s')", k, field.Name()) } // update the attrs if we need to go deeper if i < len(parts)-1 { attrs = make(map[string]*json.RawMessage) if err := json.Unmarshal(*partial, &attrs); err != nil { if r.SoftMatching { return ch.NullConst(), nil } return nil, err } } } return jsonToConst(partial) }
// AtIndex gets the value at the given index func (r *CSVRecord) AtIndex(index int) (*ch.Const, error) { if index < 0 || index > len(r.record) { return nil, fmt.Errorf("index out of bounds %d", index) } // FIXME should we accept NULL values? value := r.record[index] if value == "NULL" { return ch.NullConst(), nil } return ch.ConstFromString(value), nil }
func jsonToConst(partial *json.RawMessage) (*ch.Const, error) { var value string if partial == nil { return ch.NullConst(), nil } asString := string(*partial) if asString == "null" { return ch.NullConst(), nil } if err := json.Unmarshal(*partial, &value); err != nil { if err, ok := err.(*json.UnmarshalTypeError); ok { // we failed to unmarshal into a string, let's try the other types switch err.Value { case "number": var n json.Number if err := json.Unmarshal(*partial, &n); err != nil { return nil, err } value = n.String() case "bool": value = asString default: return nil, err } } } return ch.ConstFromString(value), nil }