Skip to content

Commit

Permalink
Experimental MySQL support
Browse files Browse the repository at this point in the history
  • Loading branch information
aodin committed May 24, 2016
1 parent dd562c0 commit c5677b8
Show file tree
Hide file tree
Showing 30 changed files with 132 additions and 99 deletions.
4 changes: 2 additions & 2 deletions column.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ func (col ColumnElem) Create(d dialect.Dialect) (string, error) {
if err != nil {
return "", err
}
return fmt.Sprintf(`"%s" %s`, col.Name(), compiled), nil
return fmt.Sprintf(`%s %s`, col.Name(), compiled), nil
}

// FullName prefixes the column name with the table name
// It deos not include opreators (such as 'max')
func (col ColumnElem) FullName() string {
return fmt.Sprintf(`"%s"."%s"`, col.table.Name(), col.name)
return fmt.Sprintf(`%s.%s`, col.table.Name(), col.name)
}

// IsInvalid will return true when a column that does not exist was
Expand Down
2 changes: 1 addition & 1 deletion columnset.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (set ColumnSet) IsEmpty() bool {
func (set ColumnSet) Names() []string {
names := make([]string, len(set.order))
for i, col := range set.order {
names[i] = fmt.Sprintf(`%s`, col.FullName())
names[i] = col.FullName()
}
return names
}
Expand Down
2 changes: 1 addition & 1 deletion create.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (stmt CreateStmt) Compile(d dialect.Dialect, p *Parameters) (string, error)
}

