Skip to content

Commit

Permalink
Improve documentation for all public funcs/types + add package level …
Browse files Browse the repository at this point in the history
…documentation (#20)
  • Loading branch information
majolo authored Apr 12, 2022
1 parent 597cb52 commit 9e7024e
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 7 deletions.
14 changes: 11 additions & 3 deletions example/custom_matcher.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package example provides example use cases of goven with a data model.
package example

import (
Expand All @@ -16,9 +17,10 @@ import (
)

const (
KeyValueRegex = `(.+)\[(.+)\]`
keyValueRegex = `(.+)\[(.+)\]`
)

// Model represents an example machine learning model schema.
type Model struct {
gorm.Model
Name string
Expand All @@ -27,18 +29,21 @@ 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
Value string
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 {
Expand All @@ -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)
Expand All @@ -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()
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down
5 changes: 5 additions & 0 deletions example/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"gorm.io/gorm"
)

// User represents an simple example database schema.
type User struct {
ID uint
Name string
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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()
Expand Down
1 change: 1 addition & 0 deletions integration/integration_custom_matcher_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package integration contains integration tests using the example DAOs.
package integration

import (
Expand Down
2 changes: 2 additions & 0 deletions parser/lexer.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -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))
}
Expand Down
7 changes: 6 additions & 1 deletion parser/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions parser/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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)
}
4 changes: 3 additions & 1 deletion sql_adaptor/adaptor.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -6,14 +7,15 @@ 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{}
defaultFields := FieldParseValidatorFromStruct(gorm)
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{}
Expand Down
8 changes: 6 additions & 2 deletions sql_adaptor/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
Expand All @@ -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()
Expand Down
3 changes: 3 additions & 0 deletions sql_adaptor/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down

0 comments on commit 9e7024e

Please sign in to comment.