Skip to content

Commit

Permalink
The management of columns within a table now uses ColumnSet
Browse files Browse the repository at this point in the history
  • Loading branch information
aodin committed May 19, 2016
1 parent 146c6cd commit 628ee04
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 83 deletions.
11 changes: 9 additions & 2 deletions column.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type ColumnElem struct {
alias string
table *TableElem
datatype types.Type
invalid bool
invalid bool // columns will be assumed valid until otherwise proven
}

var _ Columnar = ColumnElem{}
Expand Down Expand Up @@ -94,6 +94,12 @@ func (col ColumnElem) IsInvalid() bool {
return col.invalid
}

// IsValid returns true unless the column has been marked invalid. It
// may be a false positive.
func (col ColumnElem) IsValid() bool {
return !col.IsInvalid()
}

// Name returns the name of the column - unescaped and without an alias
func (col ColumnElem) Name() string {
return fmt.Sprintf(`%s`, col.name)
Expand Down Expand Up @@ -123,7 +129,8 @@ func (col ColumnElem) Modify(tabular Tabular) error {
col.table = table

// Add the column to the table
if err := table.columns.add(col); err != nil {
var err error
if table.columns, err = table.columns.Add(col); err != nil {
return err
}

Expand Down
48 changes: 0 additions & 48 deletions columns.go

This file was deleted.

74 changes: 74 additions & 0 deletions columnset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package sol

import "fmt"

// ColumnSet maintains a []ColumnElem. It includes a variety of
// getters and setter. Optionally, it can force unique
type ColumnSet struct {
// TODO what about uniqueness with aliases? across tables?
unique bool
order []ColumnElem
}

// Add adds any number of ColumnElem types to the set and returns the new set.
// If the set is marked unique, adding a column with the same name
// as an existing column in the set will return an error.
func (set ColumnSet) Add(columns ...ColumnElem) (ColumnSet, error) {
if set.unique {
for _, column := range columns {
for _, existing := range set.order {
// TODO across tables? aliases?
if existing.Name() == column.Name() {
if existing.Table() == nil {
return set, fmt.Errorf(
"sol: this set already has a column named '%s'",
existing.Name(),
)
}
return set, fmt.Errorf(
"sol: table '%s' already has a column named '%s'",
existing.Table().Name(),
existing.Name(),
)
}
}
set.order = append(set.order, column)
}
} else {
set.order = append(set.order, columns...)
}
return set, nil
}

// All returns all columns in their default order
func (set ColumnSet) All() []ColumnElem {
return set.order
}

// Get returns a ColumnElem - or an invalid ColumnElem if a column
// with the given name does not exist in the set
func (set ColumnSet) Get(name string) ColumnElem {
for _, column := range set.order {
// TODO What about table? aliases?
if column.Name() == name {
return column
}
}
return InvalidColumn(name, nil)
}

// Has returns true if there is a column with the given name in the ColumnSet
func (set ColumnSet) Has(name string) bool {
return set.Get(name).IsValid()
}

// UniqueColumns creates a new ColumnSet that can only hold columns
// with unique names
func UniqueColumns() ColumnSet {
return ColumnSet{unique: true}
}

// Columns creates a new ColumnSet
func Columns() ColumnSet {
return ColumnSet{}
}
39 changes: 39 additions & 0 deletions columnset_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package sol

import "testing"

func TestColumns(t *testing.T) {
columns := Columns()
example := ColumnElem{name: "example"}

added, err := columns.Add(example)
if err != nil {
t.Fatalf("sol: adding a column to a set should not error: %s", err)
}
if len(added.order) != 1 {
t.Errorf(
"sol: unexpected length of ColumnSet: 1 != %d",
len(added.order),
)
}
if !added.Has("example") {
t.Errorf("sol: ColumnSet should have a column named 'example")
}
if added.Has("test") {
t.Errorf("sol: ColumnSet should not have a column named 'test")
}
}

func TestUniqueColumns(t *testing.T) {
columns := UniqueColumns()
example := ColumnElem{name: "example"}

added, err := columns.Add(example)
if err != nil {
t.Fatalf("sol: adding a column to a set should not error: %s", err)
}
_, err = added.Add(example)
if err == nil {
t.Fatalf("sol: adding a duplicate column to a unqie set should error")
}
}
4 changes: 2 additions & 2 deletions delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ func (stmt DeleteStmt) Where(clauses ...Clause) DeleteStmt {
}

// Delete creates a DELETE statement for the given table.
func Delete(table *TableElem, clauses ...Clause) (stmt DeleteStmt) {
func Delete(table *TableElem) (stmt DeleteStmt) {
if table == nil {
stmt.AddMeta("sol: attempting to DELETE a nil table")
return
}
stmt.table = table
return stmt.Where(clauses...)
return
}
2 changes: 1 addition & 1 deletion delete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestDelete(t *testing.T) {

expect.SQL(
`DELETE FROM "users" WHERE ("users"."id" = $1 AND "users"."name" = $2)`,
users.Delete(users.C("id").Equals(1), users.C("name").Equals("admin")),
Delete(users).Where(users.C("id").Equals(1), users.C("name").Equals("admin")),
1, "admin",
)
}
3 changes: 2 additions & 1 deletion foreignkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ func (fk FKElem) Modify(tabular Tabular) error {
}

// Add the column to the table
if err := table.columns.add(col); err != nil {
var err error
if table.columns, err = table.columns.Add(col); err != nil {
return err
}

Expand Down
14 changes: 3 additions & 11 deletions postgres/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,10 @@ type TableElem struct {
var _ sol.Tabular = &TableElem{}

// Column will return a postgres specific ColumnElem rather than a generic
// ColumnElem
// ColumnElem. It is assumed that all columns belonging to postgres
// table are postgres columns
func (table TableElem) Column(name string) ColumnElem {
if table.Has(name) {
switch elem := table.GetColumn(name).(type) {
case ColumnElem:
return elem
case sol.ColumnElem:
return ColumnElem{ColumnElem: elem}
}
// TODO invalid column? Prevent the mixing of column types?
}
return ColumnElem{ColumnElem: sol.InvalidColumn(name, table)}
return ColumnElem{ColumnElem: table.TableElem.Column(name)}
}

// C is an alias for Column
Expand Down
30 changes: 12 additions & 18 deletions table.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type Tabular interface {
type TableElem struct {
name string
alias string
columns Columns
columns ColumnSet
pk PKArray // Table's primary key
uniques []UniqueArray
fks []FKElem // This table's foreign keys
Expand All @@ -37,14 +37,13 @@ var _ Tabular = &TableElem{}
// it will return the ColumnElem in an invalid state that will be used to
// construct an error message
func (table TableElem) Column(name string) ColumnElem {
if table.Has(name) {
switch elem := table.GetColumn(name).(type) {
case ColumnElem:
return elem
}
// TODO invalid column?
col := table.columns.Get(name)
// If the column is invalid add the current table in order
// to construct a better error message
if col.IsInvalid() {
col.table = &table
}
return InvalidColumn(name, &table)
return col
}

// C is an alias for Column
Expand All @@ -54,7 +53,7 @@ func (table TableElem) C(name string) ColumnElem {

// Columns returns all the table columns in the original schema order
func (table TableElem) Columns() []ColumnElem {
return table.columns.order
return table.columns.All()
}

// Create generates the table's CREATE statement.
Expand All @@ -63,10 +62,9 @@ func (table *TableElem) Create() CreateStmt {
}

// Delete is an alias for Delete(table). It will generate a DELETE statement
// for the entire table. Conditionals joined with AND can be passed as
// parameters or later added with the Where() method
func (table *TableElem) Delete(clauses ...Clause) DeleteStmt {
return Delete(table, clauses...)
// for the entire table
func (table *TableElem) Delete() DeleteStmt {
return Delete(table)
}

// Create generates the table's DROP statement.
Expand All @@ -79,10 +77,6 @@ func (table *TableElem) ForeignKeys() []FKElem {
return table.fks
}

func (table TableElem) GetColumn(name string) Columnar {
return table.columns.Get(name)
}

// Has returns true if the column exists in this table
func (table *TableElem) Has(name string) bool {
return table.columns.Has(name)
Expand Down Expand Up @@ -132,7 +126,7 @@ func Table(name string, modifiers ...Modifier) *TableElem {
}
table := &TableElem{
name: name,
columns: Columns{c: make(map[string]ColumnElem)}, // TODO ColumnMap
columns: UniqueColumns(),
}
for _, modifier := range modifiers {
if err := modifier.Modify(table); err != nil {
Expand Down

0 comments on commit 628ee04

Please sign in to comment.