return fmt.Sprintf(
"%s \"%s\" (\n %s\n);",
"%s %s (\n %s\n);",
name,
stmt.table.Name(),
strings.Join(compiled, ",\n "),
Expand Down
18 changes: 9 additions & 9 deletions create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ func TestCreate(t *testing.T) {
expect := NewTester(t, &defaultDialect{})

expect.SQL(
`CREATE TABLE "users" (
"id" INTEGER,
"email" VARCHAR(256) NOT NULL,
"name" VARCHAR(32) NOT NULL,
"password" VARCHAR,
"created_at" TIMESTAMP,
PRIMARY KEY ("id"),
UNIQUE ("email")
);`,
users.Create(),
`CREATE TABLE users (
id INTEGER,
email VARCHAR(256) NOT NULL,
name VARCHAR(32) NOT NULL,
password VARCHAR,
created_at TIMESTAMP,
PRIMARY KEY (id),
UNIQUE (email)
);`,
)
}
2 changes: 1 addition & 1 deletion delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (stmt DeleteStmt) Compile(d dialect.Dialect, ps *Parameters) (string, error
if err := stmt.Error(); err != nil {
return "", err
}
compiled := fmt.Sprintf(`DELETE FROM "%s"`, stmt.table.Name())
compiled := fmt.Sprintf(`DELETE FROM %s`, stmt.table.Name())

if stmt.where != nil {
cc, err := stmt.where.Compile(d, ps)
Expand Down
6 changes: 3 additions & 3 deletions delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ func TestDelete(t *testing.T) {
// Test a complete delete
// TODO Require an All when no clauses are given to prevent mass deletes?
expect.SQL(
`DELETE FROM "users"`,
users.Delete(),
`DELETE FROM users`,
)

// Test a delete with a WHERE
expect.SQL(
`DELETE FROM "users" WHERE "users"."id" = $1`,
users.Delete().Where(users.C("id").Equals(1)),
`DELETE FROM users WHERE users.id = $1`,
1,
)

expect.SQL(
`DELETE FROM "users" WHERE ("users"."id" = $1 AND "users"."name" = $2)`,
Delete(users).Where(users.C("id").Equals(1), users.C("name").Equals("admin")),
`DELETE FROM users WHERE (users.id = $1 AND users.name = $2)`,
1, "admin",
)
}
2 changes: 1 addition & 1 deletion foreignkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (fk FKElem) Create(d dialect.Dialect) (string, error) {
return "", err
}
compiled := fmt.Sprintf(
`"%s" %s REFERENCES %s("%s")`,
`%s %s REFERENCES %s(%s)`,
fk.name,
ct,
fk.col.Table().Name(),
Expand Down
28 changes: 14 additions & 14 deletions foreignkey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ func TestForeignKey(t *testing.T) {
expect := NewTester(t, &defaultDialect{})

expect.SQL(
`CREATE TABLE "contacts" (
"id" INTEGER,
"user_id" INTEGER REFERENCES users("id"),
"key" VARCHAR,
"value" VARCHAR,
PRIMARY KEY ("id"),
UNIQUE ("user_id", "key")
);`,
contacts.Create(),
`CREATE TABLE contacts (
id INTEGER,
user_id INTEGER REFERENCES users(id),
key VARCHAR,
value VARCHAR,
PRIMARY KEY (id),
UNIQUE (user_id, key)
);`,
)

expect.SQL(
`CREATE TABLE "messages" (
"id" INTEGER,
"user_id" INTEGER REFERENCES users("id"),
"parent_id" INTEGER REFERENCES messages("id"),
"text" TEXT
);`,
messages.Create(),
`CREATE TABLE messages (
id INTEGER,
user_id INTEGER REFERENCES users(id),
parent_id INTEGER REFERENCES messages(id),
text TEXT
);`,
)

if len(messages.ForeignKeys()) != 2 {
Expand Down
16 changes: 8 additions & 8 deletions function.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,33 @@ func Function(name string, col Columnar) ColumnElem {
}

func Avg(expression Columnar) ColumnElem {
return Function("avg", expression)
return Function("AVG", expression)
}

func Count(expression Columnar) ColumnElem {
return Function("count", expression)
return Function("COUNT", expression)
}

func Date(expression Columnar) ColumnElem {
return Function("date", expression)
return Function("DATE", expression)
}

func Max(expression Columnar) ColumnElem {
return Function("max", expression)
return Function("MAX", expression)
}

func Min(expression Columnar) ColumnElem {
return Function("min", expression)
return Function("MIN", expression)
}

func StdDev(expression Columnar) ColumnElem {
return Function("stddev", expression)
return Function("STDDEV", expression)
}

func Sum(expression Columnar) ColumnElem {
return Function("sum", expression)
return Function("SUM", expression)
}

func Variance(expression Columnar) ColumnElem {
return Function("variance", expression)
return Function("VARIANCE", expression)
}
4 changes: 2 additions & 2 deletions function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ func TestFunctions(t *testing.T) {
expect := NewTester(t, &defaultDialect{})

expect.SQL(
`SELECT count("users"."id") FROM "users"`,
Select(Count(users.C("id"))),
`SELECT COUNT(users.id) FROM users`,
)

expect.SQL(
`SELECT count("users"."id") AS "Count" FROM "users"`,
Select(Count(users.C("id")).As("Count")),
`SELECT COUNT(users.id) AS "Count" FROM users`,
)
}
4 changes: 2 additions & 2 deletions insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (stmt InsertStmt) Compile(d dialect.Dialect, ps *Parameters) (string, error

columns := make([]string, len(stmt.columns))
for i, column := range stmt.columns {
columns[i] = fmt.Sprintf(`"%s"`, column.Name())
columns[i] = column.Name()
}

// args must be divisable by cols without remainder
Expand Down Expand Up @@ -95,7 +95,7 @@ func (stmt InsertStmt) Compile(d dialect.Dialect, ps *Parameters) (string, error

// TODO Bulk insert syntax is dialect specific
return fmt.Sprintf(
`INSERT INTO "%s" (%s) VALUES %s`,
`INSERT INTO %s (%s) VALUES %s`,
stmt.table.Name(),
strings.Join(columns, ", "),
strings.Join(parameters, ", "),
Expand Down
8 changes: 4 additions & 4 deletions insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ func TestInsert(t *testing.T) {

// By default, an INSERT without values will assume a single entry
expect.SQL(
`INSERT INTO "contacts" ("id", "user_id", "key", "value") VALUES ($1, $2, $3, $4)`,
contacts.Insert(),
`INSERT INTO contacts (id, user_id, key, value) VALUES ($1, $2, $3, $4)`,
nil, nil, nil, nil,
)

expect.SQL(
`INSERT INTO "users" ("name", "password") VALUES ($1, $2)`,
Insert(users.C("name"), users.C("password")),
`INSERT INTO users (name, password) VALUES ($1, $2)`,
nil, nil,
)

expect.SQL(
`INSERT INTO "users" ("email", "name") VALUES ($1, $2)`,
users.Insert().Values(user{Name: "admin", Email: "[email protected]"}),
`INSERT INTO users (email, name) VALUES ($1, $2)`,
"[email protected]", "admin",
)

// Use sql.Values
expect.SQL(
`INSERT INTO "users" ("id", "name") VALUES ($1, $2)`,
users.Insert().Values(Values{"id": 1, "name": "user"}),
`INSERT INTO users (id, name) VALUES ($1, $2)`,
1, "user",
)
}
Expand Down
6 changes: 3 additions & 3 deletions join.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ func (j JoinClause) String() string {
func (j JoinClause) Compile(d dialect.Dialect, ps *Parameters) (string, error) {
// Ignore clauses if CROSS
if j.method == CROSSJOIN {
return fmt.Sprintf(`%s "%s"`, CROSSJOIN, j.table.Name()), nil
return fmt.Sprintf(`%s %s`, CROSSJOIN, j.table.Name()), nil
}

// If no clauses were given, assume the join is NATURAL
if len(j.ArrayClause.clauses) == 0 {
return fmt.Sprintf(
`NATURAL %s "%s"`, j.method, j.table.Name(),
`NATURAL %s %s`, j.method, j.table.Name(),
), nil
}

Expand All @@ -41,6 +41,6 @@ func (j JoinClause) Compile(d dialect.Dialect, ps *Parameters) (string, error) {
}

return fmt.Sprintf(
`%s "%s" ON %s`, j.method, j.table.Name(), clauses,
`%s %s ON %s`, j.method, j.table.Name(), clauses,
), nil
}
6 changes: 3 additions & 3 deletions join_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,16 @@ func TestJoinClause(t *testing.T) {
expect := NewTester(t, &defaultDialect{})

expect.SQL(
`SELECT "a"."id", "a"."value" FROM "a" CROSS JOIN "relations"`,
Select(tableA).CrossJoin(relations),
`SELECT a.id, a.value FROM a CROSS JOIN relations`,
)

expect.SQL(
`SELECT "a"."id", "a"."value" FROM "a" NATURAL INNER JOIN "relations"`,
Select(tableA).InnerJoin(relations),
`SELECT a.id, a.value FROM a NATURAL INNER JOIN relations`,
)

expect.SQL(
`SELECT "a"."id", "a"."value" FROM "a" LEFT OUTER JOIN "relations" ON "a"."id" = "relations"."a_id" AND "a"."id" = $1 LEFT OUTER JOIN "b" ON "b"."id" = "relations"."b_id"`,
Select(tableA).LeftOuterJoin(
relations,
tableA.C("id").Equals(relations.C("a_id")),
Expand All @@ -45,6 +44,7 @@ func TestJoinClause(t *testing.T) {
tableB,
tableB.C("id").Equals(relations.C("b_id")),
),
`SELECT a.id, a.value FROM a LEFT OUTER JOIN relations ON a.id = relations.a_id AND a.id = $1 LEFT OUTER JOIN b ON b.id = relations.b_id`,
2,
)

Expand Down
28 changes: 28 additions & 0 deletions mysql/mysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package mysql

import (
_ "github.com/go-sql-driver/mysql"

"github.com/aodin/sol/dialect"
)

// MySQL implements the Dialect interface for MySQL databases.
type MySQL struct{}

// The MySQL dialect must implement the dialect.Dialect interface
var _ dialect.Dialect = &MySQL{}

// Param returns the MySQL specific parameterization scheme.
func (d *MySQL) Param(i int) string {
return `?`
}

// Dialect is a constructor for the MySQL Dialect
func Dialect() *MySQL {
return &MySQL{}
}

// Add the MySQL dialect to the dialect registry
func init() {
dialect.Register("mysql", Dialect())
}
11 changes: 7 additions & 4 deletions order_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ func TestOrder(t *testing.T) {

// Asc is implied
ord := OrderedColumn{inner: users.C("id")}
expect.SQL(`"users"."id"`, ord)
expect.SQL(ord, `users.id`)

// Desc
expect.SQL(`"users"."id" DESC`, ord.Desc())
expect.SQL(ord.Desc(), `users.id DESC`)

// Desc, nulls first
expect.SQL(
`"users"."id" DESC NULLS FIRST`,
ord.Desc().NullsFirst(),
`users.id DESC NULLS FIRST`,
)

// Asc, Nulls last
expect.SQL(`"users"."id" NULLS LAST`, ord.Asc().NullsLast())
expect.SQL(
ord.Asc().NullsLast(),
`users.id NULLS LAST`,
)

// Calling Orderable on an OrderableColumn should return a copy of itself
if ord.inner.Name() != ord.Orderable().inner.Name() {
Expand Down
2 changes: 1 addition & 1 deletion postgres/column_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ func TestColumn(t *testing.T) {
expect := sol.NewTester(t, Dialect())

expect.SQL(
`SELECT "meetings"."uuid", "meetings"."time" FROM "meetings" WHERE "meetings"."time" @> $1`,
meetings.Select().Where(meetings.C("time").Contains("today")),
`SELECT meetings.uuid, meetings.time FROM meetings WHERE meetings.time @> $1`,
"today",
)
}
Loading

0 comments on commit c5677b8

Please sign in to comment.