expr

package
v0.0.0-...-c4472bd Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2025 License: GPL-2.0 Imports: 16 Imported by: 1

Documentation

Index

Constants

View Source
const SELF_TABLE = "SELF" // the name of the self table, used in expressions

Variables

View Source
var (
	ErrCastTypeNotImplemented errors.Error = errors.New(
		"CastTypeNotImplemented",
		"cast type is not implemented",
	)
	ErrCastTypeNoColumnProvided errors.Error = errors.New(
		"CastTypeNoColumnProvided",
		"cast type requires a column to be provided",
	)
)
View Source
var (
	CastString  = newCastFunc(CastTypeString)
	CastText    = newCastFunc(CastTypeText)
	CastInt     = newCastFunc(CastTypeInt)
	CastFloat   = newCastFunc(CastTypeFloat)
	CastBool    = newCastFunc(CastTypeBool)
	CastDate    = newCastFunc(CastTypeDate)
	CastTime    = newCastFunc(CastTypeTime)
	CastBytes   = newCastFunc(CastTypeBytes)
	CastDecimal = newCastFunc(CastTypeDecimal)
	CastJSON    = newCastFunc(CastTypeJSON)
	CastUUID    = newCastFunc(CastTypeUUID)
	CastNull    = newCastFunc(CastTypeNull)
	CastArray   = newCastFunc(CastTypeArray)
)
View Source
var (
	ErrLookupNotFound    errors.Error = errors.New("LookupNotFound", "lookup not found")
	ErrTransformNotFound errors.Error = errors.New("TransformNotFound", "transform not found")
	ErrLookupArgsInvalid errors.Error = errors.New("LookupArgsInvalid", "lookup arguments invalid")
)
View Source
var PARSER = &statement{
	Field: &statementParser{
		typ:     "field",
		pattern: `\!\[([a-zA-Z][a-zA-Z0-9_.-]*)\]`,
		rawtext: func(in []string) string {
			return in[1]
		},
		resolve: func(nodeIndex int, typIndex int, in []string, info *ExpressionInfo, args []any, data any) (string, []any, error) {
			var fieldName = in[1]
			info.SupportsWhereAlias = false
			info.SupportsAsExpr = false

			var resolvedField = info.ResolveExpressionField(fieldName)
			return resolvedField.SQLText, resolvedField.SQLArgs, nil
		},
	},
	Table: &statementParser{
		typ:     "table",
		pattern: `(?:(?i)table)\(([a-zA-Z][a-zA-Z0-9_.-]*)\)`,
		rawtext: func(in []string) string {
			return in[1]
		},
		resolve: func(nodeIndex int, typIndex int, in []string, info *ExpressionInfo, args []any, data any) (string, []any, error) {
			var fieldPath = in[1]
			if strings.EqualFold(fieldPath, SELF_TABLE) {
				var meta = attrs.GetModelMeta(info.Model)
				var defs = meta.Definitions()
				return info.QuoteIdentifier(defs.TableName()), []any{}, nil
			}

			var _, field, _, err = info.Resolver.Resolve(fieldPath, info)
			if err != nil {
				return "", []any{}, fmt.Errorf(
					"error when walking fields: %w", err,
				)
			}

			var rel = field.Rel()
			if rel == nil {
				return "", []any{}, fmt.Errorf(
					"field %q is not a relation, cannot resolve table name", fieldPath,
				)
			}

			var (
				current        = rel.Model()
				defs           = current.FieldDefs()
				tableName      = defs.TableName()
				lhs_tableName  = info.QuoteIdentifier(tableName)
				rhs_tableAlias = info.QuoteIdentifier(info.Resolver.Alias().GetTableAlias(
					defs.TableName(), fieldPath,
				))
			)

			return fmt.Sprintf("%s AS %s", lhs_tableName, rhs_tableAlias), []any{}, nil
		},
	},
	Value: &statementParser{
		typ:     "value",
		pattern: `(?:\?\[([0-9]+)\])|\?`,
		rawtext: func(in []string) string {
			return "?"
		},
		resolve: func(nodeIndex int, typIndex int, in []string, info *ExpressionInfo, args []any, data any) (string, []any, error) {
			var valIdx = 0
			if len(in) > 1 && in[1] != "" {
				var err error
				valIdx, err = strconv.Atoi(in[1])
				if err != nil {
					return "", []any{}, fmt.Errorf("invalid index %q in statement: %w", in[1], err)
				}
				valIdx--
			} else {
				valIdx = typIndex
			}
			if valIdx < 0 || valIdx >= len(args) {
				return "", nil, fmt.Errorf("index %d out of range in statement for %d arguments", valIdx, len(args))
			}
			var val = args[valIdx]

			if expr, ok := val.(Expression); ok {
				var exprStr strings.Builder
				var exprParams = expr.Resolve(info).SQL(&exprStr)
				return exprStr.String(), exprParams, nil
			}

			return "?", []any{val}, nil
		},
	},
	Expr: &expressionParser{
		statementParser: statementParser{
			typ:     "expr",
			pattern: `(?:(?i)expr)\(((?:[a-zA-Z][a-zA-Z0-9_.-]*|[0-9]*))\)`,
			rawtext: func(in []string) string {
				return in[1]
			},
			resolve: func(nodeIndex int, typIndex int, in []string, info *ExpressionInfo, args []any, data any) (string, []any, error) {
				if data == nil {
					return "", nil, fmt.Errorf("expression data is nil for expr statement")
				}

				var exprData, ok = data.(*expressionData)
				if !ok {
					return "", nil, fmt.Errorf("invalid expression data type for expr statement")
				}

				var (
					exprId = in[1]
					expr   Expression
				)

				if unicode.IsDigit(rune(exprId[0])) {
					var idx, err = strconv.Atoi(exprId)
					if err != nil {
						return "", nil, fmt.Errorf("invalid expression index %q: %w", exprId, err)
					}
					if idx < 0 || idx >= len(exprData._list) {
						return "", nil, fmt.Errorf("expression index %d out of range for %d expressions", idx, len(exprData._list))
					}

					expr = exprData._list[idx]

					goto buildExpression
				}

				expr, ok = exprData._map[exprId]
				if !ok {
					return "", nil, fmt.Errorf("expression %q not found in data", exprId)
				}

			buildExpression:
				var exprStr strings.Builder
				var exprParams = expr.
					Resolve(info).
					SQL(&exprStr)

				return exprStr.String(), exprParams, nil
			},
		},
	},
}

