Skip to content

Commit

Permalink
Update FOREIGN KEY to work without index name.
Browse files Browse the repository at this point in the history
  • Loading branch information
chuckpreslar committed Aug 14, 2013
1 parent 531eb7a commit f210bc8
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 22 deletions.
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,61 @@ sql, err := users.Delete(users("id").Eq(1)).ToSql()

// DELETE FROM "users" WHERE "users"."id" = 1
```

## Creations

The codex package currently provides a few common SQL data and constraint types as constants to use with creating and altering tables.

__Constraints__

* NOT_NULL
* UNIQUE
* PRIMARY_KEY
* FOREIGN_KEY
* CHECK
* DEFAULT

__Types__

* STRING
* TEXT
* BOOLEAN
* INTEGER
* FLOAT
* DECIMAL
* DATE
* TIME
* DATETIME
* TIMESTAMP

```go
// ...

users := codex.CreateTable("users").
AddColumn("first_name", codex.STRING).
AddColumn("last_name", codex.STRING).
AddColumn("email", codex.STRING).
AddColumn("id", codex.INTEGER).
AddConstraint("first_name", codex.NOT_NULL).
AddConstraint("id", codex.PRIMARY_KEY).
AddConstraint("email", codex.UNIQUE, "users_uniq_email") // Optional last argument supplies index name.

sql, err := users.ToSql()

