Skip to content

Commit

Permalink
Merge pull request #24 from yoyo-project/task/sqlite
Browse files Browse the repository at this point in the history
Early sqlite support
  • Loading branch information
dotvezz authored Aug 3, 2021
2 parents 69b62dd + 3c3a268 commit 4e5483d
Show file tree
Hide file tree
Showing 25 changed files with 959 additions and 107 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

# yoyo

[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
Expand All @@ -9,6 +10,12 @@
A Migration Generator and Database Access Layer Generator for Go projects. Made with ❤️ to hopefully make your life a
little bit easier.

Your Database access layer generated by `yoyo`...

- provides a native, fluent query generator
- is totally pure Go
- is totally reflection-free

## A Note on Using Databases in Code

Okay, accessing databases in code is annoying. Relational data is annoying. It doesn't matter which language you're using.
Expand Down
11 changes: 10 additions & 1 deletion cmd/yoyo/generate/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,33 @@ import (
"time"

"github.com/dotvezz/lime"

"github.com/yoyo-project/yoyo/internal/migration"
"github.com/yoyo-project/yoyo/internal/schema"
"github.com/yoyo-project/yoyo/internal/yoyo"
)

type FileOpener func(string) (*os.File, error)
type DatabaseValidator func(database schema.Database) error

func Migrations(
now func() time.Time,
loadGenerator migration.GeneratorLoader,
create FileOpener,
validate DatabaseValidator,
) lime.Func {
return func(args []string, w io.Writer) error {
config, err := yoyo.LoadConfig()
if err != nil {
return fmt.Errorf("unable to load config: %w", err)
}

generate, err := loadGenerator(config)
if err := validate(config.Schema); err != nil {
return err
}

var generate migration.Generator
generate, err = loadGenerator(config)
if err != nil {
return fmt.Errorf("unable to initialize migration generator: %w", err)
}
Expand Down
4 changes: 3 additions & 1 deletion cmd/yoyo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"os"

"github.com/yoyo-project/yoyo/internal/validation"

"github.com/yoyo-project/yoyo/internal/file"

"github.com/dotvezz/lime"
Expand All @@ -25,7 +27,7 @@ func main() {
Commands: []lime.Command{
{
Keyword: "migration",
Func: generate.Migrations(ucs.GetCurrentTime, ucs.LoadMigrationGenerator, file.CreateWithDirs),
Func: generate.Migrations(ucs.GetCurrentTime, ucs.LoadMigrationGenerator, file.CreateWithDirs, validation.ValidateDatabase),
},
{
Keyword: "repos",
Expand Down
51 changes: 44 additions & 7 deletions internal/datatype/datatypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ const (
SmallInt = idSmallInt | metaNumeric | metaInteger | metaSignable | metaHasGoUnisgned
MediumInt = idMediumInt | metaNumeric | metaInteger | metaSignable | metaHasGoUnisgned
BigInt = idBigInt | metaNumeric | metaInteger | metaSignable | metaHasGoUnisgned
Decimal = idDecimal | metaNumeric | metaSignable | metaRequiresParams
Decimal = idDecimal | metaNumeric | metaSignable
Numeric = idNumeric | metaNumeric | metaSignable
Real = idReal | metaNumeric | metaSignable
Float = idFloat | metaNumeric | metaSignable
Double = idDouble | metaNumeric | metaSignable
Varchar = idVarchar | metaString
Text = idText | metaString
TinyText = idTinyText | metaString
Expand All @@ -46,6 +50,12 @@ const (
mediumint = "MEDIUMINT"
bigint = "BIGINT"
decimal = "DECIMAL"
dec = "DEC"
numeric = "NUMERIC"
sreal = "REAL"
float = "FLOAT"
double = "DOUBLE"
doubleP = "DOUBLE PRECISION"
varchar = "VARCHAR"
text = "TEXT"
tinytext = "TINYTEXT"
Expand All @@ -69,7 +79,6 @@ const (
goFloat64 = "float64"
goString = "string"
goBool = "bool"
goRune = "rune"
goBlob = "[]byte"
goTime = "time.Time"
)
Expand Down Expand Up @@ -99,6 +108,14 @@ func (dt Datatype) String() (s string) {
s = bigint
case Decimal:
s = decimal
case Numeric:
s = numeric
case Real:
s = sreal
case Float:
s = float
case Double:
s = double
case Varchar:
s = varchar
case Text:
Expand Down Expand Up @@ -147,6 +164,14 @@ func (dt Datatype) GoTypeString() (s string) {
s = goInt64
case Decimal:
s = goFloat64
case Numeric:
s = goFloat64
case Real:
s = goFloat64
case Float:
s = goFloat64
case Double:
s = goFloat64
case Varchar:
s = goString
case Text:
Expand All @@ -158,18 +183,18 @@ func (dt Datatype) GoTypeString() (s string) {
case LongText:
s = goString
case Char:
s = goRune
s = goString
case Blob:
s = goBlob
case Enum:
s = goString
case Boolean:
s = goBool
case DateTime, Timestamp, Date:
//TODO: Work out sane better go-type for Time?
s = goTime
case Year:
s = goInt16
//TODO: Work out sane go-type for Time
default:
s = "NONE"
}
Expand Down Expand Up @@ -230,8 +255,16 @@ func FromString(in string) (dt Datatype, err error) {
dt = SmallInt
case tinyint:
dt = TinyInt
case decimal:
case decimal, dec:
dt = Decimal
case numeric:
dt = Numeric
case sreal:
dt = Real
case float:
dt = Float
case double, doubleP:
dt = Double
case varchar:
dt = Varchar
case text:
Expand Down Expand Up @@ -275,8 +308,8 @@ const (
metaBinary
metaString
metaTime
metaSignable
metaHasGoUnisgned
metaSignable // TODO: Remove because it is synonymous with metaNumeric?
metaHasGoUnisgned // TODO: Remove because it is synonymous with metaInteger?
metaRequiresParams
)

Expand All @@ -290,6 +323,10 @@ const (
idMediumInt
idBigInt
idDecimal
idNumeric
idReal
idFloat
idDouble
idVarchar
idText
idTinyText
Expand Down
6 changes: 3 additions & 3 deletions internal/datatype/datatypes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ func TestDatatype_IsBinary(t *testing.T) {
}
}

func TestDatatype_RequiresScale(t *testing.T) {
func TestDatatype_RequiresParams(t *testing.T) {
tests := []struct {
dt Datatype
want bool
Expand All @@ -294,7 +294,7 @@ func TestDatatype_RequiresScale(t *testing.T) {
},
{
dt: Decimal,
want: true,
want: false,
},
{
dt: Text,
Expand Down Expand Up @@ -445,7 +445,7 @@ func TestDatatype_GoTypeString(t *testing.T) {
},
{
dt: Char,
want: goRune,
want: goString,
},
{
dt: Blob,
Expand Down
9 changes: 9 additions & 0 deletions internal/dbms/base/dialect.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package base

import (
"github.com/yoyo-project/yoyo/internal/datatype"
"github.com/yoyo-project/yoyo/internal/schema"
)

// Base is a partial implementation of migration.Dialect. It provides the TypeString method.
Expand All @@ -21,3 +22,11 @@ func (d *Base) TypeString(dt datatype.Datatype) (string, error) {

return s, nil
}

func (*Base) ValidateTable(t schema.Table) error {
return nil
}

func (*Base) SupportsAutoIncrement() bool {
return false
}
2 changes: 2 additions & 0 deletions internal/dbms/dialect/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ const (
MySQL = "mysql"
// PostgreSQL is for the SQL dialect of the same name
PostgreSQL = "postgresql"
// SQLite is for the SQL dialect of the same name
SQLite = "sqlite"
)
11 changes: 10 additions & 1 deletion internal/dbms/mysql/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ import (
"database/sql"

"github.com/yoyo-project/yoyo/internal/dbms/base"
"github.com/yoyo-project/yoyo/internal/dbms/dialect"
)

type adapter struct {
db *sql.DB
base.Base
validator
}

// NewAdapter returns an implementation of migration.Dialect for MySQL
func NewAdapter() *adapter {
return &adapter{
Base: base.Base{
Dialect: dialect.MySQL,
},
}
}
21 changes: 4 additions & 17 deletions internal/dbms/mysql/adapter_migration.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
package mysql

import (
"errors"
"fmt"
"strings"

"github.com/yoyo-project/yoyo/internal/datatype"
"github.com/yoyo-project/yoyo/internal/dbms/base"
"github.com/yoyo-project/yoyo/internal/dbms/dialect"
"github.com/yoyo-project/yoyo/internal/schema"
)

// NewAdapter returns an implementation of migration.Dialect for MySQL
func NewAdapter() *adapter {
return &adapter{
Base: base.Base{
Dialect: dialect.MySQL,
},
validator: validator{},
}
}

// TypeString returns the string representation of a given datatype.Datatype for MySQL
// An error will be returned if the datatype.Datatype is invalid or not supported by MySQL
func (a *adapter) TypeString(dt datatype.Datatype) (s string, err error) {
Expand All @@ -30,8 +17,8 @@ func (a *adapter) TypeString(dt datatype.Datatype) (s string, err error) {
default:
s, err = a.Base.TypeString(dt)
}
if err == nil && !a.validator.SupportsDatatype(dt) {
err = errors.New("unsupported datatype")
if err == nil && !a.SupportsDatatype(dt) {
err = fmt.Errorf("unsupported datatype")
}
return s, err
}
Expand Down Expand Up @@ -121,8 +108,8 @@ func (a *adapter) AddReference(tName string, fTable schema.Table, r schema.Refer
sw.WriteRune('\n')
}

sw.WriteString(fmt.Sprintf("ALTER TABLE `%s` ADD CONSTRAINT `reference_%s` FOREIGN KEY (`%s`) REFERENCES %s(`%s`)",
tName, ftName, strings.Join(lCols, "`, `"), ftName, strings.Join(fCols, "`, `")))
sw.WriteString(fmt.Sprintf("ALTER TABLE `%s` ADD CONSTRAINT `reference_%s_%s_%s` FOREIGN KEY (`%s`) REFERENCES %s(`%s`)",
tName, tName, ftName, strings.Join(fCols, "_"), strings.Join(lCols, "`, `"), ftName, strings.Join(fCols, "`, `")))

if r.OnDelete != "" {
sw.WriteString(fmt.Sprintf(" ON DELETE %s", r.OnDelete))
Expand Down
Loading

0 comments on commit 4e5483d

Please sign in to comment.