Functions

func AddParentSubqueryContext

func AddParentSubqueryContext(ctx context.Context, inf *ExpressionInfo) context.Context

func GetLookup

func GetLookup(inf *ExpressionInfo, lookupName string, lhs any, args []any) (func(sb *strings.Builder) []any, error)

GetLookup retrieves a lookup function based on the provided expression info, lookup name, inner expression, and arguments. It returns a function that can be used to build a SQL string with the lookup applied. The LHS will need to be either an Expression (RESOLVED ALREADY!) or a sql `table`.`column` pair.

func IsSubqueryContext

func IsSubqueryContext(ctx context.Context) bool

func MakeSubqueryContext

func MakeSubqueryContext(ctx context.Context) context.Context

func RegisterCastType

func RegisterCastType(castType CastType, entry CastFuncEntry, drivers ...driver.Driver)

func RegisterFunc

func RegisterFunc(funcName string, fn func(d driver.Driver, value []Expression, funcParams []any) (sql string, args []any, err error), drivers ...driver.Driver)

func RegisterLookup

func RegisterLookup(Lookup Lookup)

func RegisterTransforms

func RegisterTransforms(transforms ...LookupTransform)

func StatementParserArg

func StatementParserArg(which string, data any) any

StatementParserArg creates a parserArg for the given type and data.

a parserArg is a special case used in ExpressionStatement.Resolve to pass additional data to a registered parser.

Types

type AliasField

type AliasField interface {
	attrs.Field
	Alias() string
}

A field can adhere to this interface to indicate that the field should be aliased when generating the SQL for the field.

For example: this is used in annotations to alias the field name.

type BaseLookup

type BaseLookup struct {
	AllowedDrivers []driver.Driver
	Identifier     LookupFilter
	ArgMin         int
	ArgMax         int
	Normalize      func(any) any
	ResolveFunc    func(inf *ExpressionInfo, lhsResolved ResolvedExpression, values []any) LookupExpression
}

func (*BaseLookup) Arity

func (l *BaseLookup) Arity() (min, max int)

func (*BaseLookup) Drivers

func (l *BaseLookup) Drivers() []driver.Driver

func (*BaseLookup) Name

func (l *BaseLookup) Name() string

func (*BaseLookup) NormalizeArgs

func (l *BaseLookup) NormalizeArgs(inf *ExpressionInfo, values []any) ([]any, error)

func (*BaseLookup) Resolve

func (l *BaseLookup) Resolve(inf *ExpressionInfo, lhsResolved ResolvedExpression, values []any) func(sb *strings.Builder) []any

type BaseTransform

type BaseTransform struct {
	AllowedDrivers []driver.Driver
	//	Transforms     []string
	//	Lookups        []string
	Identifier string
	Transform  func(inf *ExpressionInfo, lhsResolved ResolvedExpression) (ResolvedExpression, error)
}

func (*BaseTransform) Drivers

func (t *BaseTransform) Drivers() []driver.Driver

func (*BaseTransform) Name