// CREATE TABLE "users" ();
// ALTER TABLE "users" ADD "first_name" character varying(255);
// ALTER TABLE "users" ADD "last_name" character varying(255);
// ALTER TABLE "users" ADD "email" character varying(255);
// ALTER TABLE "users" ADD "id" integer;
// ALTER TABLE "users" ALTER "first_name" SET NOT NULL;
// ALTER TABLE "users" ADD PRIMARY KEY("id");
// ALTER TABLE "users" ADD CONSTRAINT "users_email_uniq" UNIQUE("email");
```

## Alterations

Alterations work the same as Creations, only the the initializer function `AlterTable` is used in place of `CreateTable`.

## Documentation

View godoc or visit [godoc.org](http://godoc.org/github.com/chuckpreslar/codex).
Expand Down
1 change: 1 addition & 0 deletions codex.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
TIMESTAMP = sql.TIMESTAMP
)

// ToggleDebugMode toggles debugger variable for managers package.
func ToggleDebugMode() {
visitors.DEBUG = !visitors.DEBUG
}
Expand Down
8 changes: 1 addition & 7 deletions managers/alter_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,11 @@ func (self *AlterManager) AddColumn(name interface{}, typ sql.Type) *AlterManage
}

func (self *AlterManager) AddConstraint(column interface{}, kind sql.Constraint, options ...interface{}) *AlterManager {
var expr interface{}

if 0 < len(options) {
expr = options[0]
}

if _, ok := column.(string); ok {
column = nodes.UnqualifiedColumn(column)
}

self.Tree.Constraints = append(self.Tree.Constraints, nodes.Constraint(column, kind, expr))
self.Tree.Constraints = append(self.Tree.Constraints, nodes.Constraint(column, kind, options...))
return self
}

Expand Down
10 changes: 5 additions & 5 deletions nodes/constraint_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import (

// ConstraintNode is a Nary node.
type ConstraintNode struct {
Column interface{}
Kind sql.Constraint
Expr interface{}
Column interface{}
Kind sql.Constraint
Options []interface{}
}

// ConstraintNode factory method.
func Constraint(column interface{}, kind sql.Constraint, expr interface{}) (constraint *ConstraintNode) {
func Constraint(column interface{}, kind sql.Constraint, options ...interface{}) (constraint *ConstraintNode) {
constraint = new(ConstraintNode)
constraint.Column = column
constraint.Kind = kind
constraint.Expr = expr
constraint.Options = options
return
}
79 changes: 69 additions & 10 deletions visitors/to_sql_visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,22 +368,69 @@ func (self *ToSqlVisitor) VisitUnexistingColumn(o *nodes.UnexistingColumnNode, v
func (self *ToSqlVisitor) VisitConstraint(o *nodes.ConstraintNode, visitor VisitorInterface) string {
str := ""
switch o.Kind {
//FIXME: This looks a little sloppy, clean it up.
case sql.UNIQUE, sql.PRIMARY_KEY:
str = fmt.Sprintf("%vADD%v", str, SPACE)
if nil != o.Expr {
if _, ok := o.Expr.(string); ok {
o.Expr = nodes.IndexName(o.Expr)
// Optional index name.
if 0 < len(o.Options) {
expr := o.Options[0]
if _, ok := expr.(string); ok {
expr = nodes.IndexName(expr)
}

str = fmt.Sprintf("%vCONSTRAINT %v%v", str, visitor.Visit(o.Expr, visitor), SPACE)
str = fmt.Sprintf("%vCONSTRAINT %v%v", str, visitor.Visit(expr, visitor), SPACE)
}

str = fmt.Sprintf("%v%v(%v)", str, visitor.Visit(o.Kind, visitor), visitor.Visit(o.Column, visitor))

case sql.FOREIGN_KEY:
str = fmt.Sprintf("%vADD%v", str, SPACE)
// For FOREIGN KEY, index name is optional, REFERENCES is not.
//
// No index name ex.
//
// CreateTable("orders").
// AddColumn("user_id").
// AddConstraint("user_id", FOREIGN_KEY, "users")
//
// With option index name ex.
//
// CreateTable("orders").
// AddColumn("user_id").
// AddConstraint("user_id", FOREIGN_KEY, "users_fkey", "users")
if 1 < len(o.Options) {
expr := o.Options[0]
if _, ok := expr.(string); ok {
expr = nodes.IndexName(expr)
}

// Remove this item from the array, avoiding any potential memory leak.
// https://code.google.com/p/go-wiki/wiki/SliceTricks
length := len(o.Options) - 1
copy(o.Options[0:], o.Options[1:])
o.Options[length] = nil
o.Options = o.Options[:length]

str = fmt.Sprintf("%vCONSTRAINT %v%v", str, visitor.Visit(expr, visitor), SPACE)
}

str = fmt.Sprintf("%v%v(%v)", str, visitor.Visit(o.Kind, visitor), visitor.Visit(o.Column, visitor))

// If option is not here, user didn't do it right, but don't dereference and panic.
if 0 < len(o.Options) {
relation := o.Options[0]
if _, ok := relation.(string); ok {
relation = nodes.Relation(relation.(string))
}

str = fmt.Sprintf("%v%vREFERENCES %v", str, SPACE, visitor.Visit(relation, visitor))
}

default:
str = fmt.Sprintf("ALTER %v SET %v", visitor.Visit(o.Column, visitor), visitor.Visit(o.Kind, visitor))

if nil != o.Expr {
str = fmt.Sprintf("%v %v", str, visitor.Visit(o.Expr, visitor))
if 0 < len(o.Options) {
str = fmt.Sprintf("%v %v", str, visitor.Visit(o.Options[0], visitor))
}

str = fmt.Sprintf("%v", str)
Expand Down Expand Up @@ -551,12 +598,24 @@ func (self *ToSqlVisitor) VisitAlterStatement(o *nodes.AlterStatementNode, visit
str = fmt.Sprintf("CREATE TABLE %v ();\n", visitor.Visit(o.Relation, visitor))
}

for _, column := range o.Columns {
str = fmt.Sprintf("%vALTER TABLE %v %v;\n", str, visitor.Visit(o.Relation, visitor), visitor.Visit(column, visitor))
length := len(o.Columns) - 1

for index, column := range o.Columns {
str = fmt.Sprintf("%vALTER TABLE %v %v;", str, visitor.Visit(o.Relation, visitor), visitor.Visit(column, visitor))

if index != length {
str = fmt.Sprintf("%v\n", str)
}
}

for _, constraint := range o.Constraints {
str = fmt.Sprintf("%vALTER TABLE %v %v;\n", str, visitor.Visit(o.Relation, visitor), visitor.Visit(constraint, visitor))
length = len(o.Constraints) - 1

for index, constraint := range o.Constraints {
str = fmt.Sprintf("%vALTER TABLE %v %v;", str, visitor.Visit(o.Relation, visitor), visitor.Visit(constraint, visitor))

if index != length {
str = fmt.Sprintf("%v\n", str)
}
}

return str
Expand Down

0 comments on commit f210bc8

Please sign in to comment.