Documentation
¶
Overview ¶
Package materialized provides utilities for working with materialized paths in tree structures. Materialized paths are a technique for representing hierarchical data in relational databases that optimizes read operations.
Index ¶
- Constants
- Variables
- func IsValidNodeID(nid *NodeID) bool
- func Validate(nid NodeID) error
- func ValidateNil(nid *NodeID) error
- func ValidatePath(path string) error
- type Code
- type NodeID
- type NodeIDs
- type OwnerFields
- type Path
- func (p Path) AppendNode(nodeID NodeID) (Path, error)
- func (p Path) Contains(sub Path) bool
- func (p Path) Depth() int
- func (p Path) GetAncestorAtDepth(depth int) (Path, error)
- func (p Path) GetLastNodeID() (NodeID, error)
- func (p Path) GetNodeIDs() NodeIDs
- func (p Path) GetPathPrefix() string
- func (p Path) IsDescendantOf(ancestor Path) bool
- func (p Path) IsDirectParentOf(child Path) bool
- func (p Path) IsRoot() bool
- func (p Path) Parent() (Path, error)
- type TableConfig
- type TenantFields
- type TreeNode
- type TreeQuery
- func (tq *TreeQuery) BatchCreateNodes(nodes []struct{ ... }, tenantID, tenantType string) ([]*TreeNode, error)
- func (tq *TreeQuery) CreateNode(name string, parentPath Path, tenantID, tenantType string, ...) (node *TreeNode, err error)
- func (tq *TreeQuery) CreateNodeQuery(tx *gorm.DB, name string, parentPath Path, tenantID, tenantType string, ...) (*TreeNode, *gorm.DB, error)
- func (tq *TreeQuery) DeleteNode(nodePath Path, tenantID, tenantType string, deleteDescendants bool) error
- func (tq *TreeQuery) GetAncestors(nodePath Path, tenantID, tenantType string) ([]*TreeNode, error)
- func (tq *TreeQuery) GetAncestorsNested(nodePath Path, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetAncestorsQuery(tx *gorm.DB, nodePath Path, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetChildrenByCode(code Code, tenantID, tenantType string) ([]*TreeNode, error)
- func (tq *TreeQuery) GetChildrenByCodeQuery(tx *gorm.DB, code Code, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetChildrenByParentID(code *Code, tenantID, tenantType string) ([]*TreeNode, error)
- func (tq *TreeQuery) GetChildrenByParentIDQuery(tx *gorm.DB, code *Code, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetChildrenByPath(parentPath Path, tenantID, tenantType string) ([]*TreeNode, error)
- func (tq *TreeQuery) GetChildrenByPathQuery(tx *gorm.DB, parentPath Path, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetDescendants(parentPath Path, tenantID, tenantType string) ([]*TreeNode, error)
- func (tq *TreeQuery) GetDescendantsQuery(tx *gorm.DB, parentPath Path, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetNodeByCode(code Code, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetNodeByCodeQuery(tx *gorm.DB, code Code, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetNodeByID(id any, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetNodeByIDQuery(tx *gorm.DB, id any, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetNodeByPath(path Path, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetNodeByPathQuery(tx *gorm.DB, path Path, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetNodeWithChildrenByCode(code Code, tenantID, tenantType string, limit int, offset int) (node *TreeNode, count int64, err error)
- func (tq *TreeQuery) GetNodeWithChildrenByCodeQuery(tx *gorm.DB, tenantID, tenantType string, code Code, limit, offset int) (*gorm.DB, *TreeNode, int64, error)
- func (tq *TreeQuery) GetNodeWithChildrenByPath(path Path, tenantID, tenantType string, limit int, offset int) (*TreeNode, int64, error)
- func (tq *TreeQuery) GetNodeWithChildrenByPathQuery(tx *gorm.DB, tenantID, tenantType string, path Path, limit, offset int) (*gorm.DB, *TreeNode, int64, error)
- func (tq *TreeQuery) GetNodesByDepth(depth int, tenantID, tenantType string) ([]*TreeNode, error)
- func (tq *TreeQuery) GetNodesByDepthQuery(tx *gorm.DB, depth int, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetNodesByOwner(ownerID, ownerType, tenantID, tenantType string, limit int, offset int) ([]*TreeNode, int64, error)
- func (tq *TreeQuery) GetNodesByOwnerQuery(ownerID, ownerType, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetParentByCode(code Code, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetParentByCodeQuery(tx *gorm.DB, code Code, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetParentByID(id any, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetParentByIDQuery(tx *gorm.DB, id any, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetParentByNode(node *TreeNode, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetParentByNodeQuery(tx *gorm.DB, node *TreeNode, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetParentByPath(nodePath Path, tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetParentByPathQuery(tx *gorm.DB, nodePath Path, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) GetRootNode(tenantID, tenantType string) (*TreeNode, error)
- func (tq *TreeQuery) GetRootNodeQuery(tx *gorm.DB, tenantID, tenantType string) *gorm.DB
- func (tq *TreeQuery) Migrate(m any) error
- func (tq *TreeQuery) MigrateDefault() error
- func (tq *TreeQuery) MoveNode(nodePath Path, newParentPath Path, tenantID, tenantType string) error
- func (tq *TreeQuery) SearchNodes(query string, tenantID, tenantType string, limit int, offset int) ([]*TreeNode, int64, error)
- func (tq *TreeQuery) UpdateNode(code Code, tenantID, tenantType string, updates map[string]interface{}) error
- func (tq *TreeQuery) UpdateNodeQuery(tx *gorm.DB, code Code, tenantID, tenantType string, ...) (*gorm.DB, error)
- func (tq *TreeQuery) WithTransaction(tx *gorm.DB) *TreeQuery
Constants ¶
const ( // PathSeparator is the character used to separate node IDs in a path PathSeparator = "/" // RootPath represents the path of a root node RootPath = Path(PathSeparator) )
const ( CondID = "id = ?" CondPathCol = "%s = ?" )
Variables ¶
var ( // ErrInvalidPath is returned when an invalid path is provided ErrInvalidPath = errors.New("invalid materialized path") // ErrInvalidNodeID is returned when an invalid node ID is provided ErrInvalidNodeID = errors.New("invalid node ID") )
var ( ErrUnauthorized = errors.New("unauthorized access") // ErrInvalidTableConfig is returned when table configuration is invalid ErrInvalidTableConfig = errors.New("invalid table configuration") )
Functions ¶
func IsValidNodeID ¶
func ValidateNil ¶
Types ¶
type OwnerFields ¶
type Path ¶
type Path string
Path represents a materialized path in the tree
func (Path) AppendNode ¶
AppendNode creates a new path by appending a node ID to the current path
func (Path) Contains ¶
Contains checks if the current path contains another path. This is used to determine if a node is an ancestor of another node.
For example: - path "a/b" contains "a/b/c" (true) - path "a/b" contains "a/b" (false, not a descendant) - path "a/b" contains "a/c" (false, different branch) - root "/" contains "a/b" (true, root contains all) - path "a/b" contains "/" (false, cannot contain root)
The function handles three cases: 1. If current path is root - contains all non-root paths 2. If sub path is root - nothing can contain root 3. Otherwise checks if sub path starts with current path + separator
func (Path) GetAncestorAtDepth ¶
GetAncestorAtDepth returns the ancestor path at the specified depth
func (Path) GetLastNodeID ¶
GetLastNodeID returns the ID of the last node in the path
func (Path) GetNodeIDs ¶
GetNodeIDs returns a slice of NodeIDs extracted from the path. For a root path, it returns an empty slice. For non-root paths, it splits the path and converts each segment into a NodeID. GetNodeIDs returns all node IDs in the path
func (Path) GetPathPrefix ¶
GetPathPrefix returns a SQL LIKE pattern for finding all descendants of this path
func (Path) IsDescendantOf ¶
IsDescendantOf checks if the current path is a descendant of another path
func (Path) IsDirectParentOf ¶
IsDirectParentOf checks if the current path is the direct parent of another path
type TableConfig ¶
type TableConfig struct {
// TableName is the name of the table in the database
TableName string
}
TableConfig holds configuration for the tree table
func DefaultTableConfig ¶
func DefaultTableConfig() TableConfig
DefaultTableConfig returns the default table configuration
type TenantFields ¶
type TreeNode ¶
type TreeNode struct {
gorm.Model
// Code is a unique node identifier
Code Code `json:"code,omitempty" gorm:"column:code;uniqueIndex:idx_code,sort:asc"`
// Tenancy fields
Tenant TenantFields `json:"tenant_fields,omitempty" gorm:"embedded"`
// Parent-child relationship
ParentID *Code `json:"parent_id,omitempty" gorm:"column:parent_id;size:26;index:idx_parent_id;default:null"`
Parent *TreeNode `json:"parent,omitempty" gorm:"foreignKey:ParentID;references:Code"`
Children []*TreeNode `json:"children,omitempty" gorm:"foreignKey:ParentID;references:Code"`
Path Path `json:"path,omitempty" gorm:"column:path;index:idx_path"`
Name string `json:"name,omitempty" gorm:"column:name"`
// Owner fields
Owner OwnerFields `json:"owner_fields,omitempty" gorm:"embedded"`
}
TreeNode represents a node in the materialized path tree
type TreeQuery ¶
type TreeQuery struct {
// contains filtered or unexported fields
}
TreeQuery provides methods for querying the tree structure
func NewTreeQuery ¶
func NewTreeQuery(db *gorm.DB, config TableConfig) (*TreeQuery, error)
NewTreeQuery creates a new TreeQuery instance
func (*TreeQuery) BatchCreateNodes ¶
func (tq *TreeQuery) BatchCreateNodes( nodes []struct { Name string ParentPath Path OwnerID string OwnerType string }, tenantID, tenantType string, ) ([]*TreeNode, error)
BatchCreateNodes creates multiple nodes in a single transaction
func (*TreeQuery) CreateNode ¶
func (tq *TreeQuery) CreateNode( name string, parentPath Path, tenantID, tenantType string, ownerID, ownerType string, ) (node *TreeNode, err error)
CreateNode creates a new node in the tree
func (*TreeQuery) CreateNodeQuery ¶
func (tq *TreeQuery) CreateNodeQuery( tx *gorm.DB, name string, parentPath Path, tenantID, tenantType string, ownerID, ownerType string, ) (*TreeNode, *gorm.DB, error)
CreateNodeQuery creates a new node query in the tree
func (*TreeQuery) DeleteNode ¶
func (tq *TreeQuery) DeleteNode( nodePath Path, tenantID, tenantType string, deleteDescendants bool, ) error
DeleteNode deletes a node and optionally its descendants
func (*TreeQuery) GetAncestors ¶
GetAncestors retrieves all ancestors of a node
func (*TreeQuery) GetAncestorsNested ¶
func (tq *TreeQuery) GetAncestorsNested(nodePath Path, tenantID, tenantType string) (*TreeNode, error)
GetAncestorsNested retrieves all ancestors of a node in a nested structure
func (*TreeQuery) GetAncestorsQuery ¶
func (tq *TreeQuery) GetAncestorsQuery(tx *gorm.DB, nodePath Path, tenantID, tenantType string) *gorm.DB
GetAncestorsQuery returns a query builder for retrieving all ancestors of a node
func (*TreeQuery) GetChildrenByCode ¶
GetChildrenByCode retrieves all direct children of a node by its code
func (*TreeQuery) GetChildrenByCodeQuery ¶
func (*TreeQuery) GetChildrenByParentID ¶
func (tq *TreeQuery) GetChildrenByParentID(code *Code, tenantID, tenantType string) ([]*TreeNode, error)
GetChildrenByParentID retrieves all direct children of a node
func (*TreeQuery) GetChildrenByParentIDQuery ¶
func (*TreeQuery) GetChildrenByPath ¶
func (tq *TreeQuery) GetChildrenByPath(parentPath Path, tenantID, tenantType string) ([]*TreeNode, error)
GetChildrenByPath retrieves all direct children of a node by its path This is an alternative method that uses the path when node ID is not available
func (*TreeQuery) GetChildrenByPathQuery ¶
func (tq *TreeQuery) GetChildrenByPathQuery(tx *gorm.DB, parentPath Path, tenantID, tenantType string) *gorm.DB
GetChildrenByPathQuery returns a query builder for retrieving all direct children of a node by its path
func (*TreeQuery) GetDescendants ¶
func (tq *TreeQuery) GetDescendants(parentPath Path, tenantID, tenantType string) ([]*TreeNode, error)
GetDescendants retrieves all descendants of a node
func (*TreeQuery) GetDescendantsQuery ¶
func (tq *TreeQuery) GetDescendantsQuery(tx *gorm.DB, parentPath Path, tenantID, tenantType string) *gorm.DB
GetDescendantsQuery returns a query builder for retrieving all descendants of a node
func (*TreeQuery) GetNodeByCode ¶
GetNodeByCode retrieves a node by its code with tenant security
func (*TreeQuery) GetNodeByCodeQuery ¶
func (*TreeQuery) GetNodeByID ¶
GetNodeByID retrieves a node by its ID with tenant security
func (*TreeQuery) GetNodeByIDQuery ¶
func (*TreeQuery) GetNodeByPath ¶
GetNodeByPath retrieves a node by its path with tenant security
func (*TreeQuery) GetNodeByPathQuery ¶
func (*TreeQuery) GetNodeWithChildrenByCode ¶
func (tq *TreeQuery) GetNodeWithChildrenByCode( code Code, tenantID, tenantType string, limit int, offset int, ) (node *TreeNode, count int64, err error)
GetNodeWithChildrenByCode retrieves a node with its direct children preloaded using the node code with pagination support for the children
func (*TreeQuery) GetNodeWithChildrenByCodeQuery ¶
func (tq *TreeQuery) GetNodeWithChildrenByCodeQuery( tx *gorm.DB, tenantID, tenantType string, code Code, limit, offset int, ) (*gorm.DB, *TreeNode, int64, error)
GetNodeWithChildrenByCodeQuery returns a query builder for retrieving a node with its direct children by code
func (*TreeQuery) GetNodeWithChildrenByPath ¶
func (tq *TreeQuery) GetNodeWithChildrenByPath( path Path, tenantID, tenantType string, limit int, offset int, ) (*TreeNode, int64, error)
GetNodeWithChildrenByPath retrieves a node with its direct children preloaded using the node path with pagination support for the children
func (*TreeQuery) GetNodeWithChildrenByPathQuery ¶
func (tq *TreeQuery) GetNodeWithChildrenByPathQuery( tx *gorm.DB, tenantID, tenantType string, path Path, limit, offset int, ) (*gorm.DB, *TreeNode, int64, error)
GetNodeWithChildrenByPathQuery returns a query builder for retrieving a node with its direct children by path
func (*TreeQuery) GetNodesByDepth ¶
func (tq *TreeQuery) GetNodesByDepth( depth int, tenantID, tenantType string, ) ([]*TreeNode, error)
GetNodesByDepth retrieves nodes at a specific depth in the tree
func (*TreeQuery) GetNodesByDepthQuery ¶
func (tq *TreeQuery) GetNodesByDepthQuery( tx *gorm.DB, depth int, tenantID, tenantType string, ) *gorm.DB
GetNodesByDepthQuery returns a query builder for nodes at a specific depth in the tree
func (*TreeQuery) GetNodesByOwner ¶
func (tq *TreeQuery) GetNodesByOwner( ownerID, ownerType, tenantID, tenantType string, limit int, offset int, ) ([]*TreeNode, int64, error)
GetNodesByOwner retrieves nodes associated with a specific owner
func (*TreeQuery) GetNodesByOwnerQuery ¶
func (tq *TreeQuery) GetNodesByOwnerQuery( ownerID, ownerType, tenantID, tenantType string, ) *gorm.DB
GetNodesByOwnerQuery returns a query builder for nodes associated with a specific owner
func (*TreeQuery) GetParentByCode ¶
GetParentByCode retrieves the parent of a node by its code
func (*TreeQuery) GetParentByCodeQuery ¶
func (*TreeQuery) GetParentByID ¶
GetParentByID retrieves the parent of a node
func (*TreeQuery) GetParentByIDQuery ¶
func (*TreeQuery) GetParentByNode ¶
func (*TreeQuery) GetParentByNodeQuery ¶
func (*TreeQuery) GetParentByPath ¶
GetParentByPath retrieves the parent of a node by its path
func (*TreeQuery) GetParentByPathQuery ¶
func (*TreeQuery) GetRootNode ¶
GetRootNode retrieves the root node for a tenant
func (*TreeQuery) GetRootNodeQuery ¶
GetRootNodeQuery returns a query builder for the root node
func (*TreeQuery) MigrateDefault ¶
MigrateDefault creates the database schema for the tree table
func (*TreeQuery) MoveNode ¶
func (tq *TreeQuery) MoveNode( nodePath Path, newParentPath Path, tenantID, tenantType string, ) error
MoveNode moves a node and all its descendants to a new parent
func (*TreeQuery) SearchNodes ¶
func (tq *TreeQuery) SearchNodes( query string, tenantID, tenantType string, limit int, offset int, ) ([]*TreeNode, int64, error)
SearchNodes searches for nodes by name or metadata with tenant security
func (*TreeQuery) UpdateNode ¶
func (tq *TreeQuery) UpdateNode( code Code, tenantID, tenantType string, updates map[string]interface{}, ) error
UpdateNode updates a node's properties