// Package value holds the GQL engine's runtime values -- what the executor // produces and expressions evaluate to. Distinct from the engine's columnar // chickpeas.Value (a 4-kind stored scalar): a runtime value can also be a // list, map, path, temporal, or a bound node/rel handle. Port of the Rust // cypher crate's Value<'g>; Go strings are immutable shared references, so // the 'g borrow lifetime disappears.
package value import ( chickpeas ) // Kind discriminates a Value. type Kind uint8 const ( // KindNull is the absent/unknown value; the zero Value is Null. KindNull Kind = iota // KindBool is a boolean value. KindBool // KindInt is a 64-bit integer value. KindInt // KindFloat is a 64-bit float value. KindFloat // KindStr is a string value. KindStr // KindList is a list value, e.g. the right-hand side of IN [...]. KindList // KindNode is a bound graph node -- RETURN n yields this. KindNode // KindRel is a bound relationship, identified by its outgoing-CSR // position (a chickpeas.RelRef.Pos). KindRel // KindPath is a path: the node sequence plus the CSR positions of the // relationships between consecutive nodes (len(rels) == len(nodes)-1). KindPath // KindMap is a map value with entries in insertion order; equality is // by content regardless of order. KindMap // KindTemporal is a date/datetime/localdatetime, epoch-millis-backed. KindTemporal // KindDuration is a duration by calendar components (months, days, // millis); equatable but not totally ordered. KindDuration ) // TemporalKind says which temporal a KindTemporal value is. All are epoch // milliseconds (UTC) under the hood; the kind only affects display. // Date is midnight UTC of the day. type TemporalKind uint8 const ( // Date is a calendar date (midnight UTC). Date TemporalKind = iota // DateTime is a zoned datetime (treated as UTC). DateTime // LocalDateTime is a wall-clock datetime. LocalDateTime ) // MapEntry is one key/value pair of a map value, in insertion order. type MapEntry struct { Key string Val Value } // ext carries the payloads that don't fit the inline word: list elements, // map entries, path sequences, and a duration's calendar components. type ext struct { list []Value entries []MapEntry nodes []chickpeas.NodeID rels []uint32 months int64 days int64 } // Value is one runtime value. The zero Value is Null. Scalars store their // payload inline (num holds the int64 bits, float bits, bool, node id, rel // position, or temporal millis); strings ride in str; lists, maps, paths, // and durations share the ext pointer. type Value struct { kind Kind aux uint8 num uint64 str string ext *ext } // Null is the absent/unknown value (same as the zero Value). func () Value { return Value{} } // Bool is a boolean value. func ( bool) Value { var uint64 if { = 1 } return Value{kind: KindBool, num: } } // Int is an integer value. func ( int64) Value { return Value{kind: KindInt, num: uint64()} } // Float is a float value. func ( float64) Value { return Value{kind: KindFloat, num: math.Float64bits()} } // Str is a string value. The string is referenced, not copied -- a property // read from the immutable snapshot shares the interner's text. func ( string) Value { return Value{kind: KindStr, str: } } // List is a list value; the slice is taken by reference, not copied. func ( []Value) Value { return Value{kind: KindList, ext: &ext{list: }} } // Node is a bound graph node. func ( chickpeas.NodeID) Value { return Value{kind: KindNode, num: uint64()} } // Rel is a bound relationship by outgoing-CSR position. func ( uint32) Value { return Value{kind: KindRel, num: uint64()} } // Path is a path value over a node sequence and the relationship positions // between consecutive nodes; both slices are taken by reference. func ( []chickpeas.NodeID, []uint32) Value { return Value{kind: KindPath, ext: &ext{nodes: , rels: }} } // Map is a map value; entries keep insertion order and are taken by // reference. func ( []MapEntry) Value { return Value{kind: KindMap, ext: &ext{entries: }} } // Temporal is an epoch-millis temporal of the given kind. func ( int64, TemporalKind) Value { return Value{kind: KindTemporal, aux: uint8(), num: uint64()} } // Duration is a duration by calendar components. func (, , int64) Value { return Value{kind: KindDuration, num: uint64(), ext: &ext{months: , days: }} } // Kind reports the value's discriminant. func ( Value) () Kind { return .kind } // IsNull reports whether the value is Null. func ( Value) () bool { return .kind == KindNull } // IsTruthy is the truthiness WHERE and the boolean operators use: only // Bool(true) is true; Null and non-booleans are not-true. func ( Value) () bool { return .kind == KindBool && .num != 0 } // AsBool returns the boolean payload; ok is false for other kinds. func ( Value) () (bool, bool) { return .num != 0, .kind == KindBool } // AsInt returns the integer payload; ok is false for other kinds. func ( Value) () (int64, bool) { return int64(.num), .kind == KindInt } // AsFloat returns the numeric payload as a float, coercing an integer; ok // is false for non-numeric kinds. func ( Value) () (float64, bool) { return .asNum() } // AsStr returns the string payload; ok is false for other kinds. func ( Value) () (string, bool) { return .str, .kind == KindStr } // AsList returns the list elements; ok is false for other kinds. func ( Value) () ([]Value, bool) { if .kind != KindList { return nil, false } return .ext.list, true } // AsNode returns the bound node id; ok is false for other kinds. func ( Value) () (chickpeas.NodeID, bool) { return chickpeas.NodeID(.num), .kind == KindNode } // AsRel returns the bound relationship's CSR position; ok is false for // other kinds. func ( Value) () (uint32, bool) { return uint32(.num), .kind == KindRel } // AsPath returns the path's node sequence and relationship positions; ok is // false for other kinds. func ( Value) () ( []chickpeas.NodeID, []uint32, bool) { if .kind != KindPath { return nil, nil, false } return .ext.nodes, .ext.rels, true } // AsMap returns the map entries in insertion order; ok is false for other // kinds. func ( Value) () ([]MapEntry, bool) { if .kind != KindMap { return nil, false } return .ext.entries, true } // AsTemporal returns the temporal's epoch millis and kind; ok is false for // other kinds. func ( Value) () ( int64, TemporalKind, bool) { return int64(.num), TemporalKind(.aux), .kind == KindTemporal } // AsDuration returns the duration's components; ok is false for other kinds. func ( Value) () (, , int64, bool) { if .kind != KindDuration { return 0, 0, 0, false } return .ext.months, .ext.days, int64(.num), true } // asNum is the shared numeric coercion: Int and Float read as float64, // everything else is non-numeric. func ( Value) () (float64, bool) { switch .kind { case KindInt: return float64(int64(.num)), true case KindFloat: return math.Float64frombits(.num), true default: return 0, false } } // NumericTwin is the other numeric spelling of v that value.Compare // treats as equal: an integral float's int, an int's float. The property // index keys stored values exactly, while comparison coerces int against // float through float64 -- so an index probe for one spelling must also // probe the twin or rows whose stored type differs from the literal's // are silently lost. Bounded to |v| <= 2^53, where the int<->float // mapping is exact and bijective; beyond it no twin is reported (the // conversion rounds, so a probe would ask about a different number). func ( Value) (Value, bool) { const = int64(1) << 53 if , := .AsInt(); && .Kind() == KindInt { if >= - && <= { return Float(float64()), true } return Value{}, false } if .Kind() == KindFloat { , := .AsFloat() if == float64(int64()) && >= -float64() && <= float64() { return Int(int64()), true } } return Value{}, false }