mirror of
https://github.com/hanzoai/graph.git
synced 2026-10-30 18:35:37 +00:00
Derived from Dgraph (github.com/dgraph-io/dgraph) at commit 64804bd2, Apache-2.0. See NOTICE. WHAT THIS IS. The graph engine as a Go library: posting lists, the DQL parser, the type and tokenizer system, the index and schema layers, and the wire types. 39,170 lines of the upstream's 166,337. THE STORE is github.com/luxfi/zapdb, a Badger fork that kept the package name, the subpackages (options, pb, y) and the API — Open, OpenManaged, DB, Options — so the 74 import sites are aliased rather than rewritten. THE CODEC is ZAP. zapdb serializes with ZAP, not protobuf: its pb package builds the ZAP types by default and the protobuf ones only under `-tags grpc`, a path that does not compile (table/builder.go calls pb.Marshal, which that tag removes). One call site in posting needed converting; every other type here is Hanzo's own protobuf and is untouched. NO TRANSPORT. An embedded engine dials nothing, so nothing here imports google.golang.org/grpc. Removed: 20 transport functions in x, the generated service stubs for Raft, Zero and Worker (1,657 lines), and the JWT helper — identity belongs to IAM. The core called none of them. NOT KEPT: worker, conn, raftwal, the cluster commands, the GraphQL layer and the test harnesses. `query`, the DQL execution engine, went with them because it depends on worker; parsing DQL is available here, executing it is not. The history of the upstream project lives at github.com/dgraph-io/dgraph. This repository begins at the derivation because three quarters of that history describes code this fork does not carry.
243 lines
5.9 KiB
Go
243 lines
5.9 KiB
Go
/*
|
|
* SPDX-FileCopyrightText: © 2017-2026 Istari Digital, Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package types
|
|
|
|
import (
|
|
"math/big"
|
|
"time"
|
|
|
|
"github.com/twpayne/go-geom"
|
|
|
|
"github.com/hanzoai/graph/protos/pb"
|
|
)
|
|
|
|
const (
|
|
dateFormatY = "2006" // time.longYear
|
|
dateFormatYM = "2006-01"
|
|
dateFormatYMD = "2006-01-02"
|
|
dateFormatYMDZone = "2006-01-02 15:04:05 -0700 MST"
|
|
dateTimeFormat = "2006-01-02T15:04:05"
|
|
)
|
|
|
|
const (
|
|
nanoSecondsInSec = 1000000000
|
|
BigFloatPrecision = 200
|
|
)
|
|
|
|
// Note: These ids are stored in the posting lists to indicate the type
|
|
// of the data. The order *cannot* be changed without breaking existing
|
|
// data. When adding a new type *always* add to the end of this list.
|
|
// Never delete anything from this list even if it becomes unused.
|
|
const (
|
|
// DefaultID represents the default type.
|
|
DefaultID = TypeID(pb.Posting_DEFAULT)
|
|
// BinaryID represents the binary data type.
|
|
BinaryID = TypeID(pb.Posting_BINARY)
|
|
// IntID represents the integer type.
|
|
IntID = TypeID(pb.Posting_INT)
|
|
// FloatID represents the floating-point number type.
|
|
FloatID = TypeID(pb.Posting_FLOAT)
|
|
// BoolID represents the boolean type.
|
|
BoolID = TypeID(pb.Posting_BOOL)
|
|
// DateTimeID represents the datetime type.
|
|
DateTimeID = TypeID(pb.Posting_DATETIME)
|
|
// GeoID represents the geo-location data type.
|
|
GeoID = TypeID(pb.Posting_GEO)
|
|
// UidID represents the uid type.
|
|
UidID = TypeID(pb.Posting_UID)
|
|
// PasswordID represents the password type.
|
|
PasswordID = TypeID(pb.Posting_PASSWORD)
|
|
// StringID represents the string type.
|
|
StringID = TypeID(pb.Posting_STRING)
|
|
// TODO: Add constant for pb.Posting_OBJECT ??
|
|
// Not clear if it belongs here, but if it does,
|
|
// we should add it, if not, we should document here
|
|
// why it does not belong here.
|
|
// VFloatID represents a vector of IEEE754 64-bit floats.
|
|
VFloatID = TypeID(pb.Posting_VFLOAT)
|
|
// UndefinedID represents the undefined type.
|
|
UndefinedID = TypeID(100)
|
|
// BigFloatID represents the arbitrary precision type.
|
|
BigFloatID = TypeID(pb.Posting_BIGFLOAT)
|
|
)
|
|
|
|
var typeNameMap = map[string]TypeID{
|
|
"default": DefaultID,
|
|
"binary": BinaryID,
|
|
"int": IntID,
|
|
"float": FloatID,
|
|
"bool": BoolID,
|
|
"datetime": DateTimeID,
|
|
"geo": GeoID,
|
|
"uid": UidID,
|
|
"string": StringID,
|
|
"password": PasswordID,
|
|
"bigfloat": BigFloatID,
|
|
"float32vector": VFloatID,
|
|
}
|
|
|
|
// TypeID represents the type of the data.
|
|
type TypeID pb.Posting_ValType
|
|
|
|
// Enum takes a TypeID value and returns the corresponding ValType enum value.
|
|
func (t TypeID) Enum() pb.Posting_ValType {
|
|
return pb.Posting_ValType(t)
|
|
}
|
|
|
|
// Name returns the name of the type.
|
|
func (t TypeID) Name() string {
|
|
switch t {
|
|
case DefaultID:
|
|
return "default"
|
|
case BinaryID:
|
|
return "binary"
|
|
case IntID:
|
|
return "int"
|
|
case FloatID:
|
|
return "float"
|
|
case BoolID:
|
|
return "bool"
|
|
case DateTimeID:
|
|
return "datetime"
|
|
case GeoID:
|
|
return "geo"
|
|
case UidID:
|
|
return "uid"
|
|
case StringID:
|
|
return "string"
|
|
case PasswordID:
|
|
return "password"
|
|
case BigFloatID:
|
|
return "bigfloat"
|
|
case VFloatID:
|
|
return "float32vector"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Val is a value with type information.
|
|
type Val struct {
|
|
Tid TypeID
|
|
Value interface{}
|
|
}
|
|
|
|
// Safe ensures that Val's Value is not nil. This is useful when doing type
|
|
// assertions and default values might be involved.
|
|
// This function won't change the original v.Value, may it be nil.
|
|
// See: "Default value vars" in `fillVars()`
|
|
// Returns a safe v.Value suitable for type assertions.
|
|
func (v Val) Safe() interface{} {
|
|
if v.Value == nil {
|
|
// get zero value for this v.Tid
|
|
va := ValueForType(v.Tid)
|
|
return va.Value
|
|
}
|
|
return v.Value
|
|
}
|
|
|
|
// TypeForName returns the type corresponding to the given name.
|
|
// If name is not recognized, it returns nil.
|
|
func TypeForName(name string) (TypeID, bool) {
|
|
t, ok := typeNameMap[name]
|
|
return t, ok
|
|
}
|
|
|
|
// IsScalar returns whether the type is a scalar type.
|
|
func (t TypeID) IsScalar() bool {
|
|
return t != UidID
|
|
}
|
|
|
|
// IsNumber returns whether the type is a number type.
|
|
func (t TypeID) IsNumber() bool {
|
|
return t == IntID || t == FloatID
|
|
}
|
|
|
|
// ValueForType returns the zero value for a type id
|
|
func ValueForType(id TypeID) Val {
|
|
switch id {
|
|
case BinaryID:
|
|
var b []byte
|
|
return Val{BinaryID, &b}
|
|
|
|
case IntID:
|
|
var i int64
|
|
return Val{IntID, &i}
|
|
|
|
case FloatID:
|
|
var f float64
|
|
return Val{FloatID, &f}
|
|
|
|
case BoolID:
|
|
var b bool
|
|
return Val{BoolID, &b}
|
|
|
|
case DateTimeID:
|
|
var t time.Time
|
|
return Val{DateTimeID, &t}
|
|
|
|
case BigFloatID:
|
|
var b big.Float
|
|
b.SetPrec(BigFloatPrecision)
|
|
return Val{BigFloatID, &b}
|
|
|
|
case StringID:
|
|
var s string
|
|
return Val{StringID, s}
|
|
|
|
case DefaultID:
|
|
var s string
|
|
return Val{DefaultID, s}
|
|
|
|
case GeoID:
|
|
var g geom.T
|
|
return Val{GeoID, &g}
|
|
|
|
case UidID:
|
|
var i uint64
|
|
return Val{UidID, &i}
|
|
|
|
case PasswordID:
|
|
var p string
|
|
return Val{PasswordID, p}
|
|
case VFloatID:
|
|
var v []float32
|
|
return Val{VFloatID, &v}
|
|
default:
|
|
return Val{}
|
|
}
|
|
}
|
|
|
|
// GoodTimeZone returns true if timezone (provided in offset
|
|
// format in seconds) is valid according to RFC3339.
|
|
func GoodTimeZone(offset int) bool {
|
|
const boundary = 23*60*60 + 59*60
|
|
return offset <= boundary && offset >= -1*boundary
|
|
}
|
|
|
|
// ParseTime parses the time from string trying various datetime formats.
|
|
// By default, Go parses time in UTC unless specified in the data itself.
|
|
func ParseTime(val string) (time.Time, error) {
|
|
if len(val) == len(dateFormatY) {
|
|
return time.Parse(dateFormatY, val)
|
|
}
|
|
if len(val) == len(dateFormatYM) {
|
|
return time.Parse(dateFormatYM, val)
|
|
}
|
|
if len(val) == len(dateFormatYMD) {
|
|
return time.Parse(dateFormatYMD, val)
|
|
}
|
|
if len(val) > len(dateTimeFormat) && val[len(dateFormatYMD)] == 'T' &&
|
|
(val[len(val)-1] == 'Z' || val[len(val)-3] == ':') {
|
|
// https://tools.ietf.org/html/rfc3339#section-5.6
|
|
return time.Parse(time.RFC3339, val)
|
|
}
|
|
if t, err := time.Parse(dateFormatYMDZone, val); err == nil {
|
|
return t, err
|
|
}
|
|
// Try without timezone.
|
|
return time.Parse(dateTimeFormat, val)
|
|
}
|