func (t *BaseTransform) Name() string

func (*BaseTransform) Resolve

func (t *BaseTransform) Resolve(inf *ExpressionInfo, lhsResolved ResolvedExpression) (ResolvedExpression, error)

type CaseExpression

type CaseExpression struct {
	// contains filtered or unexported fields
}

func Case

func Case(cases ...any) *CaseExpression

func (*CaseExpression) Clone

func (c *CaseExpression) Clone() Expression

func (*CaseExpression) Default

func (c *CaseExpression) Default(value any) *CaseExpression

func (*CaseExpression) Resolve

func (c *CaseExpression) Resolve(inf *ExpressionInfo) Expression

func (*CaseExpression) SQL

func (c *CaseExpression) SQL(sb *strings.Builder) []any

func (*CaseExpression) Then

func (c *CaseExpression) Then(value any) *CaseExpression

func (*CaseExpression) When

func (c *CaseExpression) When(keyOrExpr interface{}, vals ...any) *CaseExpression

type CastFuncEntry

type CastFuncEntry struct {
	Arity int
	SQL   string
}

type CastType

type CastType uint
const (
	CastTypeUnknown CastType = iota
	CastTypeString
	CastTypeText
	CastTypeInt
	CastTypeFloat
	CastTypeBool
	CastTypeDate
	CastTypeTime
	CastTypeBytes
	CastTypeDecimal
	CastTypeJSON
	CastTypeUUID
	CastTypeNull
	CastTypeArray
)

type ClauseExpression

type ClauseExpression interface {
	Expression
	IsNot() bool
	Not(b bool) ClauseExpression
	And(...Expression) ClauseExpression
	Or(...Expression) ClauseExpression
}

func Express

func Express(key interface{}, vals ...interface{}) []ClauseExpression

type ExprGroup

type ExprGroup struct {
	// contains filtered or unexported fields
}

ExprGroup

func And

func And[T any](exprs ...T) *ExprGroup

func Or

func Or[T any](exprs ...T) *ExprGroup

func (*ExprGroup) And

func (g *ExprGroup) And(exprs ...Expression) ClauseExpression

func (*ExprGroup) Clone

func (g *ExprGroup) Clone() Expression

func (*ExprGroup) IsNot

func (g *ExprGroup) IsNot() bool

func (*ExprGroup) Not

func (g *ExprGroup) Not(not bool) ClauseExpression

func (*ExprGroup) Operator

func (g *ExprGroup) Operator() ExprOp

func (*ExprGroup) Or

func (g *ExprGroup) Or(exprs ...Expression) ClauseExpression

func (*ExprGroup) Resolve

func (g *ExprGroup) Resolve(inf *ExpressionInfo) Expression

func (*ExprGroup) SQL

func (g *ExprGroup) SQL(sb *strings.Builder) []any

func (*ExprGroup) Unwrap

func (g *ExprGroup) Unwrap() []Expression

type ExprNode

type ExprNode struct {
	// contains filtered or unexported fields
}

func Expr

func Expr(field any, operation string, value ...any) *ExprNode

func Q

func Q(fieldLookup LookupFilter, value ...any) *ExprNode

func (*ExprNode) And

func (e *ExprNode) And(exprs ...Expression) ClauseExpression

func (*ExprNode) Clone

func (e *ExprNode) Clone() Expression

func (*ExprNode) IsNot

func (e *ExprNode) IsNot() bool

func (*ExprNode) Not

func (e *ExprNode) Not(not bool) ClauseExpression

func (*ExprNode) Or

func (e *ExprNode) Or(exprs ...Expression) ClauseExpression

func (*ExprNode) Resolve

func (e *ExprNode) Resolve(inf *ExpressionInfo) Expression

func (*ExprNode) SQL

func (e *ExprNode) SQL(sb *strings.Builder) []any

type ExprOp

type ExprOp string

ExprOp represents the expression operator to use in a query.

It is used to combine multiple expressions in a logical expression.

const (
	OpAnd ExprOp = "AND"
	OpOr  ExprOp = "OR"
)

type Expression

type Expression interface {
	ResolvedExpression
	Clone() Expression
	Resolve(inf *ExpressionInfo) Expression
}

func Raw

func Raw(statement string, value ...any) Expression

func V

func V(v any, unsafe ...bool) Expression

V is a shorthand for Value, allowing for a more concise syntax. See Value for more information.

func Value

func Value(v any, unsafe ...bool) Expression

Value is a function that creates a value expression. It is used to represent a value in SQL queries, allowing for both safe and unsafe usage. It can be used like so:

Value("some value") // safe usage
Value("some value", true) // unsafe usage, will not use placeholders

The unsafe usage allows for direct insertion of values into the SQL query, which can be dangerous if not used carefully.

