customfields

package
v0.8.1 Latest Latest
Warning

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

Go to latest
Published: Apr 4, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package customfields implements GoatKit PaaS Core universal custom fields.

Custom fields provide an EAV (Entity-Attribute-Value) store that works across all GoatKit entities. Plugins declare fields at registration; the platform handles storage, validation, UI rendering, and querying.

Index

Constants

View Source
const (
	EntityTicket        = "ticket"
	EntityArticle       = "article"
	EntityContact       = "contact"
	EntityAgent         = "agent"
	EntityGroup         = "group"
	EntityCustomerGroup = "customer_group"
	EntityQueue         = "queue"
	EntityOrganisation  = "organisation"
)

Supported entity types.

View Source
const (
	FieldText        = "text"
	FieldTextArea    = "textarea"
	FieldInteger     = "integer"
	FieldDecimal     = "decimal"
	FieldBoolean     = "boolean"
	FieldDate        = "date"
	FieldDateTime    = "datetime"
	FieldSelect      = "select"
	FieldMultiSelect = "multi_select"
	FieldURL         = "url"
	FieldEmail       = "email"
	FieldPhone       = "phone"
	FieldPoint       = "point"
	FieldPolygon     = "polygon"
	FieldAddress     = "address"
)

Supported field types.

View Source
const (
	OwnerPlugin = "plugin"
	OwnerAdmin  = "admin"
	OwnerLegacy = "legacy"
)

Owner types.

View Source
const (
	OpIncrement = "increment"
	OpAppend    = "append"
	OpRemove    = "remove"
	OpCAS       = "cas"
	OpToggle    = "toggle"
)

Atomic operation names for FieldOp.

Variables

This section is empty.

Functions

func IsValidEntityType

func IsValidEntityType(et string) bool

IsValidEntityType checks whether the given entity type is supported.

func IsValidFieldType

func IsValidFieldType(ft string) bool

IsValidFieldType checks whether the given field type is supported.

func MigrateLegacyFields

func MigrateLegacyFields(logger *slog.Logger) error

MigrateLegacyFields copies legacy dynamic_field definitions and values into the gk_custom_field_* tables. This is idempotent and safe to run on every startup. Legacy tables are never modified.

func StorageColumn

func StorageColumn(fieldType string) string

StorageColumn returns the primary storage column name for a given field type.

func ValidEntityTypes

func ValidEntityTypes() []string

ValidEntityTypes returns all supported entity type keys.

func ValidFieldOps added in v0.8.1

func ValidFieldOps() []string

ValidFieldOps returns all supported atomic operation names.

func ValidFieldTypes

func ValidFieldTypes() []string

ValidFieldTypes returns all supported field type keys.

func ValidFilterOperators

func ValidFilterOperators() []string

ValidFilterOperators returns all supported filter operators.

func ValidateFieldDef

func ValidateFieldDef(f *FieldDef) error

ValidateFieldDef validates a custom field definition before create/update.

func ValidateFieldOp added in v0.8.1

func ValidateFieldOp(def *FieldDef, op *FieldOp) error

ValidateFieldOp validates an atomic operation against its field definition.

func ValidateValue

func ValidateValue(def *FieldDef, val any) error

ValidateValue validates a single value against its field definition. Returns nil if valid. If val is a FieldOp, it delegates to ValidateFieldOp.

func ValidateValues

func ValidateValues(defs map[string]*FieldDef, values map[string]any) map[string]string

ValidateValues validates all values in a map against their field definitions. Returns a map of field_name → error message for any invalid values.

Types

type Address

type Address struct {
	Line1    string  `json:"line1,omitempty"`
	Line2    string  `json:"line2,omitempty"`
	City     string  `json:"city,omitempty"`
	Region   string  `json:"region,omitempty"`
	Postcode string  `json:"postcode,omitempty"`
	Country  string  `json:"country,omitempty"`
	Lat      float64 `json:"lat,omitempty"`
	Lng      float64 `json:"lng,omitempty"`
}

