Newer
Older
// Copyright (c) 2012-present 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.
José Carlos Nieto
committed
package mongo // import "upper.io/db.v2/mongo"
José Carlos Nieto
committed
import (
"strings"
"gopkg.in/mgo.v2"
"upper.io/db.v2"
José Carlos Nieto
committed
)
// Adapter holds the name of the mongodb adapter.
var connTimeout = time.Second * 5
// Source represents a MongoDB database.
name string
connURL db.ConnectionURL
session *mgo.Session
database *mgo.Database
version []int
collections map[string]*Collection
collectionsMu sync.Mutex
José Carlos Nieto
committed
}
db.RegisterAdapter(Adapter, &db.AdapterFuncMap{
Open: Open,
})
// Open stablishes a new connection to a SQL server.
func Open(settings db.ConnectionURL) (db.Database, error) {
if err := d.Open(settings); err != nil {
return nil, err
}
return d, nil
}
func (s *Source) ConnectionURL() db.ConnectionURL {
return s.connURL
}
// Name returns the name of the database.
func (s *Source) Name() string {
return s.name
// Open attempts to connect to the database.
func (s *Source) Open(connURL db.ConnectionURL) error {
// Clone returns a cloned db.Database session.
func (s *Source) Clone() (db.Database, error) {
newSession := s.session.Copy()
name: s.name,
connURL: s.connURL,
session: newSession,
database: newSession.DB(s.database.Name),
version: s.version,
collections: map[string]*Collection{},
}
return clone, nil
}
// NewTransaction should support transactions, but it doesn't as MongoDB
func (s *Source) NewTransaction() (db.Tx, error) {
return nil, db.ErrUnsupported
}
// Ping checks whether a connection to the database is still alive by pinging
// it, establishing a connection if necessary.
func (s *Source) Ping() error {
return s.session.Ping()
func (s *Source) ClearCache() {
s.collectionsMu.Lock()
defer s.collectionsMu.Unlock()
s.collections = make(map[string]*Collection)
}
// Driver returns the underlying *mgo.Session instance.
func (s *Source) Driver() interface{} {
return s.session
José Carlos Nieto
committed
}
if s.session, err = mgo.DialWithTimeout(s.connURL.String(), connTimeout); err != nil {
s.collections = map[string]*Collection{}
José Carlos Nieto
committed
}
// Close terminates the current database session.
func (s *Source) Close() error {
if s.session != nil {
s.session.Close()
José Carlos Nieto
committed
}
return nil
}
// Collections returns a list of non-system tables from the database.
func (s *Source) Collections() (cols []string, err error) {
var rawcols []string
var col string
if rawcols, err = s.database.CollectionNames(); err != nil {
cols = make([]string, 0, len(rawcols))
for _, col = range rawcols {
if !strings.HasPrefix(col, "system.") {
// Collection returns a collection by name.
func (s *Source) Collection(name string) db.Collection {
s.collectionsMu.Lock()
defer s.collectionsMu.Unlock()
var col *Collection
var ok bool
if col, ok = s.collections[name]; !ok {
col = &Collection{
parent: s,
collection: s.database.C(name),
}
s.collections[name] = col
}
func (s *Source) versionAtLeast(version ...int) bool {
// only fetch this once - it makes a db call
if len(s.version) == 0 {
buildInfo, err := s.database.Session.BuildInfo()
if err != nil {
return false
}
s.version = buildInfo.VersionArray
}
// Check major version first
if s.version[0] > version[0] {
return true
}