func Values

func Values(vs ...any) Expression

Values creates a values expression from a slice of values. It is used to represent multiple values in SQL queries, allowing for both safe and unsafe usage. It can be used like so:

Values([]any{"value1", "value2"})

type ExpressionBuilder

type ExpressionBuilder interface {
	BuildExpression() Expression
}

type ExpressionInfo

type ExpressionInfo struct {
	// Driver is the driver used to execute the query.
	Driver driver.Driver

	// Model is the base model of the queryset.
	Model attrs.Definer

	// Resolver is the field resolver used to resolve fields in the queryset.
	Resolver FieldResolver

	// Placeholder is the placeholder to use in the query.
	//
	// It is used to format the placeholders in the query.
	Placeholder string

	// FormatField is a function that formats the field for the SQL query.
	//
	// It takes a TableColumn and returns the formatted field as a string
	// and a slice of possible args that can be used in the query.
	FormatField func(*alias.Generator, *TableColumn) (string, []any)

	// Quote is a function that quotes the given string for use in a SQL query.
	Quote func(string) string

	// QuoteIdentifier is a function that quotes the given identifier for use in a SQL query.
	//
	// It should be used to quote table names, column names, and other identifiers such as aliases.
	//
	// It should only be used for advanced use cases, such as when creating custom expressions
	// or when there is no other way to format an identifier (see [ExpressionStatement.Resolve] for example).
	QuoteIdentifier func(string) string

	// Lookups provides information about how to format the lookups
	// used in the query.
	Lookups ExpressionLookupInfo

	// ForUpdate specifies if the expression is used in an UPDATE statement
	// or UPDATE- like statement.
	//
	// This will automatically append "= ?" to the SQL TableColumn statement
	ForUpdate bool

	// SupportsWhereExpressionAlias indicates if the database supports WHERE expressions with aliases.
	SupportsWhereAlias bool

	// SupportsAsExpr indicates if the current method of building expressions support aliasing the expression.
	SupportsAsExpr bool

	// Annotations is a map of queryset annotations (fields).
	Annotations *orderedmap.OrderedMap[string, attrs.Field]
}

func ParentFromSubqueryContext

func ParentFromSubqueryContext(ctx context.Context) (*ExpressionInfo, bool)

func (*ExpressionInfo) ResolveExpressionField

func (inf *ExpressionInfo) ResolveExpressionField(fieldName string) *ResolvedField

type ExpressionLookupInfo

type ExpressionLookupInfo struct {
	// PrepForLikeQuery is a function that prepares the value for a LIKE query.
	//
	// It takes any value and returns a string that is properly formatted and
	// escaped for use in a LIKE query.
	PrepForLikeQuery func(any) string

	// FormatLookupCol is a function that formats the left-hand side and right-hand side of
	// a lookup operation in the query.
	//
	// It takes the operator and the left-hand side value and returns a formatted string.
	// This is used to format the left-hand side of an operator in the query for iexact, icontains, etc.
	//
	// The default compiler has a format function for the following operators:
	//
	// - iexact
	// - icontains
	// - istartswith
	// - iendswith
	FormatLookupCol func(string, string) string

	// LogicalOpRHS is a map of logical operators to functions that format the right-hand side of the operator.
	//
	// It takes the logical operator and the right-hand side value and returns a formatted string.
	//
	// The defualt compiler has logical operators for:
	//
	// - EQ
	// - NE
	// - GT
	// - LT
	// - GTE
	// - LTE
	// - ADD
	// - SUB
	// - MUL
	// - DIV
	// - MOD
	// - BITAND
	// - BITOR
	// - BITXOR
	// - BITLSH
	// - BITRSH
	// - BITNOT
	LogicalOpRHS map[LogicalOp]func(rhs string, value []any) (string, []any)

	// Operators is a map of lookup operations to format strings.
	//
	// It is used to format the operators in the query.
	//
	// Use ExpressionInfo.FormatOp(...) to format the operator.
	//
	// The default compiler has operators for:
	//
	// - iexact
	// - contains
	// - icontains
	// - regex
	// - iregex
	// - startswith
	// - endswith
	// - istartswith
	// - iendswith
	OperatorsRHS map[string]string

	// PatternOps is a map of pattern operators to format strings.
	//
	// It is used to format operators when the operator is used as
	// an expression in a pattern match, such as 'contains' or 'icontains'.
	//
	// Use ExpressionInfo.PatternOp(...) to format the pattern operator.
	//
	// The default compiler supports pattern operators for:
	//
	// - contains
	// - icontains
	// - startswith
	// - endswith
	// - istartswith
	// - iendswith
	PatternOpsRHS map[string]string
}

func (*ExpressionLookupInfo) FormatLogicalOpRHS

func (inf *ExpressionLookupInfo) FormatLogicalOpRHS(op LogicalOp, rhs string, values ...any) (string, []any)

func (*ExpressionLookupInfo) FormatOpRHS

func (inf *ExpressionLookupInfo) FormatOpRHS(op string, fmtArgs ...any) string

func (*ExpressionLookupInfo) PatternOpRHS

func (inf *ExpressionLookupInfo) PatternOpRHS(op string, fmtArgs ...any) string

type ExpressionStatement

type ExpressionStatement struct {
	Statement string
	Values    []any
	// contains filtered or unexported fields
}

func ParseExprStatement

func ParseExprStatement(statement string, value []any) *ExpressionStatement

The statement should contain placeholders for the fields and values, which will be replaced with the actual values.

The placeholders for fields should be in the format ![FieldName], and the placeholders for values should be in the format ?[Index], or the values should use the regular SQL placeholder directly (database driver dependent).

Example usage:

 stmt := ParseExprStatement(
		"SELECT * FROM ![Table] WHERE ![Field1] = ?[0] AND ![Field2] = ?[1] AND EXPR(MyExpression)",
		"users", 42, "active",
     expr.PARSER.Expressions(map[string]expr.Expression{
			"MyExpression": expr.Q("Field2", "MyTitle")
		})
	)

func (*ExpressionStatement) Clone

func (*ExpressionStatement) Raw

func (s *ExpressionStatement) Raw(which string) []string

func (*ExpressionStatement) Resolve

func (*ExpressionStatement) SQL

func (s *ExpressionStatement) SQL() (string, []any)

type FieldResolver

type FieldResolver interface {
	Alias() *alias.Generator
	Peek() QueryInformation
	Context() context.Context
	Resolve(fieldName string, inf *ExpressionInfo) (model attrs.Definer, field attrs.FieldDefinition, col *TableColumn, err error)
}

type Function

type Function struct {
	// contains filtered or unexported fields
}

func (*Function) Clone

func (e *Function) Clone() Expression

func (*Function) FieldName

func (e *Function) FieldName() string

func (*Function) Resolve

func (e *Function) Resolve(inf *ExpressionInfo) Expression

func (*Function) SQL

func (e *Function) SQL(sb *strings.Builder) []any

type InLookup

type InLookup struct {
	BaseLookup
}

func (*InLookup) Arity

func (l *InLookup) Arity() (min, max int)

func (*InLookup) NormalizeArgs

func (l *InLookup) NormalizeArgs(inf *ExpressionInfo, values []any) ([]any, error)

func (*InLookup) Resolve

func (l *InLookup) Resolve(inf *ExpressionInfo, resolvedExpression ResolvedExpression, values []any) func(sb *strings.Builder) []any

type IsNullLookup

type IsNullLookup struct {
	BaseLookup
}

func (*IsNullLookup) Arity

func (l *IsNullLookup) Arity() (min, max int)

func (*IsNullLookup) NormalizeArgs

func (l *IsNullLookup) NormalizeArgs(inf *ExpressionInfo, values []any) ([]any, error)

func (*IsNullLookup) Resolve

func (l *IsNullLookup) Resolve(inf *ExpressionInfo, resolvedExpression ResolvedExpression, values []any) func(sb *strings.Builder) []any

type Join

type Join interface {
	TableName() string
	TableAlias() string
	Type() JoinType
	Condition() JoinCondition
}

type JoinCondition

type JoinCondition interface {
	// LHS returns the left-hand side of the join condition.
	LHS() TableColumn

	// RHS returns the right-hand side of the join condition.
	RHS() TableColumn

	// Op returns the operator used in the join condition.
	Op() LogicalOp

	// NextCondition returns the next join condition, if any.
	NextCondition() JoinCondition
}

type JoinType

type JoinType string

JoinType represents the type of join to use in a query.

It is used to specify how to join two tables in a query.

const (
	TypeJoinLeft  JoinType = "LEFT JOIN"
	TypeJoinRight JoinType = "RIGHT JOIN"
	TypeJoinInner JoinType = "INNER JOIN"
	TypeJoinFull  JoinType = "FULL JOIN"
	TypeJoinCross JoinType = "CROSS JOIN"
)

type LogicalExpression

type LogicalExpression interface {
	Expression
	Scope(LogicalOp, Expression) LogicalExpression
	EQ(key interface{}, vals ...interface{}) LogicalExpression
	NE(key interface{}, vals ...interface{}) LogicalExpression
	GT(key interface{}, vals ...interface{}) LogicalExpression
	LT(key interface{}, vals ...interface{}) LogicalExpression
	GTE(key interface{}, vals ...interface{}) LogicalExpression
	LTE(key interface{}, vals ...interface{}) LogicalExpression
	ADD(key interface{}, vals ...interface{}) LogicalExpression
	SUB(key interface{}, vals ...interface{}) LogicalExpression
	MUL(key interface{}, vals ...interface{}) LogicalExpression
	DIV(key interface{}, vals ...interface{}) LogicalExpression
	MOD(key interface{}, vals ...interface{}) LogicalExpression
	BITAND(key interface{}, vals ...interface{}) LogicalExpression
	BITOR(key interface{}, vals ...interface{}) LogicalExpression
	BITXOR(key interface{}, vals ...interface{}) LogicalExpression
	BITLSH(key interface{}, vals ...interface{}) LogicalExpression
	BITRSH(key interface{}, vals ...interface{}) LogicalExpression
	BITNOT(key interface{}, vals ...interface{}) LogicalExpression
}

func Logical

func Logical(expr ...any) LogicalExpression

type LogicalLookup

type LogicalLookup struct {
	BaseLookup
	Operator LogicalOp
}

func (*LogicalLookup) NormalizeArgs

func (l *LogicalLookup) NormalizeArgs(inf *ExpressionInfo, values []any) ([]any, error)

func (*LogicalLookup) Resolve

func (l *LogicalLookup) Resolve(inf *ExpressionInfo, lhsResolved ResolvedExpression, values []any) func(sb *strings.Builder) []any

type LogicalNamedExpressionFunc

type LogicalNamedExpressionFunc interface {
	NamedExpression
	LogicalExpression
}

func AVG

func AVG(expr ...any) LogicalNamedExpressionFunc

func COALESCE

func COALESCE(expr ...any) LogicalNamedExpressionFunc

func CONCAT

func CONCAT(expr ...any) LogicalNamedExpressionFunc

func COUNT

func COUNT(expr ...any) LogicalNamedExpressionFunc

func DATE

func DATE_FORMAT

func DATE_FORMAT(expr any, format string) LogicalNamedExpressionFunc

func EXISTS

func EXISTS(expr any) LogicalNamedExpressionFunc

func LENGTH

func LENGTH(expr any) LogicalNamedExpressionFunc

func LOCALTIMESTAMP

func LOCALTIMESTAMP() LogicalNamedExpressionFunc

func LOWER

func LOWER(expr any) LogicalNamedExpressionFunc

func MAX

func MAX(expr ...any) LogicalNamedExpressionFunc

func MIN

func MIN(expr ...any) LogicalNamedExpressionFunc

func SUBSTR

func SUBSTR(expr any, start, length any) LogicalNamedExpressionFunc

func SUM

func SUM(expr ...any) LogicalNamedExpressionFunc

func UPPER

func UPPER(expr any) LogicalNamedExpressionFunc

func UTCNOW

type LogicalOp

type LogicalOp string

LogicalOp represents the logical operator to use in a query.

It is used to compare two values in a logical expression. The logical operators are used in the WHERE clause of a SQL query, or inside of queryset join conditions.

const (
	EQ  LogicalOp = "="
	NE  LogicalOp = "!="
	GT  LogicalOp = ">"
	LT  LogicalOp = "<"
	GTE LogicalOp = ">="
	LTE LogicalOp = "<="
	IN  LogicalOp = "IN"

	ADD LogicalOp = "+"
	SUB LogicalOp = "-"
	MUL LogicalOp = "*"
	DIV LogicalOp = "/"
	MOD LogicalOp = "%"

	BITAND LogicalOp = "&"
	BITOR  LogicalOp = "|"
	BITXOR LogicalOp = "^"
	BITLSH LogicalOp = "<<"
	BITRSH LogicalOp = ">>"
	BITNOT LogicalOp = "~"
)

func Op

func Op(op any) (LogicalOp, bool)

func (LogicalOp) Clone

func (op LogicalOp) Clone() Expression

func (LogicalOp) Resolve

func (op LogicalOp) Resolve(*ExpressionInfo) Expression

func (LogicalOp) SQL

func (op LogicalOp) SQL(sb *strings.Builder) []any

type Lookup

type Lookup interface {
	// returns the drivers that support this lookup
	// if empty, the lookup is supported by all drivers
	Drivers() []driver.Driver

	// name of the lookup
	Name() string

	// number of arguments the lookup expects, or -1 for variable arguments
	Arity() (min, max int)

	// normalize the arguments for the lookup
	NormalizeArgs(inf *ExpressionInfo, value []any) ([]any, error)

	// Resolve resolves the lookup for the given field and value
	// and generates an expression for the lookup.
	Resolve(inf *ExpressionInfo, lhsResolved ResolvedExpression, args []any) LookupExpression
}

type LookupExpression

type LookupExpression = func(sb *strings.Builder) []any

type LookupField