Address represents a structured address stored in val_json for address fields.

type FieldConfig

type FieldConfig struct {
	// text / textarea
	MaxLength  *int   `json:"max_length,omitempty"`
	Regex      string `json:"regex,omitempty"`
	RegexError string `json:"regex_error,omitempty"`

	// select / multi_select
	Options     []SelectOption `json:"options,omitempty"`
	AllowEmpty  bool           `json:"allow_empty,omitempty"`
	MinSelected *int           `json:"min_selected,omitempty"`
	MaxSelected *int           `json:"max_selected,omitempty"`

	// integer / decimal
	Min  *float64 `json:"min,omitempty"`
	Max  *float64 `json:"max,omitempty"`
	Step *float64 `json:"step,omitempty"`

	// date / datetime
	MinDate    string `json:"min_date,omitempty"`
	MaxDate    string `json:"max_date,omitempty"`
	FutureOnly bool   `json:"future_only,omitempty"`

	// point
	DefaultZoom   *int    `json:"default_zoom,omitempty"`
	DefaultCenter *LatLng `json:"default_center,omitempty"`

	// address
	Countries       []string `json:"countries,omitempty"`
	GeocodeProvider string   `json:"geocode_provider,omitempty"`

	// url
	AllowedSchemes []string `json:"allowed_schemes,omitempty"`

	// full-text search opt-in
	Searchable bool `json:"searchable,omitempty"`
}

FieldConfig holds type-specific configuration stored in the config JSON column. Not all fields apply to all types — each field type uses a subset.

type FieldDef

type FieldDef struct {
	ID           int64            `json:"id" db:"id"`
	Name         string           `json:"name" db:"name"`
	Label        string           `json:"label" db:"label"`
	EntityType   string           `json:"entity_type" db:"entity_type"`
	FieldType    string           `json:"field_type" db:"field_type"`
	OwnerType    string           `json:"owner_type" db:"owner_type"`
	OwnerName    *string          `json:"owner_name,omitempty" db:"owner_name"`
	MigratedFrom *int64           `json:"migrated_from,omitempty" db:"migrated_from"`
	Section      string           `json:"section" db:"section"`
	FieldOrder   int              `json:"field_order" db:"field_order"`
	Description  *string          `json:"description,omitempty" db:"description"`
	Placeholder  *string          `json:"placeholder,omitempty" db:"placeholder"`
	Required     bool             `json:"required" db:"required"`
	Config       *json.RawMessage `json:"config,omitempty" db:"config"`
	ValidID      int              `json:"valid_id" db:"valid_id"`
	CreateTime   time.Time        `json:"create_time" db:"create_time"`
	CreateBy     int              `json:"create_by" db:"create_by"`
	ChangeTime   time.Time        `json:"change_time" db:"change_time"`
	ChangeBy     int              `json:"change_by" db:"change_by"`
}

FieldDef represents a custom field definition from gk_custom_field_def.

func (*FieldDef) IsActive

func (f *FieldDef) IsActive() bool

IsActive returns true if this field definition is valid/enabled.

func (*FieldDef) ParsedConfig

func (f *FieldDef) ParsedConfig() (*FieldConfig, error)

ParsedConfig returns the parsed type-specific configuration.

type FieldFilter

type FieldFilter struct {
	Field    string `json:"field"`
	Operator string `json:"operator"` // eq, neq, gt, lt, gte, lte, like, in, between, near
	Value    any    `json:"value"`
	Value2   any    `json:"value2,omitempty"` // second value for between (upper bound) and near (radius km)
}

FieldFilter is a query filter for CustomFieldsQuery.

type FieldOp added in v0.8.1

type FieldOp struct {
	Op      string   `json:"op"`
	Value   any      `json:"value,omitempty"`
	Expect  any      `json:"expect,omitempty"`
	Floor   *float64 `json:"floor,omitempty"`
	Ceiling *float64 `json:"ceiling,omitempty"`
}

