Adding upstream version 0.28.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
88f1d47ab6
commit
e28c88ef14
933 changed files with 194711 additions and 0 deletions
252
core/field.go
Normal file
252
core/field.go
Normal file
|
@ -0,0 +1,252 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||
"github.com/pocketbase/pocketbase/core/validators"
|
||||
"github.com/pocketbase/pocketbase/tools/list"
|
||||
)
|
||||
|
||||
var fieldNameRegex = regexp.MustCompile(`^\w+$`)
|
||||
|
||||
const maxSafeJSONInt int64 = 1<<53 - 1
|
||||
|
||||
// Commonly used field names.
|
||||
const (
|
||||
FieldNameId = "id"
|
||||
FieldNameCollectionId = "collectionId"
|
||||
FieldNameCollectionName = "collectionName"
|
||||
FieldNameExpand = "expand"
|
||||
FieldNameEmail = "email"
|
||||
FieldNameEmailVisibility = "emailVisibility"
|
||||
FieldNameVerified = "verified"
|
||||
FieldNameTokenKey = "tokenKey"
|
||||
FieldNamePassword = "password"
|
||||
)
|
||||
|
||||
// SystemFields returns special internal field names that are usually readonly.
|
||||
var SystemDynamicFieldNames = []string{
|
||||
FieldNameCollectionId,
|
||||
FieldNameCollectionName,
|
||||
FieldNameExpand,
|
||||
}
|
||||
|
||||
// Common RecordInterceptor action names.
|
||||
const (
|
||||
InterceptorActionValidate = "validate"
|
||||
InterceptorActionDelete = "delete"
|
||||
InterceptorActionDeleteExecute = "deleteExecute"
|
||||
InterceptorActionAfterDelete = "afterDelete"
|
||||
InterceptorActionAfterDeleteError = "afterDeleteError"
|
||||
InterceptorActionCreate = "create"
|
||||
InterceptorActionCreateExecute = "createExecute"
|
||||
InterceptorActionAfterCreate = "afterCreate"
|
||||
InterceptorActionAfterCreateError = "afterCreateFailure"
|
||||
InterceptorActionUpdate = "update"
|
||||
InterceptorActionUpdateExecute = "updateExecute"
|
||||
InterceptorActionAfterUpdate = "afterUpdate"
|
||||
InterceptorActionAfterUpdateError = "afterUpdateError"
|
||||
)
|
||||
|
||||
// Common field errors.
|
||||
var (
|
||||
ErrUnknownField = validation.NewError("validation_unknown_field", "Unknown or invalid field.")
|
||||
ErrInvalidFieldValue = validation.NewError("validation_invalid_field_value", "Invalid field value.")
|
||||
ErrMustBeSystemAndHidden = validation.NewError("validation_must_be_system_and_hidden", `The field must be marked as "System" and "Hidden".`)
|
||||
ErrMustBeSystem = validation.NewError("validation_must_be_system", `The field must be marked as "System".`)
|
||||
)
|
||||
|
||||
// FieldFactoryFunc defines a simple function to construct a specific Field instance.
|
||||
type FieldFactoryFunc func() Field
|
||||
|
||||
// Fields holds all available collection fields.
|
||||
var Fields = map[string]FieldFactoryFunc{}
|
||||
|
||||
// Field defines a common interface that all Collection fields should implement.
|
||||
type Field interface {
|
||||
// note: the getters has an explicit "Get" prefix to avoid conflicts with their related field members
|
||||
|
||||
// GetId returns the field id.
|
||||
GetId() string
|
||||
|
||||
// SetId changes the field id.
|
||||
SetId(id string)
|
||||
|
||||
// GetName returns the field name.
|
||||
GetName() string
|
||||
|
||||
// SetName changes the field name.
|
||||
SetName(name string)
|
||||
|
||||
// GetSystem returns the field system flag state.
|
||||
GetSystem() bool
|
||||
|
||||
// SetSystem changes the field system flag state.
|
||||
SetSystem(system bool)
|
||||
|
||||
// GetHidden returns the field hidden flag state.
|
||||
GetHidden() bool
|
||||
|
||||
// SetHidden changes the field hidden flag state.
|
||||
SetHidden(hidden bool)
|
||||
|
||||
// Type returns the unique type of the field.
|
||||
Type() string
|
||||
|
||||
// ColumnType returns the DB column definition of the field.
|
||||
ColumnType(app App) string
|
||||
|
||||
// PrepareValue returns a properly formatted field value based on the provided raw one.
|
||||
//
|
||||
// This method is also called on record construction to initialize its default field value.
|
||||
PrepareValue(record *Record, raw any) (any, error)
|
||||
|
||||
// ValidateSettings validates the current field value associated with the provided record.
|
||||
ValidateValue(ctx context.Context, app App, record *Record) error
|
||||
|
||||
// ValidateSettings validates the current field settings.
|
||||
ValidateSettings(ctx context.Context, app App, collection *Collection) error
|
||||
}
|
||||
|
||||
// MaxBodySizeCalculator defines an optional field interface for
|
||||
// specifying the max size of a field value.
|
||||
type MaxBodySizeCalculator interface {
|
||||
// CalculateMaxBodySize returns the approximate max body size of a field value.
|
||||
CalculateMaxBodySize() int64
|
||||
}
|
||||
|
||||
type (
|
||||
SetterFunc func(record *Record, raw any)
|
||||
|
||||
// SetterFinder defines a field interface for registering custom field value setters.
|
||||
SetterFinder interface {
|
||||
// FindSetter returns a single field value setter function
|
||||
// by performing pattern-like field matching using the specified key.
|
||||
//
|
||||
// The key is usually just the field name but it could also
|
||||
// contains "modifier" characters based on which you can perform custom set operations
|
||||
// (ex. "users+" could be mapped to a function that will append new user to the existing field value).
|
||||
//
|
||||
// Return nil if you want to fallback to the default field value setter.
|
||||
FindSetter(key string) SetterFunc
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
GetterFunc func(record *Record) any
|
||||
|
||||
// GetterFinder defines a field interface for registering custom field value getters.
|
||||
GetterFinder interface {
|
||||
// FindGetter returns a single field value getter function
|
||||
// by performing pattern-like field matching using the specified key.
|
||||
//
|
||||
// The key is usually just the field name but it could also
|
||||
// contains "modifier" characters based on which you can perform custom get operations
|
||||
// (ex. "description:excerpt" could be mapped to a function that will return an excerpt of the current field value).
|
||||
//
|
||||
// Return nil if you want to fallback to the default field value setter.
|
||||
FindGetter(key string) GetterFunc
|
||||
}
|
||||
)
|
||||
|
||||
// DriverValuer defines a Field interface for exporting and formatting
|
||||
// a field value for the database.
|
||||
type DriverValuer interface {
|
||||
// DriverValue exports a single field value for persistence in the database.
|
||||
DriverValue(record *Record) (driver.Value, error)
|
||||
}
|
||||
|
||||
// MultiValuer defines a field interface that every multi-valued (eg. with MaxSelect) field has.
|
||||
type MultiValuer interface {
|
||||
// IsMultiple checks whether the field is configured to support multiple or single values.
|
||||
IsMultiple() bool
|
||||
}
|
||||
|
||||
// RecordInterceptor defines a field interface for reacting to various
|
||||
// Record related operations (create, delete, validate, etc.).
|
||||
type RecordInterceptor interface {
|
||||
// Interceptor is invoked when a specific record action occurs
|
||||
// allowing you to perform extra validations and normalization
|
||||
// (ex. uploading or deleting files).
|
||||
//
|
||||
// Note that users must call actionFunc() manually if they want to
|
||||
// execute the specific record action.
|
||||
Intercept(
|
||||
ctx context.Context,
|
||||
app App,
|
||||
record *Record,
|
||||
actionName string,
|
||||
actionFunc func() error,
|
||||
) error
|
||||
}
|
||||
|
||||
// DefaultFieldIdValidationRule performs base validation on a field id value.
|
||||
func DefaultFieldIdValidationRule(value any) error {
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return validators.ErrUnsupportedValueType
|
||||
}
|
||||
|
||||
rules := []validation.Rule{
|
||||
validation.Required,
|
||||
validation.Length(1, 100),
|
||||
}
|
||||
|
||||
for _, r := range rules {
|
||||
if err := r.Validate(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// exclude special filter and system literals
|
||||
var excludeNames = append([]any{
|
||||
"null", "true", "false", "_rowid_",
|
||||
}, list.ToInterfaceSlice(SystemDynamicFieldNames)...)
|
||||
|
||||
// DefaultFieldIdValidationRule performs base validation on a field name value.
|
||||
func DefaultFieldNameValidationRule(value any) error {
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return validators.ErrUnsupportedValueType
|
||||
}
|
||||
|
||||
rules := []validation.Rule{
|
||||
validation.Required,
|
||||
validation.Length(1, 100),
|
||||
validation.Match(fieldNameRegex),
|
||||
validation.NotIn(excludeNames...),
|
||||
validation.By(checkForVia),
|
||||
}
|
||||
|
||||
for _, r := range rules {
|
||||
if err := r.Validate(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkForVia(value any) error {
|
||||
v, _ := value.(string)
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.Contains(strings.ToLower(v), "_via_") {
|
||||
return validation.NewError("validation_found_via", `The value cannot contain "_via_".`)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func noopSetter(record *Record, raw any) {
|
||||
// do nothing
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue