diff --git a/example/custom_matcher.go b/example/custom_matcher.go index ffacb1f..981d3d7 100644 --- a/example/custom_matcher.go +++ b/example/custom_matcher.go @@ -1,3 +1,4 @@ +// Package example provides example use cases of goven with a data model. package example import ( @@ -16,9 +17,10 @@ import ( ) const ( - KeyValueRegex = `(.+)\[(.+)\]` + keyValueRegex = `(.+)\[(.+)\]` ) +// Model represents an example machine learning model schema. type Model struct { gorm.Model Name string @@ -27,6 +29,7 @@ type Model struct { Tags []Tag `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"` } +// Tag is a string key value tag. type Tag struct { gorm.Model Key string @@ -34,11 +37,13 @@ type Tag struct { ModelID uint } +// ModelDAO is an example DAO for machine learning models. type ModelDAO struct { db *gorm.DB queryAdaptor *sql_adaptor.SqlAdaptor } +// NewModelDAO returns a ModelDAO. func NewModelDAO(db *gorm.DB) (*ModelDAO, error) { adaptor, err := CreateModelAdaptor() if err != nil { @@ -50,6 +55,7 @@ func NewModelDAO(db *gorm.DB) (*ModelDAO, error) { }, nil } +// CreateModel commits the provided model to the database. func (u *ModelDAO) CreateModel(model *Model) error { ctx := context.Background() tx := u.db.Begin().WithContext(ctx) @@ -61,6 +67,7 @@ func (u *ModelDAO) CreateModel(model *Model) error { return tx.Commit().Error } +// MakeQuery takes a goven query and performs it against the model database. func (u *ModelDAO) MakeQuery(q string) ([]Model, error) { var models []Model ctx := context.Background() @@ -77,12 +84,13 @@ func (u *ModelDAO) MakeQuery(q string) ([]Model, error) { return models, nil } +// CreateModelAdaptor creates a new SqlAdaptor for the model schema. func CreateModelAdaptor() (*sql_adaptor.SqlAdaptor, error) { matchers := map[*regexp.Regexp]sql_adaptor.ParseValidateFunc{} fieldMappings := map[string]string{} // Custom matcher initialised here. - reg, err := regexp.Compile(KeyValueRegex) + reg, err := regexp.Compile(keyValueRegex) if err != nil { return nil, err } @@ -95,7 +103,7 @@ func CreateModelAdaptor() (*sql_adaptor.SqlAdaptor, error) { // keyValueMatcher is a custom matcher for tags[x]. func keyValueMatcher(ex *parser.Expression) (*sql_adaptor.SqlResponse, error) { - reg, err := regexp.Compile(KeyValueRegex) + reg, err := regexp.Compile(keyValueRegex) if err != nil { return nil, err } diff --git a/example/simple.go b/example/simple.go index d1bd41d..6f95975 100644 --- a/example/simple.go +++ b/example/simple.go @@ -10,6 +10,7 @@ import ( "gorm.io/gorm" ) +// User represents an simple example database schema. type User struct { ID uint Name string @@ -20,11 +21,13 @@ type User struct { CreatedAt time.Time } +// UserDAO is an example DAO for user data. type UserDAO struct { db *gorm.DB queryAdaptor *sql_adaptor.SqlAdaptor } +// NewUserDAO returns a UserDAO. func NewUserDAO(db *gorm.DB) (*UserDAO, error) { reflection := reflect.ValueOf(&User{}) adaptor := sql_adaptor.NewDefaultAdaptorFromStruct(reflection) @@ -34,6 +37,7 @@ func NewUserDAO(db *gorm.DB) (*UserDAO, error) { }, nil } +// CreateUser commits the provided user to the database. func (u *UserDAO) CreateUser(user *User) error { ctx := context.Background() tx := u.db.Begin().WithContext(ctx) @@ -45,6 +49,7 @@ func (u *UserDAO) CreateUser(user *User) error { return tx.Commit().Error } +// MakeQuery takes a goven query and performs it against the user database. func (u *UserDAO) MakeQuery(q string) ([]User, error) { var users []User ctx := context.Background() diff --git a/integration/integration_custom_matcher_test.go b/integration/integration_custom_matcher_test.go index 220cf2d..7126c0d 100644 --- a/integration/integration_custom_matcher_test.go +++ b/integration/integration_custom_matcher_test.go @@ -1,3 +1,4 @@ +// Package integration contains integration tests using the example DAOs. package integration import ( diff --git a/parser/lexer.go b/parser/lexer.go index 6dfa96a..ace6c37 100644 --- a/parser/lexer.go +++ b/parser/lexer.go @@ -1,3 +1,4 @@ +// Package parser contains the definitions of the base tokens, the lexer that converts a query to a token stream, and the parser that converts a token stream into an AST. package parser import ( @@ -12,6 +13,7 @@ type Lexer struct { r *bufio.Reader } +// NewLexerFromString returns a Lexer for the provided string. func NewLexerFromString(s string) *Lexer { return NewLexer(strings.NewReader(s)) } diff --git a/parser/nodes.go b/parser/nodes.go index 9e0ed61..f86b9c7 100644 --- a/parser/nodes.go +++ b/parser/nodes.go @@ -27,13 +27,18 @@ type Operation struct { RightNode Node } +// Type returns the type for expression. func (e Expression) Type() string { return EXPRESSION } -func (o Operation) Type() string { return OPERATION } +// Type returns the type for operation. +func (o Operation) Type() string { return OPERATION } + +// String returns the string representation of expression. func (e Expression) String() string { return fmt.Sprintf("%v %v %v", e.Field, e.Comparator, e.Value) } +// String returns the string representation of operation. func (o Operation) String() string { if o.Gate == "" { return fmt.Sprintf("(%v)", o.LeftNode) diff --git a/parser/parser.go b/parser/parser.go index 7a2eb89..9eab22e 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -19,6 +19,7 @@ func NewParser(s string) *Parser { return &Parser{s: NewLexer(strings.NewReader(s)), raw: s} } +// Parse takes the raw string and returns the root node of the AST. func (p *Parser) Parse() (Node, error) { operation, err := p.parseOperation() if err != nil { diff --git a/parser/stack.go b/parser/stack.go index b0a8bdf..a7311b7 100644 --- a/parser/stack.go +++ b/parser/stack.go @@ -9,10 +9,12 @@ type TokenStack struct { stack []TokenInfo } +// Push pushes a token to the TokenStack. func (s *TokenStack) Push(v TokenInfo) { s.stack = append(s.stack, v) } +// Pop removes and returns a token from the TokenStack. func (s *TokenStack) Pop() (TokenInfo, error) { if len(s.stack) == 0 { return TokenInfo{}, errors.New("stack is empty") @@ -23,6 +25,7 @@ func (s *TokenStack) Pop() (TokenInfo, error) { return token, nil } +// Len returns the current length of the TokenStack. func (s *TokenStack) Len() int { return len(s.stack) } diff --git a/sql_adaptor/adaptor.go b/sql_adaptor/adaptor.go index 6ec9800..3aabf06 100644 --- a/sql_adaptor/adaptor.go +++ b/sql_adaptor/adaptor.go @@ -1,3 +1,4 @@ +// Package sql_adaptor provides functions to convert a goven query to a valid and safe SQL query. package sql_adaptor import ( @@ -6,6 +7,7 @@ import ( "strings" ) +// NewDefaultAdaptorFromStruct returns a new basic SqlAdaptor from the reflection of your database object. func NewDefaultAdaptorFromStruct(gorm reflect.Value) *SqlAdaptor { matchers := map[*regexp.Regexp]ParseValidateFunc{} fieldMappings := map[string]string{} @@ -13,7 +15,7 @@ func NewDefaultAdaptorFromStruct(gorm reflect.Value) *SqlAdaptor { return NewSqlAdaptor(fieldMappings, defaultFields, matchers) } -// FieldParseValidatorFromStruct +// FieldParseValidatorFromStruct takes the reflection of your database object and returns a map of fieldnames to ParseValidateFuncs. // Don't panic - reflection is only used once on initialisation. func FieldParseValidatorFromStruct(gorm reflect.Value) map[string]ParseValidateFunc { defaultFields := map[string]ParseValidateFunc{} diff --git a/sql_adaptor/sql.go b/sql_adaptor/sql.go index 3dabb3c..59e436d 100644 --- a/sql_adaptor/sql.go +++ b/sql_adaptor/sql.go @@ -18,20 +18,23 @@ type ( ParseValidateFunc = func(ex *parser.Expression) (*SqlResponse, error) ) +// SqlResponse is an object that stores the raw query, and the values to interpolate. type SqlResponse struct { Raw string Values []string } +// SqlAdaptor represents the adaptor tailored to your database schema. type SqlAdaptor struct { - // fieldMappings (currently unimplements) is used to provide ability to map different frontend to backend field names. + // fieldMappings (currently unimplemented) is used to provide ability to map different frontend to backend field names. fieldMappings map[string]string // defaultFields is the default field matcher, used when a regex isn't matched. defaultFields map[string]ParseValidateFunc - // Non default matchers, these are custom matchers used to extend Goven's functionality. + // Non default matchers, these are custom matchers used to extend goven's functionality. matchers map[*regexp.Regexp]ParseValidateFunc } +// NewSqlAdaptor returns a SqlAdaptor populated with the provided arguments. func NewSqlAdaptor(fieldMappings map[string]string, defaultFields map[string]ParseValidateFunc, matchers map[*regexp.Regexp]ParseValidateFunc) *SqlAdaptor { if fieldMappings == nil { fieldMappings = map[string]string{} @@ -50,6 +53,7 @@ func NewSqlAdaptor(fieldMappings map[string]string, defaultFields map[string]Par return &sa } +// Parse takes a string goven query and returns a SqlResponse that can be executed against your database. func (s *SqlAdaptor) Parse(str string) (*SqlResponse, error) { newParser := parser.NewParser(str) node, err := newParser.Parse() diff --git a/sql_adaptor/validators.go b/sql_adaptor/validators.go index 449dad2..b9b209b 100644 --- a/sql_adaptor/validators.go +++ b/sql_adaptor/validators.go @@ -35,10 +35,12 @@ func DefaultMatcher(ex *parser.Expression) *SqlResponse { return &sq } +// NullValidator is a no-op validator on a string, always returns nil error. func NullValidator(_ string) error { return nil } +// IntegerValidator validates that the input is an integer. func IntegerValidator(s string) error { _, err := strconv.Atoi(s) if err != nil { @@ -47,6 +49,7 @@ func IntegerValidator(s string) error { return nil } +// NumericValidator validates that the input is a number. func NumericValidator(s string) error { _, err := strconv.ParseFloat(s, 64) if err != nil {