fluent

package module
v0.1.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2024 License: Apache-2.0 Imports: 6 Imported by: 109

README

fluent - Yet another entity Framework For Go (fork of ent)

Project structure

  • dialect - Contains SQL and Gremlin code used by the generated code.

    • dialect/sql/schema - Auto migration logic resides there.
    • dialect/sql/sqljson - JSON extension for SQL.
  • schema - User schema API.

    • schema/{field, edge, index, mixin} - provides schema builders API.
    • schema/field/gen - Templates and codegen for numeric builders.
  • flc - Codegen of ent.

    • flc/load - flc loader API for loading user schemas into a Go objects at runtime.
    • flc/gen - The actual code generation logic resides in this package (and its templates package).
    • integration - Integration tests for flc.
  • privacy - Runtime code for privacy layer.

  • doc - Documentation code for github.com/usalko/fluent (uses Docusaurus).

    • doc/md - Markdown files for documentation.
    • doc/website - Website code and assets.

    In order to test your documentation changes, run npm start from the doc/website directory, and open localhost:3000.

Run integration tests

If you touch any file in flc, run the following commands in flc/integration and 'examples' dirs:

go generate ./...
go mod tidy

Then, in flc/integration run docker-compose in order to spin-up all database containers:

docker-compose -f docker-compose.yaml up -d

Then, run go test ./... to run all integration tests.

Documentation

Overview

Package fluent is the interface between end-user schemas and flc (ent codegen).

Index

Constants

View Source
const (
	OpQueryFirst   = "First"
	OpQueryFirstID = "FirstID"
	OpQueryOnly    = "Only"
	OpQueryOnlyID  = "OnlyID"
	OpQueryAll     = "All"
	OpQueryIDs     = "IDs"
	OpQueryCount   = "Count"
	OpQueryExist   = "Exist"
	OpQueryGroupBy = "GroupBy"
	OpQuerySelect  = "Select"
)

List of query operations used by the codegen.

Variables

This section is empty.

Functions

func NewQueryContext

func NewQueryContext(parent context.Context, c *QueryContext) context.Context

NewQueryContext returns a new context with the given QueryContext attached.

Types

type Config deprecated

type Config struct {
	// A Table is an optional table name defined for the schema.
	Table string
}

A Config structure is used to configure an entity schema. The usage of this structure is as follows:

func (T) Config() fluent.Config {
	return fluent.Config{
		Table: "Name",
	}
}

Deprecated: the Config object predates the schema.Annotation method and it is planned to be removed in future versions. New code should use Annotations instead.

func (T) Annotations() []schema.Annotation {
	return []schema.Annotation{
		fluent_sql.Annotation{Table: "Name"},
	}
}

type Edge

type Edge interface {
	Descriptor() *edge.Descriptor
}

An Edge interface returns an edge descriptor for vertex edges. The usage for the interface is as follows:

func (T) Edges() []fluent.Edge {
	return []fluent.Edge{
		edge.To("S", S.Type),
	}
}

type Field

type Field interface {
	Descriptor() *field.Descriptor
}

A Field interface returns a field descriptor for vertex fields/properties. The usage for the interface is as follows:

func (T) Fields() []fluent.Field {
	return []fluent.Field{
		field.Int("int"),
	}
}

type Hook

type Hook func(Mutator) Mutator

Hook defines the "mutation middleware". A function that gets a Mutator and returns a Mutator. For example:

hook := func(next fluent.Mutator) fluent.Mutator {
	return fluent.MutateFunc(func(ctx context.Context, m fluent.Mutation) (fluent.Value, error) {
		fmt.Printf("Type: %s, Operation: %s, ConcreteType: %T\n", m.Type(), m.Op(), m)
		return next.Mutate(ctx, m)
	})
}

type Index

type Index interface {
	Descriptor() *index.Descriptor
}

An Index interface returns an index descriptor for vertex indexes. The usage for the interface is as follows:

func (T) Indexes() []fluent.Index {
	return []fluent.Index{
		index.Fields("f1", "f2").
			Unique(),
	}
}

type InterceptFunc

