diff --git a/client/descriptions.go b/client/collection_description.go similarity index 52% rename from client/descriptions.go rename to client/collection_description.go index dd12e9cf00..2e3e10aa36 100644 --- a/client/descriptions.go +++ b/client/collection_description.go @@ -1,4 +1,4 @@ -// Copyright 2022 Democratized Data Foundation +// Copyright 2024 Democratized Data Foundation // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt. @@ -67,6 +67,44 @@ type CollectionDescription struct { Indexes []IndexDescription } +// QuerySource represents a collection data source from a query. +// +// The query will be executed when data from this source is requested, and the query results +// yielded to the consumer. +type QuerySource struct { + // Query contains the base query of this data source. + Query request.Select + + // Transform is a optional Lens configuration. If specified, data drawn from the [Query] will have the + // transform applied before being returned. + // + // The transform is not limited to just transforming the input documents, it may also yield new ones, or filter out + // those passed in from the underlying query. + Transform immutable.Option[model.Lens] +} + +// CollectionSource represents a collection data source from another collection instance. +// +// Data against all collection instances in a CollectionSource chain will be returned as-if +// from the same dataset when queried. Lens transforms may be applied between instances. +// +// Typically these are used to link together multiple schema versions into the same dataset. +type CollectionSource struct { + // SourceCollectionID is the local identifier of the source [CollectionDescription] from which to + // share data. + // + // This is a bi-directional relationship, and documents in the host collection instance will also + // be available to the source collection instance. + SourceCollectionID uint32 + + // Transform is a optional Lens configuration. If specified, data drawn from the source will have the + // transform applied before being returned by any operation on the host collection instance. + // + // If the transform supports an inverse operation, that inverse will be applied when the source collection + // draws data from this host. + Transform immutable.Option[model.Lens] +} + // IDString returns the collection ID as a string. func (col CollectionDescription) IDString() string { return fmt.Sprint(col.ID) @@ -83,17 +121,6 @@ func (col CollectionDescription) GetFieldByName(fieldName string) (CollectionFie return CollectionFieldDescription{}, false } -// GetFieldByName returns the field for the given field name. If such a field is found it -// will return it and true, if it is not found it will return false. -func (s SchemaDescription) GetFieldByName(fieldName string) (SchemaFieldDescription, bool) { - for _, field := range s.Fields { - if field.Name == fieldName { - return field, true - } - } - return SchemaFieldDescription{}, false -} - // GetFieldByRelation returns the field that supports the relation of the given name. func (col CollectionDescription) GetFieldByRelation( relationName string, @@ -131,253 +158,6 @@ func sourcesOfType[ResultType any](col CollectionDescription) []ResultType { return result } -// QuerySource represents a collection data source from a query. -// -// The query will be executed when data from this source is requested, and the query results -// yielded to the consumer. -type QuerySource struct { - // Query contains the base query of this data source. - Query request.Select - - // Transform is a optional Lens configuration. If specified, data drawn from the [Query] will have the - // transform applied before being returned. - // - // The transform is not limited to just transforming the input documents, it may also yield new ones, or filter out - // those passed in from the underlying query. - Transform immutable.Option[model.Lens] -} - -// CollectionSource represents a collection data source from another collection instance. -// -// Data against all collection instances in a CollectionSource chain will be returned as-if -// from the same dataset when queried. Lens transforms may be applied between instances. -// -// Typically these are used to link together multiple schema versions into the same dataset. -type CollectionSource struct { - // SourceCollectionID is the local identifier of the source [CollectionDescription] from which to - // share data. - // - // This is a bi-directional relationship, and documents in the host collection instance will also - // be available to the source collection instance. - SourceCollectionID uint32 - - // Transform is a optional Lens configuration. If specified, data drawn from the source will have the - // transform applied before being returned by any operation on the host collection instance. - // - // If the transform supports an inverse operation, that inverse will be applied when the source collection - // draws data from this host. - Transform immutable.Option[model.Lens] -} - -// SchemaDescription describes a Schema and its associated metadata. -type SchemaDescription struct { - // Root is the version agnostic identifier for this schema. - // - // It remains constant throughout the lifetime of this schema. - Root string - - // VersionID is the version-specific identifier for this schema. - // - // It is generated on mutation of this schema and can be used to uniquely - // identify a schema at a specific version. - VersionID string - - // Name is the name of this Schema. - // - // It is currently used to define the Collection Name, and as such these two properties - // will currently share the same name. - // - // It is immutable. - Name string - - // Fields contains the fields within this Schema. - // - // Currently new fields may be added after initial declaration, but they cannot be removed. - Fields []SchemaFieldDescription -} - -// FieldKind describes the type of a field. -type FieldKind uint8 - -func (f FieldKind) String() string { - switch f { - case FieldKind_DocID: - return "ID" - case FieldKind_NILLABLE_BOOL: - return "Boolean" - case FieldKind_NILLABLE_BOOL_ARRAY: - return "[Boolean]" - case FieldKind_BOOL_ARRAY: - return "[Boolean!]" - case FieldKind_NILLABLE_INT: - return "Int" - case FieldKind_NILLABLE_INT_ARRAY: - return "[Int]" - case FieldKind_INT_ARRAY: - return "[Int!]" - case FieldKind_NILLABLE_DATETIME: - return "DateTime" - case FieldKind_NILLABLE_FLOAT: - return "Float" - case FieldKind_NILLABLE_FLOAT_ARRAY: - return "[Float]" - case FieldKind_FLOAT_ARRAY: - return "[Float!]" - case FieldKind_NILLABLE_STRING: - return "String" - case FieldKind_NILLABLE_STRING_ARRAY: - return "[String]" - case FieldKind_STRING_ARRAY: - return "[String!]" - case FieldKind_NILLABLE_BLOB: - return "Blob" - case FieldKind_NILLABLE_JSON: - return "JSON" - default: - return fmt.Sprint(uint8(f)) - } -} - -// IsObject returns true if this FieldKind is an object type. -func (f FieldKind) IsObject() bool { - return f == FieldKind_FOREIGN_OBJECT || - f == FieldKind_FOREIGN_OBJECT_ARRAY -} - -// IsObjectArray returns true if this FieldKind is an object array type. -func (f FieldKind) IsObjectArray() bool { - return f == FieldKind_FOREIGN_OBJECT_ARRAY -} - -// IsArray returns true if this FieldKind is an array type which includes inline arrays as well -// as relation arrays. -func (f FieldKind) IsArray() bool { - return f == FieldKind_BOOL_ARRAY || - f == FieldKind_INT_ARRAY || - f == FieldKind_FLOAT_ARRAY || - f == FieldKind_STRING_ARRAY || - f == FieldKind_FOREIGN_OBJECT_ARRAY || - f == FieldKind_NILLABLE_BOOL_ARRAY || - f == FieldKind_NILLABLE_INT_ARRAY || - f == FieldKind_NILLABLE_FLOAT_ARRAY || - f == FieldKind_NILLABLE_STRING_ARRAY -} - -// Note: These values are serialized and persisted in the database, avoid modifying existing values. -const ( - FieldKind_None FieldKind = 0 - FieldKind_DocID FieldKind = 1 - FieldKind_NILLABLE_BOOL FieldKind = 2 - FieldKind_BOOL_ARRAY FieldKind = 3 - FieldKind_NILLABLE_INT FieldKind = 4 - FieldKind_INT_ARRAY FieldKind = 5 - FieldKind_NILLABLE_FLOAT FieldKind = 6 - FieldKind_FLOAT_ARRAY FieldKind = 7 - _ FieldKind = 8 // safe to repurpose (was never used) - _ FieldKind = 9 // safe to repurpose (previously old field) - FieldKind_NILLABLE_DATETIME FieldKind = 10 - FieldKind_NILLABLE_STRING FieldKind = 11 - FieldKind_STRING_ARRAY FieldKind = 12 - FieldKind_NILLABLE_BLOB FieldKind = 13 - FieldKind_NILLABLE_JSON FieldKind = 14 - _ FieldKind = 15 // safe to repurpose (was never used) - - // Embedded object, but accessed via foreign keys - FieldKind_FOREIGN_OBJECT FieldKind = 16 - - // Array of embedded objects, accessed via foreign keys - FieldKind_FOREIGN_OBJECT_ARRAY FieldKind = 17 - - FieldKind_NILLABLE_BOOL_ARRAY FieldKind = 18 - FieldKind_NILLABLE_INT_ARRAY FieldKind = 19 - FieldKind_NILLABLE_FLOAT_ARRAY FieldKind = 20 - FieldKind_NILLABLE_STRING_ARRAY FieldKind = 21 -) - -// FieldKindStringToEnumMapping maps string representations of [FieldKind] values to -// their enum values. -// -// It is currently used to by [db.PatchSchema] to allow string representations of -// [FieldKind] to be provided instead of their raw int values. This usage may expand -// in the future. They currently roughly correspond to the GQL field types, but this -// equality is not guaranteed. -var FieldKindStringToEnumMapping = map[string]FieldKind{ - "ID": FieldKind_DocID, - "Boolean": FieldKind_NILLABLE_BOOL, - "[Boolean]": FieldKind_NILLABLE_BOOL_ARRAY, - "[Boolean!]": FieldKind_BOOL_ARRAY, - "Int": FieldKind_NILLABLE_INT, - "[Int]": FieldKind_NILLABLE_INT_ARRAY, - "[Int!]": FieldKind_INT_ARRAY, - "DateTime": FieldKind_NILLABLE_DATETIME, - "Float": FieldKind_NILLABLE_FLOAT, - "[Float]": FieldKind_NILLABLE_FLOAT_ARRAY, - "[Float!]": FieldKind_FLOAT_ARRAY, - "String": FieldKind_NILLABLE_STRING, - "[String]": FieldKind_NILLABLE_STRING_ARRAY, - "[String!]": FieldKind_STRING_ARRAY, - "Blob": FieldKind_NILLABLE_BLOB, - "JSON": FieldKind_NILLABLE_JSON, -} - -// RelationType describes the type of relation between two types. -type RelationType uint8 - -// FieldID is a unique identifier for a field in a schema. -type FieldID uint32 - -func (f FieldID) String() string { - return fmt.Sprint(uint32(f)) -} - -// SchemaFieldDescription describes a field on a Schema and its associated metadata. -type SchemaFieldDescription struct { - // Name contains the name of this field. - // - // It is currently immutable. - Name string - - // The data type that this field holds. - // - // Must contain a valid value. It is currently immutable. - Kind FieldKind - - // Schema contains the schema name of the type this field contains if this field is - // a relation field. Otherwise this will be empty. - Schema string - - // RelationName the name of the relationship that this field represents if this field is - // a relation field. Otherwise this will be empty. - RelationName string - - // The CRDT Type of this field. If no type has been provided it will default to [LWW_REGISTER]. - // - // It is currently immutable. - Typ CType - - // If true, this is the primary half of a relation, otherwise is false. - IsPrimaryRelation bool -} - -// CollectionFieldDescription describes the local components of a field on a collection. -type CollectionFieldDescription struct { - // Name contains the name of the [SchemaFieldDescription] that this field uses. - Name string - - // ID contains the local, internal ID of this field. - ID FieldID -} - -// IsRelation returns true if this field is a relation. -func (f SchemaFieldDescription) IsRelation() bool { - return f.RelationName != "" -} - -// IsSet returns true if the target relation type is set. -func (m RelationType) IsSet(target RelationType) bool { - return m&target > 0 -} - // collectionDescription is a private type used to facilitate the unmarshalling // of json to a [CollectionDescription]. type collectionDescription struct { diff --git a/client/collection_field_description.go b/client/collection_field_description.go new file mode 100644 index 0000000000..048cde24c0 --- /dev/null +++ b/client/collection_field_description.go @@ -0,0 +1,29 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package client + +import "fmt" + +// FieldID is a unique identifier for a field in a schema. +type FieldID uint32 + +// CollectionFieldDescription describes the local components of a field on a collection. +type CollectionFieldDescription struct { + // Name contains the name of the [SchemaFieldDescription] that this field uses. + Name string + + // ID contains the local, internal ID of this field. + ID FieldID +} + +func (f FieldID) String() string { + return fmt.Sprint(uint32(f)) +} diff --git a/client/schema_description.go b/client/schema_description.go new file mode 100644 index 0000000000..302fadf5e7 --- /dev/null +++ b/client/schema_description.go @@ -0,0 +1,49 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package client + +// SchemaDescription describes a Schema and its associated metadata. +type SchemaDescription struct { + // Root is the version agnostic identifier for this schema. + // + // It remains constant throughout the lifetime of this schema. + Root string + + // VersionID is the version-specific identifier for this schema. + // + // It is generated on mutation of this schema and can be used to uniquely + // identify a schema at a specific version. + VersionID string + + // Name is the name of this Schema. + // + // It is currently used to define the Collection Name, and as such these two properties + // will currently share the same name. + // + // It is immutable. + Name string + + // Fields contains the fields within this Schema. + // + // Currently new fields may be added after initial declaration, but they cannot be removed. + Fields []SchemaFieldDescription +} + +// GetFieldByName returns the field for the given field name. If such a field is found it +// will return it and true, if it is not found it will return false. +func (s SchemaDescription) GetFieldByName(fieldName string) (SchemaFieldDescription, bool) { + for _, field := range s.Fields { + if field.Name == fieldName { + return field, true + } + } + return SchemaFieldDescription{}, false +} diff --git a/client/schema_field_description.go b/client/schema_field_description.go new file mode 100644 index 0000000000..05b7f99a5e --- /dev/null +++ b/client/schema_field_description.go @@ -0,0 +1,171 @@ +// Copyright 2024 Democratized Data Foundation +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package client + +import "fmt" + +// FieldKind describes the type of a field. +type FieldKind uint8 + +// SchemaFieldDescription describes a field on a Schema and its associated metadata. +type SchemaFieldDescription struct { + // Name contains the name of this field. + // + // It is currently immutable. + Name string + + // The data type that this field holds. + // + // Must contain a valid value. It is currently immutable. + Kind FieldKind + + // Schema contains the schema name of the type this field contains if this field is + // a relation field. Otherwise this will be empty. + Schema string + + // RelationName the name of the relationship that this field represents if this field is + // a relation field. Otherwise this will be empty. + RelationName string + + // The CRDT Type of this field. If no type has been provided it will default to [LWW_REGISTER]. + // + // It is currently immutable. + Typ CType + + // If true, this is the primary half of a relation, otherwise is false. + IsPrimaryRelation bool +} + +func (f FieldKind) String() string { + switch f { + case FieldKind_DocID: + return "ID" + case FieldKind_NILLABLE_BOOL: + return "Boolean" + case FieldKind_NILLABLE_BOOL_ARRAY: + return "[Boolean]" + case FieldKind_BOOL_ARRAY: + return "[Boolean!]" + case FieldKind_NILLABLE_INT: + return "Int" + case FieldKind_NILLABLE_INT_ARRAY: + return "[Int]" + case FieldKind_INT_ARRAY: + return "[Int!]" + case FieldKind_NILLABLE_DATETIME: + return "DateTime" + case FieldKind_NILLABLE_FLOAT: + return "Float" + case FieldKind_NILLABLE_FLOAT_ARRAY: + return "[Float]" + case FieldKind_FLOAT_ARRAY: + return "[Float!]" + case FieldKind_NILLABLE_STRING: + return "String" + case FieldKind_NILLABLE_STRING_ARRAY: + return "[String]" + case FieldKind_STRING_ARRAY: + return "[String!]" + case FieldKind_NILLABLE_BLOB: + return "Blob" + case FieldKind_NILLABLE_JSON: + return "JSON" + default: + return fmt.Sprint(uint8(f)) + } +} + +// IsObject returns true if this FieldKind is an object type. +func (f FieldKind) IsObject() bool { + return f == FieldKind_FOREIGN_OBJECT || + f == FieldKind_FOREIGN_OBJECT_ARRAY +} + +// IsObjectArray returns true if this FieldKind is an object array type. +func (f FieldKind) IsObjectArray() bool { + return f == FieldKind_FOREIGN_OBJECT_ARRAY +} + +// IsArray returns true if this FieldKind is an array type which includes inline arrays as well +// as relation arrays. +func (f FieldKind) IsArray() bool { + return f == FieldKind_BOOL_ARRAY || + f == FieldKind_INT_ARRAY || + f == FieldKind_FLOAT_ARRAY || + f == FieldKind_STRING_ARRAY || + f == FieldKind_FOREIGN_OBJECT_ARRAY || + f == FieldKind_NILLABLE_BOOL_ARRAY || + f == FieldKind_NILLABLE_INT_ARRAY || + f == FieldKind_NILLABLE_FLOAT_ARRAY || + f == FieldKind_NILLABLE_STRING_ARRAY +} + +// Note: These values are serialized and persisted in the database, avoid modifying existing values. +const ( + FieldKind_None FieldKind = 0 + FieldKind_DocID FieldKind = 1 + FieldKind_NILLABLE_BOOL FieldKind = 2 + FieldKind_BOOL_ARRAY FieldKind = 3 + FieldKind_NILLABLE_INT FieldKind = 4 + FieldKind_INT_ARRAY FieldKind = 5 + FieldKind_NILLABLE_FLOAT FieldKind = 6 + FieldKind_FLOAT_ARRAY FieldKind = 7 + _ FieldKind = 8 // safe to repurpose (was never used) + _ FieldKind = 9 // safe to repurpose (previously old field) + FieldKind_NILLABLE_DATETIME FieldKind = 10 + FieldKind_NILLABLE_STRING FieldKind = 11 + FieldKind_STRING_ARRAY FieldKind = 12 + FieldKind_NILLABLE_BLOB FieldKind = 13 + FieldKind_NILLABLE_JSON FieldKind = 14 + _ FieldKind = 15 // safe to repurpose (was never used) + + // Embedded object, but accessed via foreign keys + FieldKind_FOREIGN_OBJECT FieldKind = 16 + + // Array of embedded objects, accessed via foreign keys + FieldKind_FOREIGN_OBJECT_ARRAY FieldKind = 17 + + FieldKind_NILLABLE_BOOL_ARRAY FieldKind = 18 + FieldKind_NILLABLE_INT_ARRAY FieldKind = 19 + FieldKind_NILLABLE_FLOAT_ARRAY FieldKind = 20 + FieldKind_NILLABLE_STRING_ARRAY FieldKind = 21 +) + +// FieldKindStringToEnumMapping maps string representations of [FieldKind] values to +// their enum values. +// +// It is currently used to by [db.PatchSchema] to allow string representations of +// [FieldKind] to be provided instead of their raw int values. This usage may expand +// in the future. They currently roughly correspond to the GQL field types, but this +// equality is not guaranteed. +var FieldKindStringToEnumMapping = map[string]FieldKind{ + "ID": FieldKind_DocID, + "Boolean": FieldKind_NILLABLE_BOOL, + "[Boolean]": FieldKind_NILLABLE_BOOL_ARRAY, + "[Boolean!]": FieldKind_BOOL_ARRAY, + "Int": FieldKind_NILLABLE_INT, + "[Int]": FieldKind_NILLABLE_INT_ARRAY, + "[Int!]": FieldKind_INT_ARRAY, + "DateTime": FieldKind_NILLABLE_DATETIME, + "Float": FieldKind_NILLABLE_FLOAT, + "[Float]": FieldKind_NILLABLE_FLOAT_ARRAY, + "[Float!]": FieldKind_FLOAT_ARRAY, + "String": FieldKind_NILLABLE_STRING, + "[String]": FieldKind_NILLABLE_STRING_ARRAY, + "[String!]": FieldKind_STRING_ARRAY, + "Blob": FieldKind_NILLABLE_BLOB, + "JSON": FieldKind_NILLABLE_JSON, +} + +// IsRelation returns true if this field is a relation. +func (f SchemaFieldDescription) IsRelation() bool { + return f.RelationName != "" +}