FieldOp represents an atomic operation on a custom field value. This is the internal mirror of plugin.FieldOp.

func AsFieldOp added in v0.8.1

func AsFieldOp(val any) (*FieldOp, bool)

AsFieldOp detects whether val is a FieldOp (either a direct struct or a JSON-decoded map with an "op" key, as arrives from gRPC plugins).

type FieldValue

type FieldValue struct {
	ID          int64            `json:"id" db:"id"`
	FieldID     int64            `json:"field_id" db:"field_id"`
	ObjectID    int64            `json:"object_id" db:"object_id"`
	ValText     *string          `json:"val_text,omitempty" db:"val_text"`
	ValInt      *int64           `json:"val_int,omitempty" db:"val_int"`
	ValDecimal  *float64         `json:"val_decimal,omitempty" db:"val_decimal"`
	ValDecimal2 *float64         `json:"val_decimal2,omitempty" db:"val_decimal2"`
	ValDate     *time.Time       `json:"val_date,omitempty" db:"val_date"`
	ValDatetime *time.Time       `json:"val_datetime,omitempty" db:"val_datetime"`
	ValJSON     *json.RawMessage `json:"val_json,omitempty" db:"val_json"`
}

FieldValue represents a stored value from gk_custom_field_value.

type LatLng

type LatLng struct {
	Lat float64 `json:"lat"`
	Lng float64 `json:"lng"`
}

LatLng represents a geographic coordinate.

type Repository

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

Repository provides CRUD operations for custom field definitions and values.

func NewRepository

func NewRepository() (*Repository, error)

NewRepository creates a new custom fields repository using the global DB connection.

func NewRepositoryWithDB

func NewRepositoryWithDB(db *sql.DB) *Repository

NewRepositoryWithDB creates a new custom fields repository with an explicit DB connection.

func (*Repository) CreateDef

func (r *Repository) CreateDef(f *FieldDef, userID int) (int64, error)

CreateDef inserts a new field definition. Returns the new row ID.

func (*Repository) GetDef

func (r *Repository) GetDef(id int64) (*FieldDef, error)

GetDef retrieves a single field definition by ID.

func (*Repository) GetDefByEntityAndName

func (r *Repository) GetDefByEntityAndName(entityType, name string) (*FieldDef, error)

GetDefByEntityAndName retrieves a field definition by entity type and name.

func (*Repository) GetValues

func (r *Repository) GetValues(entityType string, objectID int64, fieldNames []string) (map[string]any, error)

GetValues retrieves all custom field values for an entity, joined with definitions. If fieldNames is non-empty, only those fields are returned.

func (*Repository) HardDeleteDef

func (r *Repository) HardDeleteDef(id int64) error

HardDeleteDef removes a field definition and all its values permanently.

func (*Repository) ListDefs

func (r *Repository) ListDefs(entityType, ownerType, ownerName string, activeOnly bool) ([]FieldDef, error)

ListDefs retrieves field definitions with optional filters.

func (*Repository) QueryByFields

func (r *Repository) QueryByFields(entityType string, filters []FieldFilter) ([]int64, error)

QueryByFields finds entity object IDs matching the given custom field filters.

func (*Repository) SetValues

func (r *Repository) SetValues(entityType string, objectID int64, values map[string]any) error

SetValues stores custom field values for an entity. values is field_name → value (or field_name → FieldOp for atomic operations). The caller is responsible for validation.

func (*Repository) SoftDeleteDef

func (r *Repository) SoftDeleteDef(id int64, userID int) error

SoftDeleteDef marks a field as invalid (valid_id=2). Data is preserved.

func (*Repository) UpdateDef

func (r *Repository) UpdateDef(f *FieldDef, userID int) error

UpdateDef updates an existing field definition.

type SelectOption

type SelectOption struct {
	Value string `json:"value"`
	Label string `json:"label"`
}

SelectOption represents a single option in a select or multi_select field.

Jump to

Keyboard shortcuts

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