type InterceptFunc func(Querier) Querier

The InterceptFunc type is an adapter to allow the use of ordinary function as Interceptor. If f is a function with the appropriate signature, InterceptFunc(f) is an Interceptor that calls f.

func (InterceptFunc) Intercept

func (f InterceptFunc) Intercept(next Querier) Querier

Intercept calls f(ctx, q).

type Interceptor

type Interceptor interface {
	// Intercept is a function that gets a Querier and returns a Querier. For example:
	//
	//	fluent.InterceptFunc(func(next fluent.Querier) fluent.Querier {
	//		return fluent.QuerierFunc(func(ctx context.Context, query fluent.Query) (fluent.Value, error) {
	//			// Do something before the query execution.
	//			value, err := next.Query(ctx, query)
	//			// Do something after the query execution.
	//			return value, err
	//		})
	//	})
	//
	// Note that unlike Traverse functions, which are called at each traversal stage, Intercept functions
	// are invoked before the query executions. This means that using Traverse functions is a better fit
	// for adding default filters, while using Intercept functions is a better fit for implementing logging
	// or caching.
	//
	//
	//	client.User.Query().
	//		QueryGroups().	// User traverse functions applied.
	//		QueryPosts().	// Group traverse functions applied.
	//		All(ctx)	// Post traverse and intercept functions applied.
	//
	Intercept(Querier) Querier
}

Interceptor defines an execution middleware for various types of Ent queries. Contrary to Hooks, Interceptors are implemented as interfaces, allows them to intercept and modify the query at different stages, providing more fine-grained control over its behavior. For example, see the Traverser interface.

type Interface

type Interface interface {
	// Type is a dummy method, that is used in edge declaration.
	//
	// The Type method should be used as follows:
	//
	//	type S struct { fluent.Schema }
	//
	//	type T struct { fluent.Schema }
	//
	//	func (T) Edges() []fluent.Edge {
	//		return []fluent.Edge{
	//			edge.To("S", S.Type),
	//		}
	//	}
	//
	Type()
	// Fields returns the fields of the schema.
	Fields() []Field
	// Edges returns the edges of the schema.
	Edges() []Edge
	// Indexes returns the indexes of the schema.
	Indexes() []Index
	// Config returns an optional config for the schema.
	//
	// Deprecated: the Config method predates the Annotations method, and it
	// is planned be removed in v0.5.0. New code should use Annotations instead.
	//
	//	func (T) Annotations() []schema.Annotation {
	//		return []schema.Annotation{
	//			fluent_sql.Annotation{Table: "Name"},
	//		}
	//	}
	//
	Config() Config
	// Mixin returns an optional list of Mixin to extends
	// the schema.
	Mixin() []Mixin
	// Hooks returns an optional list of Hook to apply on
	// the executed mutations.
	Hooks() []Hook
	// Interceptors returns an optional list of Interceptor
	// to apply on the executed queries.
	Interceptors() []Interceptor
	// Policy returns the privacy policy of the schema.
	Policy() Policy
	// Annotations returns a list of schema annotations to be used by
	// codegen extensions.
	Annotations() []schema.Annotation
}

The Interface type describes the requirements for an exported type defined in the schema package. It functions as the interface between the user's schema types and codegen loader. Users should use the Schema type for embedding as follows:

type T struct {
	fluent.Schema
}

type Mixin

type Mixin interface {
	// Fields returns a slice of fields to add to the schema.
	Fields() []Field
	// Edges returns a slice of edges to add to the schema.
	Edges() []Edge
	// Indexes returns a slice of indexes to add to the schema.
	Indexes() []Index
	// Hooks returns a slice of hooks to add to the schema.
	// Note that mixin hooks are executed before schema hooks.
	Hooks() []Hook
	// Interceptors returns a slice of interceptors to add to the schema.
	// Note that mixin interceptors are executed before schema interceptors.
	Interceptors() []Interceptor
	// Policy returns a privacy policy to add to the schema.
	// Note that mixin policy are executed before schema policy.
	Policy() Policy
	// Annotations returns a list of schema annotations to add
	// to the schema annotations.
	Annotations() []schema.Annotation
}

