Documentation ¶
Index ¶
- Constants
- Variables
- func CursorsPredicate[T any](after, before *Cursor[T], idField, field string, direction OrderDirection) []func(s *sql.Selector)
- func ErrNodeNotFound(id interface{}) *gqlerror.Error
- func MultiCursorsPredicate[T any](after, before *Cursor[T], opts *MultiCursorsOptions) ([]func(s *sql.Selector), error)
- func QueryField(name ...string) queryFieldAnnotation
- type Annotation
- func Bind() Annotationdeprecated
- func Directives(directives ...Directive) Annotation
- func Implements(interfaces ...string) Annotation
- func MapsTo(names ...string) Annotation
- func MultiOrder() Annotation
- func Mutations(inputs ...MutationOption) Annotation
- func OrderField(name string) Annotation
- func RelayConnection() Annotation
- func Skip(flags ...SkipMode) Annotation
- func Type(name string) Annotation
- func Unbind() Annotation
- type Cursor
- type Directive
- type Extension
- type ExtensionOption
- func WithConfigPath(path string, gqlgenOptions ...api.Option) ExtensionOption
- func WithMapScalarFunc(scalarFunc func(*gen.Field, gen.Op) string) ExtensionOption
- func WithNodeDescriptor(b bool) ExtensionOption
- func WithOutputWriter(w func(*ast.Schema) error) ExtensionOption
- func WithRelaySpec(enabled bool) ExtensionOption
- func WithSchemaGenerator() ExtensionOption
- func WithSchemaHook(hooks ...SchemaHook) ExtensionOption
- func WithSchemaPath(path string) ExtensionOption
- func WithTemplates(templates ...*gen.Template) ExtensionOption
- func WithWhereInputs(b bool) ExtensionOption
- type FieldConfig
- type InputFieldDescriptor
- type MultiCursorsOptions
- type MutationConfig
- type MutationDescriptor
- type MutationOption
- type OrderDirection
- func (o OrderDirection) MarshalGQL(w io.Writer)
- func (o OrderDirection) OrderTermOption() sql.OrderTermOption
- func (o OrderDirection) Reverse() OrderDirection
- func (o OrderDirection) String() string
- func (o *OrderDirection) UnmarshalGQL(val interface{}) error
- func (o OrderDirection) Validate() error
- type OrderTerm
- type PageInfo
- type PaginationNames
- type SchemaHook
- type SkipMode
- type Transactioner
- func (Transactioner) ExtensionName() string
- func (t Transactioner) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
- func (Transactioner) MutateOperationContext(_ context.Context, oc *graphql.OperationContext) *gqlerror.Error
- func (t Transactioner) Validate(graphql.ExecutableSchema) error
- type TxOpener
- type TxOpenerFunc
Constants ¶
const ( // QueryType is the name of the root Query object. QueryType = "Query" // OrderDirectionEnum is the name of enum OrderDirection OrderDirectionEnum = "OrderDirection" // RelayCursor is the name of the cursor type RelayCursor = "Cursor" // RelayNode is the name of the interface that all nodes implement RelayNode = "Node" // RelayPageInfo is the name of the PageInfo type RelayPageInfo = "PageInfo" )
Variables ¶
var ( // CollectionTemplate adds fields collection support using auto eager-load ent edges. // More info can be found here: https://spec.graphql.org/June2018/#sec-Field-Collection. CollectionTemplate = parseT("template/collection.tmpl") // EnumTemplate adds a template implementing MarshalGQL/UnmarshalGQL methods for enums. EnumTemplate = parseT("template/enum.tmpl") // NodeTemplate implements the Relay Node interface for all types. NodeTemplate = parseT("template/node.tmpl") // NodeDescriptorTemplate implements the Node descriptor API for all types. NodeDescriptorTemplate = parseT("template/node_descriptor.tmpl") // PaginationTemplate adds pagination support according to the GraphQL Cursor Connections Spec. // More info can be found in the following link: https://relay.dev/graphql/connections.htm. PaginationTemplate = parseT("template/pagination.tmpl") // TransactionTemplate adds support for ent.Client for opening transactions for the transaction // middleware. See transaction.go for for information. TransactionTemplate = parseT("template/transaction.tmpl") // EdgeTemplate adds edge resolution using eager-loading with a query fallback. EdgeTemplate = parseT("template/edge.tmpl") // WhereTemplate adds a template for generating <T>WhereInput filters for each schema type. WhereTemplate = parseT("template/where_input.tmpl") // MutationInputTemplate adds a template for generating Create<T>Input and Update<T>Input for each schema type. MutationInputTemplate = parseT("template/mutation_input.tmpl").SkipIf(skipMutationTemplate) // AllTemplates holds all templates for extending ent to support GraphQL. AllTemplates = []*gen.Template{ CollectionTemplate, EnumTemplate, NodeTemplate, PaginationTemplate, TransactionTemplate, EdgeTemplate, MutationInputTemplate, } // TemplateFuncs contains the extra template functions used by entgql. TemplateFuncs = template.FuncMap{ "fieldCollections": fieldCollections, "fieldMapping": fieldMapping, "filterEdges": filterEdges, "filterFields": filterFields, "filterNodes": filterNodes, "gqlIDType": gqlIDType, "gqlMarshaler": gqlMarshaler, "gqlUnmarshaler": gqlUnmarshaler, "hasWhereInput": hasWhereInput, "isRelayConn": isRelayConn, "isSkipMode": isSkipMode, "mutationInputs": mutationInputs, "nodePaginationNames": nodePaginationNames, "orderFields": orderFields, "skipMode": skipModeFromString, } )
var ( // ErrRelaySpecDisabled is the error returned when the relay specification is disabled ErrRelaySpecDisabled = errors.New("entgql: must enable relay specification via the WithRelaySpec option") )
var ( // WithWhereFilters configures the extension to either add or // remove the WhereTemplate from the code generation templates. // // Deprecated: use WithWhereInputs instead. This option is planned // to be removed in future versions. WithWhereFilters = WithWhereInputs )
Functions ¶
func CursorsPredicate ¶
func CursorsPredicate[T any](after, before *Cursor[T], idField, field string, direction OrderDirection) []func(s *sql.Selector)
CursorsPredicate converts the given cursors to predicates.
func ErrNodeNotFound ¶
ErrNodeNotFound creates a node not found graphql error.
func MultiCursorsPredicate ¶
func MultiCursorsPredicate[T any](after, before *Cursor[T], opts *MultiCursorsOptions) ([]func(s *sql.Selector), error)
MultiCursorsPredicate returns a predicate that filters records by the given cursors.
func QueryField ¶
func QueryField(name ...string) queryFieldAnnotation
QueryField returns an annotation for expose the field on the Query type.
Types ¶
type Annotation ¶
type Annotation struct { // OrderField is the ordering field as defined in graphql schema. OrderField string `json:"OrderField,omitempty"` // MultiOrder indicates that orderBy should accept a list of OrderField terms. MultiOrder bool `json:"MultiOrder,omitempty"` // Unbind implies the edge field name in GraphQL schema is not equivalent // to the name used in ent schema. That means, by default, edges with this // annotation will not be eager-loaded on Paginate calls. See the `MapsTo` // option in order to load edges be different name mapping. Unbind bool `json:"Unbind,omitempty"` // Mapping is the edge field names as defined in graphql schema. Mapping []string `json:"Mapping,omitempty"` // Type is the underlying GraphQL type name (e.g. Boolean). Type string `json:"Type,omitempty"` // Skip exclude the type Skip SkipMode `json:"Skip,omitempty"` // RelayConnection enables the Relay Connection specification for the entity. // It's also can apply on an edge to create the Relay-style filter. RelayConnection bool `json:"RelayConnection,omitempty"` // Implements defines a list of interfaces implemented by the type. Implements []string `json:"Implements,omitempty"` // Directives to add on the field/type. Directives []Directive `json:"Directives,omitempty"` // QueryField exposes the generated type with the given string under the Query object. QueryField *FieldConfig `json:"QueryField,omitempty"` // MutationInputs defines the input types for the mutation. MutationInputs []MutationConfig `json:"MutationInputs,omitempty"` }
Annotation annotates fields and edges with metadata for templates.
func Bind
deprecated
func Bind() Annotation
Bind returns a binding annotation.
No-op function to avoid breaking the existing schema. You can safely remove this function from your scheme.
Deprecated: the Bind option predates the Unbind option, and it is planned to be removed in future versions. Users should not use this annotation as it is a no-op call, or use `Unbind` in order to disable `Bind`.
func Directives ¶
func Directives(directives ...Directive) Annotation
Directives returns a Directives annotation. The Directives() annotation is used to add directives to a GraphQL type or on the field.
For example, to add the `@deprecated` directive to the `text` field:
type Todo { id: ID text: String ... }
Add the entgql.Directives() to the text field's annotations:
field.Text("text"). NotEmpty(). Annotations( entgql.Directives(entgql.Deprecated("Use `description` instead.")), ),
and the GraphQL type will be generated with the directive.
type Todo { id: ID text: String @deprecated(reason: "Use `description` instead.") ... }
func Implements ¶
func Implements(interfaces ...string) Annotation
Implements returns an Implements annotation. The Implements() annotation is used to add implements interfaces to a GraphQL type.
For example, to add the `Entity` to the `Todo` type:
type Todo implements Node { id: ID! ... }
Add the entgql.Implements("Entity") to the Todo's annotations:
func (Todo) Annotations() []schema.Annotation { return []schema.Annotation{ entgql.Implements("Entity"), } }
and the GraphQL type will be generated with the implements interface.
type Todo implements Node & Entity { id: ID! ... }
func MultiOrder ¶
func MultiOrder() Annotation
MultiOrder indicates that orderBy should accept a list of OrderField terms.
func Mutations ¶
func Mutations(inputs ...MutationOption) Annotation
Mutations returns an annotation for generate input types for mutation.
func OrderField ¶
func OrderField(name string) Annotation
OrderField enables ordering in GraphQL for the annotated Ent field with the given name. Note that, the field type must be comparable.
field.Time("created_at"). Default(time.Now). Immutable(). Annotations( entgql.OrderField("CREATED_AT"), )
For enum fields, values must be uppercase or mapped using the NamedValues option:
field.Enum("status"). NamedValues( "InProgress", "IN_PROGRESS", "Completed", "COMPLETED", ). Default("IN_PROGRESS"). Annotations( entgql.OrderField("STATUS"), )
func RelayConnection ¶
func RelayConnection() Annotation
RelayConnection returns an annotation indicating that the node/edge should support pagination. Hence,the returned result is a Relay connection rather than a list of nodes.
Setting this annotation on schema `T` (reside in ent/schema), enables pagination for this type and therefore, Ent will generate all Relay types for this schema, such as: `<T>Edge`, `<T>Connection`, and PageInfo. For example:
func (Todo) Annotations() []schema.Annotation { return []schema.Annotation{ entgql.RelayConnection(), entgql.QueryField(), } }
Setting this annotation on an Ent edge indicates that the GraphQL field for this edge should support nested pagination and the returned type is a Relay connection type rather than the actual nodes. For example:
func (Todo) Edges() []ent.Edge { return []ent.Edge{ edge.To("parent", Todo.Type). Unique(). From("children"). Annotation(entgql.RelayConnection()), } }
The generated GraphQL schema will be:
children(first: Int, last: Int, after: Cursor, before: Cursor): TodoConnection!
Rather than:
children: [Todo!]!
func Skip ¶
func Skip(flags ...SkipMode) Annotation
Skip returns a skip annotation. The Skip() annotation is used to skip generating the type or the field from GraphQL schema.
It gives you the flexibility to skip generating the type or the field based on the SkipMode flags.
For example, if you don't want to expose a field on the <T>WhereInput type you can use the following:
field.String("name"). Annotations( entgql.Skip(entgql.SkipWhereInput), )
Since SkipMode is a bit flag, it's possible to skip multiple modes using the bitwise OR operator as follows:
entgql.Skip(entgql.SkipWhereInput | entgql.SkipEnumField)
To skip everything except the type, use the bitwise NOT operator:
entgql.Skip(^entgql.SkipType)
You can also skip all modes with the `entgql.SkipAll` constant which is the default mode.
func Type ¶
func Type(name string) Annotation
Type returns a type mapping annotation. The Type() annotation is used to map the underlying GraphQL type to the type.
To change the GraphQL type for a type:
func (User) Annotations() []schema.Annotation { return []schema.Annotation{ entgql.Type("MasterUser"), } }
To change the GraphQL type for a field (rename enum type):
field.Enum("status"). NamedValues( "InProgress", "IN_PROGRESS", "Completed", "COMPLETED", ). Default("IN_PROGRESS"). Annotations( entgql.Type("TodoStatus"), )
func Unbind ¶
func Unbind() Annotation
Unbind implies the edge field name in GraphQL schema is not equivalent to the name used in ent schema. That means, by default, edges with this annotation will not be eager-loaded on Paginate calls. See the `MapsTo` option in order to load edges with different name mapping.
func (Todo) Edges() []ent.Edge { return []ent.Edge{ edge.To("parent", Todo.Type). Annotations(entgql.Unbind()). Unique(). From("children"). Annotations(entgql.Unbind()), } }
func (*Annotation) Decode ¶
func (a *Annotation) Decode(annotation interface{}) error
Decode unmarshalls the annotation.
func (Annotation) Merge ¶
func (a Annotation) Merge(other schema.Annotation) schema.Annotation
Merge implements the schema.Merger interface.
type Cursor ¶
Cursor of an edge type.
func (Cursor[T]) MarshalGQL ¶
MarshalGQL implements graphql.Marshaler interface.
func (*Cursor[T]) UnmarshalGQL ¶
UnmarshalGQL implements graphql.Unmarshaler interface.
type Directive ¶
type Directive struct { Name string `json:"name,omitempty"` Arguments []*ast.Argument `json:"arguments,omitempty"` }
Directive to apply on the field/type.
func Deprecated ¶
Deprecated create `@deprecated` directive to apply on the field/type
type Extension ¶
type Extension struct { entc.DefaultExtension // contains filtered or unexported fields }
Extension implements the entc.Extension for providing GraphQL integration.
func NewExtension ¶
func NewExtension(opts ...ExtensionOption) (*Extension, error)
NewExtension creates a new extension with the given configuration.
ex, err := entgql.NewExtension( entgql.WithSchemaGenerator(), entgql.WithSchemaPath("../ent.graphql"), entgql.WithWhereInputs(true), )
func (*Extension) BuildSchema ¶
type ExtensionOption ¶
ExtensionOption allows for managing the Extension configuration using functional options.
func WithConfigPath ¶
func WithConfigPath(path string, gqlgenOptions ...api.Option) ExtensionOption
WithConfigPath sets the filepath to gqlgen.yml configuration file and injects its parsed version to the global annotations.
Note that, enabling this option is recommended as it improves the GraphQL integration,
func WithMapScalarFunc ¶
WithMapScalarFunc allows users to provide a custom function that maps an ent.Field (*gen.Field) into its GraphQL scalar type. If the function returns an empty string, the extension fallbacks to its default mapping.
ex, err := entgql.NewExtension( entgql.WithMapScalarFunc(func(f *gen.Field, op gen.Op) string { if t, ok := knowType(f, op); ok { return t } // Fallback to the default mapping. return "" }), )
func WithNodeDescriptor ¶
func WithNodeDescriptor(b bool) ExtensionOption
WithNodeDescriptor configures the extension to either add or remove the NodeDescriptorTemplate from the code generation templates.
In case this option is enabled, EntGQL generates a `Node()` method for each type that returns its representation in one standard way. A common use case for this option is to develop an administrator tool on top of Ent as implemented in: https://github.com/ent/ent/issues/1000#issuecomment-735663175.
func WithOutputWriter ¶
func WithOutputWriter(w func(*ast.Schema) error) ExtensionOption
WithOutputWriter sets the function to write the generated schema.
func WithRelaySpec ¶
func WithRelaySpec(enabled bool) ExtensionOption
WithRelaySpec enables or disables generating the Relay Node interface.
func WithSchemaGenerator ¶
func WithSchemaGenerator() ExtensionOption
WithSchemaGenerator add a hook for generate GQL schema
func WithSchemaHook ¶
func WithSchemaHook(hooks ...SchemaHook) ExtensionOption
WithSchemaHook allows users to provide a list of hooks to run after the GQL schema generation.
func WithSchemaPath ¶
func WithSchemaPath(path string) ExtensionOption
WithSchemaPath sets the filepath to the GraphQL schema to write the generated Ent types. If the file does not exist, it will generate a new schema. Please note that your gqlgen.yml config file should be updated as follows to support multiple schema files:
schema: - schema.graphql // existing schema. - ent.graphql // generated schema.
func WithTemplates ¶
func WithTemplates(templates ...*gen.Template) ExtensionOption
WithTemplates overrides the default templates (entgql.AllTemplates) with specific templates.
func WithWhereInputs ¶
func WithWhereInputs(b bool) ExtensionOption
WithWhereInputs configures the extension to either add or remove the WhereTemplate from the code generation templates.
The WhereTemplate generates GraphQL filters to all types in the ent/schema.
type FieldConfig ¶
type FieldConfig struct { // Name is the name of the field in the Query object. Name string `json:"Name,omitempty"` // Description is the description of the field. Description string `json:"Description,omitempty"` // Directives to add on the field Directives []Directive `json:"Directives,omitempty"` }
type InputFieldDescriptor ¶
type InputFieldDescriptor struct { *gen.Field // AppendOp indicates if the field has the Append operator AppendOp bool // ClearOp indicates if the field has the Clear operator ClearOp bool // Nullable indicates if the field is nullable. Nullable bool }
InputFieldDescriptor holds the information about a field in the input type. It's shared between GQL and Go types.
func (*InputFieldDescriptor) IsPointer ¶
func (f *InputFieldDescriptor) IsPointer() bool
IsPointer returns true if the Go type should be a pointer
type MultiCursorsOptions ¶
type MultiCursorsOptions struct { FieldID string // ID field name. DirectionID OrderDirection // ID field direction. Fields []string // OrderBy fields used by the cursor. Directions []OrderDirection // OrderBy directions used by the cursor. }
MultiCursorOptions are the options for building the cursor predicates.
type MutationConfig ¶
type MutationConfig struct { IsCreate bool `json:"IsCreate,omitempty"` Description string `json:"Description,omitempty"` }
MutationConfig hold config for mutation
type MutationDescriptor ¶
MutationDescriptor holds information about a GraphQL mutation input.
func (*MutationDescriptor) Builders ¶
func (m *MutationDescriptor) Builders() []string
Builders return the builder's names to apply the input.
func (*MutationDescriptor) Input ¶
func (m *MutationDescriptor) Input() (string, error)
Input returns the input's name.
func (*MutationDescriptor) InputEdges ¶
func (m *MutationDescriptor) InputEdges() ([]*gen.Edge, error)
InputEdges returns the list of fields in the input type.
NOTE(giautm): This method should refactor to return a list of InputFieldDescriptor.
func (*MutationDescriptor) InputFields ¶
func (m *MutationDescriptor) InputFields() ([]*InputFieldDescriptor, error)
InputFields returns the list of fields in the input type.
type MutationOption ¶
type MutationOption interface { IsCreate() bool GetDescription() string // Description allows you to customize the comment of the auto-generated Mutation Input // // For example, // // entgql.Mutations( // entgql.MutationCreate(). // Description("The fields used in the creation of a TodoItem"), // ), // // Creates // // """The fields used in the creation of a TodoItem""" // input CreateTodoItem { // """fields omitted""" // } Description(string) MutationOption }
func MutationCreate ¶
func MutationCreate() MutationOption
func MutationUpdate ¶
func MutationUpdate() MutationOption
type OrderDirection ¶
type OrderDirection string
OrderDirection defines the directions in which to order a list of items.
const ( // OrderDirectionAsc specifies an ascending order. OrderDirectionAsc OrderDirection = "ASC" // OrderDirectionDesc specifies a descending order. OrderDirectionDesc OrderDirection = "DESC" )
func (OrderDirection) MarshalGQL ¶
func (o OrderDirection) MarshalGQL(w io.Writer)
MarshalGQL implements graphql.Marshaler interface.
func (OrderDirection) OrderTermOption ¶
func (o OrderDirection) OrderTermOption() sql.OrderTermOption
OrderTermOption returns the OrderTermOption for setting the order direction.
func (OrderDirection) Reverse ¶
func (o OrderDirection) Reverse() OrderDirection
Reverse the direction.
func (OrderDirection) String ¶
func (o OrderDirection) String() string
String implements fmt.Stringer interface.
func (*OrderDirection) UnmarshalGQL ¶
func (o *OrderDirection) UnmarshalGQL(val interface{}) error
UnmarshalGQL implements graphql.Unmarshaler interface.
func (OrderDirection) Validate ¶
func (o OrderDirection) Validate() error
Validate the order direction value.
type OrderTerm ¶
type OrderTerm struct { GQL string // The GraphQL name of the field. Type *gen.Type // The type that owns the field. Field *gen.Field // Not nil if it is a type/edge field. Edge *gen.Edge // Not nil if it is an edge field or count. Count bool // True if it is a count field. }
OrderTerm is a struct that represents a single GraphQL order term.
func (*OrderTerm) IsEdgeCountTerm ¶
IsEdgeCountTerm returns true if the order term is an edge count term.
func (*OrderTerm) IsEdgeFieldTerm ¶
IsEdgeFieldTerm returns true if the order term is an edge field term.
func (*OrderTerm) IsFieldTerm ¶
IsFieldTerm returns true if the order term is a type field term.
type PageInfo ¶
type PageInfo[T any] struct { HasNextPage bool `json:"hasNextPage"` HasPreviousPage bool `json:"hasPreviousPage"` StartCursor *Cursor[T] `json:"startCursor"` EndCursor *Cursor[T] `json:"endCursor"` }
PageInfo of a connection type.
type PaginationNames ¶
type PaginationNames struct { Connection string Edge string Node string Order string OrderField string WhereInput string }
PaginationNames holds the names of the pagination fields.
func (*PaginationNames) ConnectionField ¶
func (p *PaginationNames) ConnectionField(name string, hasOrderBy, multiOrder, hasWhereInput bool) *ast.FieldDefinition
func (*PaginationNames) OrderInputDef ¶
func (p *PaginationNames) OrderInputDef() *ast.Definition
func (*PaginationNames) TypeDefs ¶
func (p *PaginationNames) TypeDefs() []*ast.Definition
type SchemaHook ¶
SchemaHook is the hook that run after the GQL schema generation.
type SkipMode ¶
type SkipMode int
SkipMode is a bit flag for the Skip annotation.
const ( // SkipType skips generating GraphQL types or fields in the schema. SkipType SkipMode = 1 << iota // SkipEnumField skips generating GraphQL enums for enum fields in the schema. SkipEnumField // SkipOrderField skips generating GraphQL order inputs and enums for ordered-fields in the schema. SkipOrderField // SkipWhereInput skips generating GraphQL WhereInput types. // If defined on a field, the type will be generated without the field. SkipWhereInput // SkipMutationCreateInput skips generating GraphQL Create<Type>Input types. // If defined on a field, the type will be generated without the field. SkipMutationCreateInput // SkipMutationUpdateInput skips generating GraphQL Update<Type>Input types. // If defined on a field, the type will be generated without the field. SkipMutationUpdateInput // SkipAll is default mode to skip all. SkipAll = SkipType | SkipEnumField | SkipOrderField | SkipWhereInput | SkipMutationCreateInput | SkipMutationUpdateInput )
type Transactioner ¶
type Transactioner struct{ TxOpener }
Transactioner for graphql mutations.
func (Transactioner) ExtensionName ¶
func (Transactioner) ExtensionName() string
ExtensionName returns the extension name.
func (Transactioner) InterceptResponse ¶
func (t Transactioner) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
InterceptResponse runs graphql mutations under a transaction.
func (Transactioner) MutateOperationContext ¶
func (Transactioner) MutateOperationContext(_ context.Context, oc *graphql.OperationContext) *gqlerror.Error
MutateOperationContext serializes field resolvers during mutations.
func (Transactioner) Validate ¶
func (t Transactioner) Validate(graphql.ExecutableSchema) error
Validate is called when adding an extension to the server, it allows validation against the servers schema.
type TxOpenerFunc ¶
The TxOpenerFunc type is an adapter to allow the use of ordinary functions as tx openers.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
internal
|
|
todo/ent/schema/schematype
Package schematype provides custom types for ent/schema.
|
Package schematype provides custom types for ent/schema. |
todofed/ent/schema/schematype
Package schematype provides custom types for ent/schema.
|
Package schematype provides custom types for ent/schema. |
todopulid/ent/schema/pulid
Package pulid implements the pulid type.
|
Package pulid implements the pulid type. |