type LookupField interface {
	attrs.FieldDefinition
	AllowedTransforms() []string
	AllowedLookups() []string
}

type LookupFilter

type LookupFilter = string
const (
	LOOKUP_EXACT LookupFilter = "exact"
	LOOKUP_NOT   LookupFilter = "not"
	LOOKUP_GT    LookupFilter = "gt"
	LOOKUP_LT    LookupFilter = "lt"
	LOOKUP_GTE   LookupFilter = "gte"
	LOOKUP_LTE   LookupFilter = "lte"

	LOOKUP_BITAND LookupFilter = "bitand"
	LOOKUP_BITOR  LookupFilter = "bitor"
	LOOKUP_BITXOR LookupFilter = "bitxor"
	LOOKUP_BITLSH LookupFilter = "bitlsh"
	LOOKUP_BITRSH LookupFilter = "bitrsh"
	LOOKUP_BITNOT LookupFilter = "bitnot"

	LOOKUP_IEXACT      LookupFilter = "iexact"
	LOOKUP_CONTAINS    LookupFilter = "contains"
	LOOKUP_ICONTANS    LookupFilter = "icontains"
	LOOKUP_STARTSWITH  LookupFilter = "startswith"
	LOOKUP_ISTARTSWITH LookupFilter = "istartswith"
	LOOKUP_IENDSWITH   LookupFilter = "iendswith"
	LOOKUP_ENDSWITH    LookupFilter = "endswith"
	LOOKUP_IN          LookupFilter = "in"
	LOOKUP_ISNULL      LookupFilter = "isnull"
	LOOKUP_RANGE       LookupFilter = "range"

	DEFAULT_LOOKUP = LOOKUP_EXACT
)

type LookupTransform

type LookupTransform interface {
	// returns the drivers that support this transform
	// if empty, the transform is supported by all drivers
	Drivers() []driver.Driver

	// name of the transform
	Name() string

	// Resolves the expression and generates a new expressionq
	Resolve(inf *ExpressionInfo, lhsResolved ResolvedExpression) (ResolvedExpression, error)
}

type ModelMeta

type ModelMeta interface {
	Model() attrs.Definer
	TableName() string
	PrimaryKey() attrs.FieldDefinition
	OrderBy() []string
}

type NamedExpression

type NamedExpression interface {
	Expression
	FieldName() string
}

func As

func As(name string, expr Expression) NamedExpression

As creates a NamedExpression with a specified field name and an expression.

It is used to give a name to an expression, which can be useful for annotations, or for updating fields in a model using [Expression]s.

func Cast

func Cast(typ CastType, col any, value ...any) NamedExpression

func Chain

func Chain(expr ...any) NamedExpression

func F

func F(statement any, value ...any) NamedExpression

F creates a new RawNamedExpression or chainExpr with the given statement and values. It parses the statement to extract the fields and values, and returns a pointer to the new RawNamedExpression.

The first field in the statement is used as the field name for the expression, and the rest of the fields are used as placeholders for the values.

The statement should contain placeholders for the fields and values, which will be replaced with the actual values.

The placeholders for fields should be in the format ![FieldName], and the placeholders for values should be in the format ?[Index], or the values should use the regular SQL placeholder directly (database driver dependent).

Example usage:

 # sets the field name to the first field found in the statement, I.E. ![Age]:

	expr := F("![Age] + ?[1] + ![Height] + ?[2] * ?[1]", 3, 4)
	fmt.Println(expr.SQL()) // prints: "table.age + ? + table.height + ? * ?"
	fmt.Println(expr.Args()) // prints: [3, 4, 3]

 # sets the field name to the first field found in the statement, I.E. ![Height]:

	expr := F("? + ? + ![Height] + ? * ?", 4, 5, 6, 7)
	fmt.Println(expr.SQL()) // prints: "? + ? + table.height + ? * ?"
	fmt.Println(expr.Args()) // prints: [4, 5, 6, 7]

func Field

func Field(fld string) NamedExpression

func OuterRef

func OuterRef(fld string) NamedExpression

type OrderBy

type OrderBy struct {
	Column TableColumn // The field to order by
	Desc   bool
}

OrderBy represents an order by clause in a query.

It contains the table to order by, the field to order by, an optional alias for the field, and a boolean indicating whether to order in descending order.

It is used to specify how to order the results of a query.

type PatternLookup

type PatternLookup struct {
	BaseLookup
	Pattern string
}

func (*PatternLookup) Arity

func (l *PatternLookup) Arity() (min, max int)

func (*PatternLookup) NormalizeArgs

func (l *PatternLookup) NormalizeArgs(inf *ExpressionInfo, value []any) ([]any, error)

func (*PatternLookup) Resolve

func (l *PatternLookup) Resolve(inf *ExpressionInfo, resolvedExpression ResolvedExpression, values []any) func(sb *strings.Builder) []any