The Mixin type describes a set of methods that can extend other methods in the schema without calling them directly.

type TimeMixin struct {}

func (TimeMixin) Fields() []fluent.Field {
	return []fluent.Field{
		field.Time("created_at").
			Immutable().
			Default(time.Now),
		field.Time("updated_at").
			Default(time.Now).
			UpdateDefault(time.Now),
	}
}

type T struct {
	fluent.Schema
}

func(T) Mixin() []fluent.Mixin {
	return []fluent.Mixin{
		TimeMixin{},
	}
}

type MutateFunc

type MutateFunc func(context.Context, Mutation) (Value, error)

The MutateFunc type is an adapter to allow the use of ordinary function as Mutator. If f is a function with the appropriate signature, MutateFunc(f) is a Mutator that calls f.

func (MutateFunc) Mutate

func (f MutateFunc) Mutate(ctx context.Context, m Mutation) (Value, error)

Mutate calls f(ctx, m).

type Mutation

type Mutation interface {
	// Op returns the operation name generated by flc.
	Op() Op
	// Type returns the schema type for this mutation.
	Type() string

	// Fields returns all fields that were changed during
	// this mutation. Note that, in order to get all numeric
	// fields that were in/decremented, call AddedFields().
	Fields() []string
	// Field returns the value of a field with the given name.
	// The second boolean value indicates that this field was
	// not set, or was not defined in the schema.
	Field(name string) (Value, bool)
	// SetField sets the value for the given name. It returns an
	// error if the field is not defined in the schema, or if the
	// type mismatch the field type.
	SetField(name string, value Value) error

	// AddedFields returns all numeric fields that were incremented
	// or decremented during this mutation.
	AddedFields() []string
	// AddedField returns the numeric value that was in/decremented
	// from a field with the given name. The second value indicates
	// that this field was not set, or was not define in the schema.
	AddedField(name string) (Value, bool)
	// AddField adds the value for the given name. It returns an
	// error if the field is not defined in the schema, or if the
	// type mismatch the field type.
	AddField(name string, value Value) error

	// ClearedFields returns all nullable fields that were cleared
	// during this mutation.
	ClearedFields() []string
	// FieldCleared returns a bool indicates if this field was
	// cleared in this mutation.
	FieldCleared(name string) bool
	// ClearField clears the value for the given name. It returns an
	// error if the field is not defined in the schema.
	ClearField(name string) error

	// ResetField resets all changes in the mutation regarding the
	// given field name. It returns an error if the field is not
	// defined in the schema.
	ResetField(name string) error

	// AddedEdges returns all edge names that were set/added in this
	// mutation.
	AddedEdges() []string
	// AddedIDs returns all ids (to other nodes) that were added for
	// the given edge name.
	AddedIDs(name string) []Value

	// RemovedEdges returns all edge names that were removed in this
	// mutation.
	RemovedEdges() []string
	// RemovedIDs returns all ids (to other nodes) that were removed for
	// the given edge name.
	RemovedIDs(name string) []Value

	// ClearedEdges returns all edge names that were cleared in this
	// mutation.
	ClearedEdges() []string
	// EdgeCleared returns a bool indicates if this edge was
	// cleared in this mutation.
	EdgeCleared(name string) bool
	// ClearEdge clears the value for the given name. It returns an
	// error if the edge name is not defined in the schema.
	ClearEdge(name string) error

	// ResetEdge resets all changes in the mutation regarding the
	// given edge name. It returns an error if the edge is not
	// defined in the schema.
	ResetEdge(name string) error

	// OldField returns the old value of the field from the database.
	// An error is returned if the mutation operation is not UpdateOne,
	// or the query to the database was failed.
	OldField(ctx context.Context, name string) (Value, error)
}

Mutation represents an operation that mutate the graph. For example, adding a new node, updating many, or dropping data. The implementation is generated by flc (ent codegen).

type Mutator

