diff --git a/db.go b/db.go index 2ba9df76507811017ad1553623eca66ec2b76ecd..2b11c2f6aecbd1634fe475393b9aff8be6398841 100644 --- a/db.go +++ b/db.go @@ -178,13 +178,13 @@ type Database interface { // collection to exists will fail returning the original error a call to // Collection() would have returned. The output of C() may be a cached // collection value. - C(...string) Collection + C(string) Collection // Collection() returns a `db.Collection{}` struct by name. Some databases // support collections of more than one source or table, refer to the // documentation of the specific database adapter to see if using multiple // sources is supported. - Collection(...string) (Collection, error) + Collection(string) (Collection, error) // Collections() returns the names of all non-system sources or tables within // the active database. diff --git a/postgresql/collection.go b/postgresql/collection.go index 5656e6e616f91670ec1216b375f69c03ebfc5d3a..f06f1f0eb5676bf0ee37e27268bd7aae5204b63c 100644 --- a/postgresql/collection.go +++ b/postgresql/collection.go @@ -35,8 +35,8 @@ import ( ) type table struct { - sqlutil.T *database + name string } var _ = db.Collection(&table{}) @@ -50,7 +50,7 @@ func (t *table) Find(conds ...interface{}) db.Result { func (t *table) Truncate() error { _, err := t.database.Exec(&sqlgen.Statement{ Type: sqlgen.Truncate, - Table: sqlgen.TableWithName(t.MainTableName()), + Table: sqlgen.TableWithName(t.Name()), }) if err != nil { return err @@ -75,7 +75,7 @@ func (t *table) Append(item interface{}) (interface{}, error) { var pKey []string - if pKey, err = t.database.getPrimaryKey(t.MainTableName()); err != nil { + if pKey, err = t.database.getPrimaryKey(t.Name()); err != nil { if err != sql.ErrNoRows { // Can't tell primary key. return nil, err @@ -84,7 +84,7 @@ func (t *table) Append(item interface{}) (interface{}, error) { stmt := &sqlgen.Statement{ Type: sqlgen.Insert, - Table: sqlgen.TableWithName(t.MainTableName()), + Table: sqlgen.TableWithName(t.Name()), Columns: sqlgenCols, Values: sqlgenVals, } @@ -158,7 +158,7 @@ func (t *table) Append(item interface{}) (interface{}, error) { // Exists returns true if the collection exists. func (t *table) Exists() bool { - if err := t.database.tableExists(t.Tables...); err != nil { + if err := t.database.tableExists(t.Name()); err != nil { return false } return true @@ -166,5 +166,5 @@ func (t *table) Exists() bool { // Name returns the name of the table or tables that form the collection. func (t *table) Name() string { - return strings.Join(t.Tables, `, `) + return t.name } diff --git a/postgresql/database.go b/postgresql/database.go index 2dc9a99e9eec56e9ccb6ab7afbb863dea168a522..1dd8acd84fdb3c9345dd10f366c7c5b7601245c0 100644 --- a/postgresql/database.go +++ b/postgresql/database.go @@ -52,6 +52,7 @@ type database struct { cachedStatements *cache.Cache collections map[string]*table collectionsMu sync.Mutex + builder db.QueryBuilder } type cachedStatement struct { @@ -152,6 +153,8 @@ func (d *database) Open() error { return err } + d.builder = builder.NewBuilder(d, template.Template) + d.cachedStatements = cache.NewCache() d.collections = make(map[string]*table) @@ -197,16 +200,12 @@ func (d *database) Close() error { } // C returns a collection interface. -func (d *database) C(names ...string) db.Collection { - if len(names) == 0 { - return &adapter.NonExistentCollection{Err: db.ErrMissingCollectionName} - } - - if c, ok := d.collections[sqlutil.HashTableNames(names)]; ok { +func (d *database) C(name string) db.Collection { + if c, ok := d.collections[name]; ok { return c } - c, err := d.Collection(names...) + c, err := d.Collection(name) if err != nil { return &adapter.NonExistentCollection{Err: err} } @@ -214,43 +213,21 @@ func (d *database) C(names ...string) db.Collection { } // Collection returns a table by name. -func (d *database) Collection(names ...string) (db.Collection, error) { - var err error - - if len(names) == 0 { - return nil, db.ErrMissingCollectionName - } - +func (d *database) Collection(name string) (db.Collection, error) { if d.tx != nil { if d.tx.Done() { return nil, sql.ErrTxDone } } - col := &table{database: d} - col.T.Tables = names - - for _, name := range names { - chunks := strings.SplitN(name, ` `, 2) - - if len(chunks) == 0 { - return nil, db.ErrMissingCollectionName - } - - tableName := chunks[0] - - if err := d.tableExists(tableName); err != nil { - return nil, err - } - - if col.Columns, err = d.tableColumns(tableName); err != nil { - return nil, err - } + if err := d.tableExists(name); err != nil { + return nil, err } - // Saving the collection for C(). + col := &table{database: d, name: name} + d.collectionsMu.Lock() - d.collections[sqlutil.HashTableNames(names)] = col + d.collections[name] = col d.collectionsMu.Unlock() return col, nil @@ -638,7 +615,7 @@ func (d *database) getPrimaryKey(tableName string) ([]string, error) { // Builder returns a custom query builder. func (d *database) Builder() db.QueryBuilder { - return builder.NewBuilder(d, template) + return d.builder } // waitForConnection tries to execute the connectFn function, if connectFn diff --git a/postgresql/database_test.go b/postgresql/database_test.go index f98e862e20f0c806330f3635a85afb954ed3e43a..94053effbea249a3089c8ce22ee09aacfa80c1dc 100644 --- a/postgresql/database_test.go +++ b/postgresql/database_test.go @@ -35,9 +35,7 @@ import ( "time" "github.com/jmoiron/sqlx" - "github.com/stretchr/testify/assert" "upper.io/db" - "upper.io/db/util/sqlutil" ) const ( @@ -1131,225 +1129,6 @@ func TestRemove(t *testing.T) { } } -// Attempts to use SQL raw statements. -func TestRawRelations(t *testing.T) { - var sess db.Database - var err error - - var artist db.Collection - var publication db.Collection - var review db.Collection - - type publicationType struct { - ID int64 `db:"id,omitempty"` - Title string `db:"title"` - AuthorID int64 `db:"author_id"` - } - - type reviewType struct { - ID int64 `db:"id,omitempty"` - PublicationID int64 `db:"publication_id"` - Name string `db:"name"` - Comments string `db:"comments"` - Created time.Time `db:"created"` - } - - if sess, err = db.Open(Adapter, settings); err != nil { - t.Fatal(err) - } - - defer sess.Close() - - // Artist collection. - if artist, err = sess.Collection("artist"); err != nil { - t.Fatal(err) - } - - if err = artist.Truncate(); err != nil { - t.Fatal(err) - } - - // Publication collection. - if publication, err = sess.Collection("publication"); err != nil { - t.Fatal(err) - } - - if err = publication.Truncate(); err != nil { - t.Fatal(err) - } - - // Review collection. - if review, err = sess.Collection("review"); err != nil { - t.Fatal(err) - } - - if err = review.Truncate(); err != nil { - t.Fatal(err) - } - - // Adding some artists. - var miyazakiID interface{} - miyazaki := artistType{Name: `Hayao Miyazaki`} - if miyazakiID, err = artist.Append(miyazaki); err != nil { - t.Fatal(err) - } - miyazaki.ID = miyazakiID.(int64) - - var asimovID interface{} - asimov := artistType{Name: `Isaac Asimov`} - if asimovID, err = artist.Append(asimov); err != nil { - t.Fatal(err) - } - - var marquezID interface{} - marquez := artistType{Name: `Gabriel GarcÃa Márquez`} - if marquezID, err = artist.Append(marquez); err != nil { - t.Fatal(err) - } - - // Adding some publications. - publication.Append(publicationType{ - Title: `Tonari no Totoro`, - AuthorID: miyazakiID.(int64), - }) - - publication.Append(publicationType{ - Title: `Howl's Moving Castle`, - AuthorID: miyazakiID.(int64), - }) - - publication.Append(publicationType{ - Title: `Ponyo`, - AuthorID: miyazakiID.(int64), - }) - - publication.Append(publicationType{ - Title: `Memoria de mis Putas Tristes`, - AuthorID: marquezID.(int64), - }) - - publication.Append(publicationType{ - Title: `El Coronel no tiene quien le escriba`, - AuthorID: marquezID.(int64), - }) - - publication.Append(publicationType{ - Title: `El Amor en los tiempos del Cólera`, - AuthorID: marquezID.(int64), - }) - - publication.Append(publicationType{ - Title: `I, Robot`, - AuthorID: asimovID.(int64), - }) - - var foundationID interface{} - foundationID, err = publication.Append(publicationType{ - Title: `Foundation`, - AuthorID: asimovID.(int64), - }) - if err != nil { - t.Fatal(err) - } - - publication.Append(publicationType{ - Title: `The Robots of Dawn`, - AuthorID: asimovID.(int64), - }) - - // Adding reviews for foundation. - review.Append(reviewType{ - PublicationID: foundationID.(int64), - Name: "John Doe", - Comments: "I love The Foundation series.", - Created: time.Now(), - }) - - review.Append(reviewType{ - PublicationID: foundationID.(int64), - Name: "Edr Pls", - Comments: "The Foundation series made me fall in love with Isaac Asimov.", - Created: time.Now(), - }) - - // Exec'ing a raw query. - var artistPublication db.Collection - if artistPublication, err = sess.Collection(`artist AS a`, `publication AS p`); err != nil { - t.Fatal(err) - } - - res := artistPublication.Find( - db.Raw{`a.id = p.author_id`}, - ).Select( - "p.id", - "p.title as publication_title", - db.Raw{"a.name AS artist_name"}, - ) - - type artistPublicationType struct { - ID int64 `db:"id"` - PublicationTitle string `db:"publication_title"` - ArtistName string `db:"artist_name"` - } - - all := []artistPublicationType{} - - if err = res.All(&all); err != nil { - t.Fatal(err) - } - - if len(all) != 9 { - t.Fatalf("Expecting some rows.") - } -} - -func TestRawQuery(t *testing.T) { - var sess db.Database - var rows *sqlx.Rows - var err error - var drv *sqlx.DB - - type publicationType struct { - ID int64 `db:"id,omitempty"` - Title string `db:"title"` - AuthorID int64 `db:"author_id"` - } - - if sess, err = db.Open(Adapter, settings); err != nil { - t.Fatal(err) - } - - defer sess.Close() - - drv = sess.Driver().(*sqlx.DB) - - rows, err = drv.Queryx(` - SELECT - p.id, - p.title AS publication_title, - a.name AS artist_name - FROM - artist AS a, - publication AS p - WHERE - a.id = p.author_id - `) - - if err != nil { - t.Fatal(err) - } - - var all []publicationType - - if err = sqlutil.FetchRows(rows, &all); err != nil { - t.Fatal(err) - } - - if len(all) != 9 { - t.Fatalf("Expecting some rows.") - } -} - // Attempts to test database transactions. func TestTransactionsAndRollback(t *testing.T) { var sess db.Database @@ -1914,269 +1693,6 @@ func TestOptionTypeJsonbStruct(t *testing.T) { } } -func TestQueryBuilder(t *testing.T) { - var sess db.Database - var err error - - if sess, err = db.Open(Adapter, settings); err != nil { - t.Fatal(err) - } - - defer sess.Close() - - b := sess.Builder() - - assert := assert.New(t) - - // Testing SELECT. - - assert.Equal( - `SELECT * FROM "artist"`, - b.SelectAllFrom("artist").String(), - ) - - assert.Equal( - `SELECT * FROM "artist"`, - b.Select().From("artist").String(), - ) - - assert.Equal( - `SELECT * FROM "artist" LIMIT -1 OFFSET 5`, - b.Select().From("artist").Limit(-1).Offset(5).String(), - ) - - assert.Equal( - `SELECT "id" FROM "artist"`, - b.Select("id").From("artist").String(), - ) - - assert.Equal( - `SELECT "id", "name" FROM "artist"`, - b.Select("id", "name").From("artist").String(), - ) - - assert.Equal( - `SELECT * FROM "artist" WHERE ("name" = $1)`, - b.SelectAllFrom("artist").Where("name", "Haruki").String(), - ) - - assert.Equal( - `SELECT * FROM "artist" WHERE (name LIKE $1)`, - b.SelectAllFrom("artist").Where("name LIKE ?", `%F%`).String(), - ) - - assert.Equal( - `SELECT "id" FROM "artist" WHERE (name LIKE $1 OR name LIKE $2)`, - b.Select("id").From("artist").Where(`name LIKE ? OR name LIKE ?`, `%Miya%`, `F%`).String(), - ) - - assert.Equal( - `SELECT * FROM "artist" WHERE ("id" > $1)`, - b.SelectAllFrom("artist").Where("id >", 2).String(), - ) - - assert.Equal( - `SELECT * FROM "artist" WHERE (id <= 2 AND name != $1)`, - b.SelectAllFrom("artist").Where("id <= 2 AND name != ?", "A").String(), - ) - - assert.Equal( - `SELECT * FROM "artist" WHERE ("id" IN ($1, $2, $3, $4))`, - b.SelectAllFrom("artist").Where("id IN", []int{1, 9, 8, 7}).String(), - ) - - assert.Equal( - `SELECT * FROM "artist" WHERE (name IS NOT NULL)`, - b.SelectAllFrom("artist").Where("name IS NOT NULL").String(), - ) - - assert.Equal( - `SELECT * FROM "artist" AS "a", "publication" AS "p" WHERE (p.author_id = a.id) LIMIT 1`, - b.Select().From("artist a", "publication as p").Where("p.author_id = a.id").Limit(1).String(), - ) - - assert.Equal( - `SELECT "id" FROM "artist" NATURAL JOIN "publication"`, - b.Select("id").From("artist").Join("publication").String(), - ) - - assert.Equal( - `SELECT * FROM "artist" AS "a" JOIN "publication" AS "p" ON (p.author_id = a.id) LIMIT 1`, - b.SelectAllFrom("artist a").Join("publication p").On("p.author_id = a.id").Limit(1).String(), - ) - - assert.Equal( - `SELECT * FROM "artist" AS "a" JOIN "publication" AS "p" ON (p.author_id = a.id) WHERE ("a"."id" = $1) LIMIT 1`, - b.SelectAllFrom("artist a").Join("publication p").On("p.author_id = a.id").Where("a.id", 2).Limit(1).String(), - ) - - assert.Equal( - `SELECT * FROM "artist" JOIN "publication" AS "p" ON (p.author_id = a.id) WHERE (a.id = 2) LIMIT 1`, - b.SelectAllFrom("artist").Join("publication p").On("p.author_id = a.id").Where("a.id = 2").Limit(1).String(), - ) - - assert.Equal( - `SELECT * FROM "artist" AS "a" JOIN "publication" AS "p" ON (p.title LIKE $1 OR p.title LIKE $2) WHERE (a.id = $3) LIMIT 1`, - b.SelectAllFrom("artist a").Join("publication p").On("p.title LIKE ? OR p.title LIKE ?", "%Totoro%", "%Robot%").Where("a.id = ?", 2).Limit(1).String(), - ) - - assert.Equal( - `SELECT * FROM "artist" AS "a" LEFT JOIN "publication" AS "p1" ON (p1.id = a.id) RIGHT JOIN "publication" AS "p2" ON (p2.id = a.id)`, - b.SelectAllFrom("artist a"). - LeftJoin("publication p1").On("p1.id = a.id"). - RightJoin("publication p2").On("p2.id = a.id"). - String(), - ) - - assert.Equal( - `SELECT * FROM "artist" CROSS JOIN "publication"`, - b.SelectAllFrom("artist").CrossJoin("publication").String(), - ) - - assert.Equal( - `SELECT * FROM "artist" JOIN "publication" USING ("id")`, - b.SelectAllFrom("artist").Join("publication").Using("id").String(), - ) - - assert.Equal( - `SELECT DATE()`, - b.Select(db.Raw{"DATE()"}).String(), - ) - - // Testing INSERT. - - assert.Equal( - `INSERT INTO "artist" VALUES ($1, $2), ($3, $4), ($5, $6)`, - b.InsertInto("artist"). - Values(10, "Ryuichi Sakamoto"). - Values(11, "Alondra de la Parra"). - Values(12, "Haruki Murakami"). - String(), - ) - - assert.Equal( - `INSERT INTO "artist" ("name", "id") VALUES ($1, $2)`, - b.InsertInto("artist").Values(map[string]string{"id": "12", "name": "Chavela Vargas"}).String(), - ) - - assert.Equal( - `INSERT INTO "artist" ("name", "id") VALUES ($1, $2)`, - b.InsertInto("artist").Values(struct { - ID int `db:"id"` - Name string `db:"name"` - }{12, "Chavela Vargas"}).String(), - ) - - assert.Equal( - `INSERT INTO "artist" ("name", "id") VALUES ($1, $2)`, - b.InsertInto("artist").Columns("name", "id").Values("Chavela Vargas", 12).String(), - ) - - // Testing DELETE. - - assert.Equal( - `DELETE FROM "artist" WHERE (name = $1) LIMIT 1`, - b.DeleteFrom("artist").Where("name = ?", "Chavela Vargas").Limit(1).String(), - ) - - assert.Equal( - `DELETE FROM "artist" WHERE (id > 5)`, - b.DeleteFrom("artist").Where("id > 5").String(), - ) - - // Testing UPDATE. - - assert.Equal( - `UPDATE "artist" SET "name" = $1`, - b.Update("artist").Set("name", "Artist").String(), - ) - - assert.Equal( - `UPDATE "artist" SET "name" = $1 WHERE ("id" < $2)`, - b.Update("artist").Set("name = ?", "Artist").Where("id <", 5).String(), - ) - - assert.Equal( - `UPDATE "artist" SET "name" = $1 WHERE ("id" < $2)`, - b.Update("artist").Set(map[string]string{"name": "Artist"}).Where(db.Cond{"id <": 5}).String(), - ) - - assert.Equal( - `UPDATE "artist" SET "name" = $1 WHERE ("id" < $2)`, - b.Update("artist").Set(struct { - Nombre string `db:"name"` - }{"Artist"}).Where(db.Cond{"id <": 5}).String(), - ) - - assert.Equal( - `UPDATE "artist" SET "name" = $1, "last_name" = $2 WHERE ("id" < $3)`, - b.Update("artist").Set(struct { - Nombre string `db:"name"` - }{"Artist"}).Set(map[string]string{"last_name": "Foo"}).Where(db.Cond{"id <": 5}).String(), - ) - - assert.Equal( - `UPDATE "artist" SET "name" = $1 || ' ' || $2 || id, "id" = id + $3 WHERE (id > $4)`, - b.Update("artist").Set( - "name = ? || ' ' || ? || id", "Artist", "#", - "id = id + ?", 10, - ).Where("id > ?", 0).String(), - ) - - /* - // INSERT INTO artist (name) VALUES(? || ?) - if err = b.InsertInto("artist").Columns("name").Values(db.Expr("? || ' ' || ?", "Tom", "Yorke")).Exec(); err != nil { - t.Fatal(err) - } - // INSERT INTO artist ("name") VALUES('Michael Jackson') - if err = b.InsertInto("artist").Columns("name").Record(map[string]string{"no": "Not me!", "name": "Michael Jackson"}).Exec(); err != nil { - t.Fatal(err) - } - - // INSERT INTO artist ("id", "name") VALUES(20, 'Francisco Toledo') - if err = b.InsertInto("artist").Value(map[string]string{"id": 20, "name": "Francisco Toledo"}).Exec(); err != nil { - t.Fatal(err) - } - - // INSERT INTO artist ("name") VALUES('Mads Mikkelsen') - if err = b.InsertInto("artist").Value(artistType{"Mads Mikkelsen"}).Exec(); err != nil { - t.Fatal(err) - } - */ - - // Testing actual queries. - - /* - var artist artistType - var artists []artistType - - err = b.SelectAllFrom("artist").Iterator().All(&artists) - assert.NoError(err) - assert.True(len(artists) > 0) - - err = b.SelectAllFrom("artist").Iterator().One(&artist) - assert.NoError(err) - assert.NotNil(artist) - - var qs db.QuerySelector - - qs = b.SelectAllFrom("artist") - iter := qs.Iterator() - for iter.Next(&artist) { - assert.Nil(iter.Err()) - assert.NotNil(artist) - } - - assert.Nil(iter.Close()) - - qs = b.Select().From("artist a").Join("publications p").On("p1.id = a.id").Using("id") - assert.Error(qs.Iterator().One(&artist), `Should not work because it attempts to use both "On()" and "Using()" in the same JOIN.`) - - qs = b.Select().From("artist a").On("p1.id = a.id") - assert.Error(qs.Iterator().One(&artist), `Should not work because it should put a "Join()" before "On()".`) - */ -} - // TestExhaustConnections simulates a "too many connections" situation // triggered by opening more transactions than available connections. // upper.io/db deals with this problem by waiting a bit more for the connection diff --git a/util/sqlgen/default.go b/util/sqlgen/default.go index 3bd1a5c67068a8447d923ce76fa48ab32a8476c1..db531ccd2d7157126645ac9021eb7151890c11e6 100644 --- a/util/sqlgen/default.go +++ b/util/sqlgen/default.go @@ -16,6 +16,7 @@ const ( defaultDescKeyword = `DESC` defaultAscKeyword = `ASC` defaultDefaultOperator = `=` + defaultAssignmentOperator = `=` defaultClauseGroup = `({{.}})` defaultClauseOperator = ` {{.}} ` defaultColumnValue = `{{.Column}} {{.Operator}} {{.Value}}` @@ -64,36 +65,44 @@ const ( ` defaultSelectLayout = ` - SELECT + SELECT - {{if .Columns}} - {{.Columns}} - {{else}} - * - {{end}} + {{if .Columns}} + {{.Columns}} + {{else}} + * + {{end}} - FROM {{.Table}} + {{if .Table}} + FROM {{.Table}} + {{end}} - {{.Joins}} + {{.Joins}} - {{.Where}} + {{.Where}} - {{.GroupBy}} + {{.GroupBy}} - {{.OrderBy}} + {{.OrderBy}} - {{if .Limit}} - LIMIT {{.Limit}} - {{end}} + {{if .Limit}} + LIMIT {{.Limit}} + {{end}} - {{if .Offset}} - OFFSET {{.Offset}} - {{end}} + {{if .Offset}} + OFFSET {{.Offset}} + {{end}} ` defaultDeleteLayout = ` - DELETE - FROM {{.Table}} - {{.Where}} + DELETE + FROM {{.Table}} + {{.Where}} + {{if .Limit}} + LIMIT {{.Limit}} + {{end}} + {{if .Offset}} + OFFSET {{.Offset}} + {{end}} ` defaultUpdateLayout = ` UPDATE @@ -118,11 +127,11 @@ const ( ` defaultInsertLayout = ` - INSERT INTO {{.Table}} - ({{.Columns}}) - VALUES - {{.Values}} - {{.Extra}} + INSERT INTO {{.Table}} + {{if .Columns }}({{.Columns}}){{end}} + VALUES + {{.Values}} + {{.Extra}} ` defaultTruncateLayout = ` @@ -158,6 +167,7 @@ var defaultTemplate = &Template{ DescKeyword: defaultDescKeyword, AscKeyword: defaultAscKeyword, DefaultOperator: defaultDefaultOperator, + AssignmentOperator: defaultAssignmentOperator, ClauseGroup: defaultClauseGroup, ClauseOperator: defaultClauseOperator, ColumnValue: defaultColumnValue, diff --git a/util/sqlutil/sqlutil.go b/util/sqlutil/sqlutil.go deleted file mode 100644 index 3290adfa2e5451eaad77cd63e666a493ece7ada4..0000000000000000000000000000000000000000 --- a/util/sqlutil/sqlutil.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012-2015 The upper.io/db authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -package sqlutil - -import ( - "strings" -) - -type T struct { - Columns []string - Tables []string // Holds table names. -} - -// MainTableName returns the name of the first table. -func (t *T) MainTableName() string { - return t.NthTableName(0) -} - -// NthTableName returns the table name at index i. -func (t *T) NthTableName(i int) string { - if len(t.Tables) > i { - chunks := strings.SplitN(t.Tables[i], " ", 2) - if len(chunks) > 0 { - return chunks[0] - } - } - return "" -} - -// HashTableNames returns a unique string for the given array of tables. -func HashTableNames(names []string) string { - return strings.Join(names, "|") - // I think we don't really need to do this, the strings.Join already provides a unique string per array. - // return fmt.Sprintf("%x", md5.Sum([]byte(strings.Join(names, "|")))) -}