type QueryInformation

type QueryInformation struct {
	Meta      ModelMeta
	Select    []attrs.FieldDefinition
	GroupBy   []attrs.FieldDefinition
	Joins     []Join
	Where     []ClauseExpression
	Having    []ClauseExpression
	Unions    []FieldResolver
	OrderBy   []OrderBy
	Limit     int
	Offset    int
	ForUpdate bool
	Distinct  bool
}

type RangeLookup

type RangeLookup struct {
	BaseLookup
}

func (*RangeLookup) Arity

func (l *RangeLookup) Arity() (min, max int)

func (*RangeLookup) Resolve

func (l *RangeLookup) Resolve(inf *ExpressionInfo, resolvedExpression ResolvedExpression, values []any) func(sb *strings.Builder) []any

type RawExpr

type RawExpr = RawNamedExpression

RawExpr is a function expression for SQL queries. It is used to represent a function call in SQL queries.

It can be used like so:

	RawExpr{
		// Represent the SQL function call, with each %s being replaced by the corresponding field in fields.
		Statement:    `SUBSTR(TRIM(%s, " "), 0, 2) = ?``,
     	// The fields to be used in the SQL function call. Each field will be replaced by the corresponding value in args.
		Fields: []string{"myField"},
		// The arguments to be used in the SQL function call. Each argument will be replaced by the corresponding value in args.
		Params:   []any{"ab"},
	}

type RawNamedExpression

type RawNamedExpression struct {
	Statement *ExpressionStatement // The statement to be executed, containing placeholders for fields and values.
	Field     string
	// contains filtered or unexported fields
}

func (*RawNamedExpression) Clone

func (e *RawNamedExpression) Clone() Expression

func (*RawNamedExpression) FieldName

func (e *RawNamedExpression) FieldName() string

func (*RawNamedExpression) Resolve

func (e *RawNamedExpression) Resolve(inf *ExpressionInfo) Expression

func (*RawNamedExpression) SQL

func (e *RawNamedExpression) SQL(sb *strings.Builder) []any

type ResolvedExpression

type ResolvedExpression interface {
	SQL(sb *strings.Builder) []any
}

type ResolvedField

type ResolvedField struct {
	FieldPath         string
	Field             string
	SQLText           string
	SQLArgs           []any
	AllowedTransforms []string
	AllowedLookups    []string
}

type StatementParser

type StatementParser interface {
	// return the type / identifier of the statement parser, e.g. "field", "table", "value", "expr"
	Type() string

	// should return a value created by StatementParserArg of type parserArg
	Data(v any) any

	// Compiled returns the compiled regex for the statement parser
	Compiled() *regexp.Regexp

	// CompiledAbs returns the compiled regex for the statement parser with anchors
	CompiledAbs() *regexp.Regexp

	// RawText returns the raw text of the statement parser, given the matched input, I.E. ![FieldName] -> FieldName
	RawText(in []string) string

	// Resolve resolves the statement parser, given the matched input, the expression info, the arguments and any additional data
	Resolve(nodesIndex int, typIndex int, in []string, info *ExpressionInfo, args []any, data any) (string, []any, error)
}

type String

type String string

StringExpr is a string type which implements the Expression interface. It is used to represent a string value in SQL queries.

It can be used like so, and supports no arguments:

StringExpr("a = b")

func (String) Clone

func (e String) Clone() Expression

func (String) Resolve

func (e String) Resolve(inf *ExpressionInfo) Expression

func (String) SQL

func (e String) SQL(sb *strings.Builder) []any

func (String) String

func (e String) String() string

type TableColumn

type TableColumn struct {
	// The table or alias to use in the join condition
	// If this is set, the FieldColumn must be specified
	TableOrAlias string

	// The alias for the field in the join condition.
	FieldAlias string

	// RawSQL is the raw SQL to use in the join condition
	RawSQL string

	// The field or column to use in the join condition
	FieldColumn attrs.FieldDefinition

	// ForUpdate specifies if the field should be used in an UPDATE statement
	// This will automatically append "= ?" to the SQL statement
	ForUpdate bool

	// The value to use for the placeholder if the field column is not specified
	Values []any
}

func (*TableColumn) Validate

func (c *TableColumn) Validate() error

type VirtualField

type VirtualField interface {
	attrs.FieldDefinition
	SQL(inf *ExpressionInfo) (string, []any)
}

A field can adhere to this interface to indicate that the field should be rendered as SQL.

For example: this is used in fields.ExpressionField to render the expression as SQL.

type WhenExpression

type WhenExpression = *when

func When

func When(keyOrExpr interface{}, vals ...any) WhenExpression

Jump to

Keyboard shortcuts

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