type Mutator interface {
	// Mutate apply the given mutation on the graph. The returned
	// fluent.Value is changing according to the mutation operation:
	//
	// OpCreate, the returned value is the created node (T).
	// OpUpdateOne, the returned value is the updated node (T).
	// OpUpdate, the returned value is the amount of updated nodes (int).
	// OpDeleteOne, OpDelete, the returned value is the amount of deleted nodes (int).
	//
	Mutate(context.Context, Mutation) (Value, error)
}

Mutator is the interface that wraps the Mutate method.

type Op

type Op uint

An Op represents a mutation operation.

const (
	OpCreate    Op = 1 << iota // node creation.
	OpUpdate                   // update nodes by predicate (if any).
	OpUpdateOne                // update one node.
	OpDelete                   // delete nodes by predicate (if any).
	OpDeleteOne                // delete one node.
)

Mutation operations.

func (Op) Is

func (i Op) Is(o Op) bool

Is reports whether o is match the given operation.

func (Op) String

func (i Op) String() string

type Policy

type Policy interface {
	EvalMutation(context.Context, Mutation) error
	EvalQuery(context.Context, Query) error
}

The Policy type defines the privacy policy of an entity. The usage for the interface is as follows:

type T struct {
	fluent.Schema
}

func(T) Policy() fluent.Policy {
	return privacy.AlwaysAllowRule()
}

type Querier

type Querier interface {
	// Query runs the given query on the graph and returns its result.
	Query(context.Context, Query) (Value, error)
}

Querier is the interface that wraps the Query method. Calling Querier.Query(fluent.Query) triggers the execution of the query.

type QuerierFunc

type QuerierFunc func(context.Context, Query) (Value, error)

The QuerierFunc type is an adapter to allow the use of ordinary function as Querier. If f is a function with the appropriate signature, QuerierFunc(f) is a Querier that calls f.

func (QuerierFunc) Query

func (f QuerierFunc) Query(ctx context.Context, q Query) (Value, error)

Query calls f(ctx, q).

type Query

type Query any

Query represents a query builder of an entity. It is usually one of the following types: <T>Query.

type QueryContext

type QueryContext struct {
	// Op defines the operation name. e.g., First, All, Count, etc.
	Op string
	// Type defines the query type as defined in the generated code.
	Type string
	// Unique indicates if the Unique modifier was set on the query and
	// its value. Calling Unique(false) sets the value of Unique to false.
	Unique *bool
	// Limit indicates if the Limit modifier was set on the query and
	// its value. Calling Limit(10) sets the value of Limit to 10.
	Limit *int
	// Offset indicates if the Offset modifier was set on the query and
	// its value. Calling Offset(10) sets the value of Offset to 10.
	Offset *int
	// Fields specifies the fields that were selected in the query.
	Fields []string
}

QueryContext contains additional information about the context in which the query is executed.

func QueryFromContext

func QueryFromContext(ctx context.Context) *QueryContext

QueryFromContext returns the QueryContext value stored in ctx, if any.

func (*QueryContext) AppendFieldOnce

func (q *QueryContext) AppendFieldOnce(f string) *QueryContext

AppendFieldOnce adds the given field to the spec if it is not already present.

func (*QueryContext) Clone

func (q *QueryContext) Clone() *QueryContext

Clone returns a deep copy of the query context.

type Schema

type Schema struct {
	Interface
}

Schema is the default implementation for the schema Interface. It can be embedded in end-user schemas as follows:

type T struct {
	fluent.Schema
}

func (Schema) Annotations

func (Schema) Annotations() []schema.Annotation

Annotations of the schema.

func (Schema) Config

func (Schema) Config() Config

Config of the schema.

func (Schema) Edges

func (Schema) Edges() []Edge

Edges of the schema.

func (Schema) Fields

func (Schema) Fields() []Field

Fields of the schema.

func (Schema) Hooks

func (Schema) Hooks() []Hook

Hooks of the schema.

func (Schema) Indexes

func (Schema) Indexes() []Index

Indexes of the schema.

func (Schema) Interceptors

func (Schema) Interceptors() []Interceptor

Interceptors of the schema.

func (Schema) Mixin

func (Schema) Mixin() []Mixin

Mixin of the schema.

func (Schema) Policy

func (Schema) Policy() Policy

Policy of the schema.

type TraverseFunc

type TraverseFunc func(context.Context, Query) error

The TraverseFunc type is an adapter to allow the use of ordinary function as Traverser. If f is a function with the appropriate signature, TraverseFunc(f) is a Traverser that calls f.

func (TraverseFunc) Intercept

func (f TraverseFunc) Intercept(next Querier) Querier

Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.

func (TraverseFunc) Traverse

func (f TraverseFunc) Traverse(ctx context.Context, q Query) error

Traverse calls f(ctx, q).

type Traverser

type Traverser interface {
	Traverse(context.Context, Query) error
}

Traverser defines a graph-traversal middleware for various types of Ent queries. Contrary to Interceptors, the Traverse are executed on graph traversals before the query is executed. For example:

fluent.TraverseFunc(func(ctx context.Context, q fluent.Query) error {
	// Filter out deleted pets.
	if pq, ok := q.(*gen.PetQuery); ok {
		pq.Where(pet.DeletedAtIsNil())
	}
	return nil
})

client.Pet.Query().
	QueryOwner().	// Pet traverse functions are applied and filter deleted pets.
	All(ctx)	// User traverse and interceptor functions are applied.

type Value

type Value any

Value represents a dynamic value returned by mutations or queries.

type View

type View struct {
	Schema
}

A View only schema describes an entity that all its operations are limited to read-only. For example, a database view.

Users that wants to define a view schema should embed the View struct in their schema as follows:

type V struct {
	fluent.View
}

type Viewer

type Viewer interface {
	// contains filtered or unexported methods
}

Viewer is an interface that wraps the view method. Implemented by the View struct.

Directories

Path Synopsis
cmd
flc
internal/base
Package base defines shared basic pieces of the fluent command.
Package base defines shared basic pieces of the fluent command.
gremlin/graph/dsl
Package dsl provide an API for writing gremlin dsl queries almost as-is in Go without using strings in the code.
Package dsl provide an API for writing gremlin dsl queries almost as-is in Go without using strings in the code.
sql
Package sql provides wrappers around the standard database/sql package to allow the generated code to interact with a statically-typed API.
Package sql provides wrappers around the standard database/sql package to allow the generated code to interact with a statically-typed API.
sql/schema
Package schema contains all schema migration logic for SQL dialects.
Package schema contains all schema migration logic for SQL dialects.
sql/sqlgraph
Package sqlgraph provides graph abstraction capabilities on top of sql-based databases for fluent codegen.
Package sqlgraph provides graph abstraction capabilities on top of sql-based databases for fluent codegen.
examples module
flc
Package flc provides an interface for interacting with flc (ent codegen) as a package rather than an executable.
Package flc provides an interface for interacting with flc (ent codegen) as a package rather than an executable.
gen
Package gen is the interface for generating loaded schemas into a Go package.
Package gen is the interface for generating loaded schemas into a Go package.
load
Package load is the interface for loading an fluent/schema package into a Go program.
Package load is the interface for loading an fluent/schema package into a Go program.
integration Module
internal/todo/fluent/schema/schematype
Package schematype provides custom types for fluent/schema.
Package schematype provides custom types for fluent/schema.
internal/todo_fed/fluent/schema/schematype
Package schematype provides custom types for fluent/schema.
Package schematype provides custom types for fluent/schema.
internal/todo_pulid/fluent/schema/pulid
Package pulid implements the pulid type.
Package pulid implements the pulid type.
Package fluent_ql provides an experimental API for interacting dynamically with fluent queries.
Package fluent_ql provides an experimental API for interacting dynamically with fluent queries.
internal
A codegen cmd for generating builder types from template.
A codegen cmd for generating builder types from template.
Package privacy provides sets of types and helpers for writing privacy rules in user schemas, and deal with their evaluation at runtime.
Package privacy provides sets of types and helpers for writing privacy rules in user schemas, and deal with their evaluation at runtime.
field/internal
gen is a codegen cmd for generating numeric build types from template.
gen is a codegen cmd for generating numeric build types from template.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL