package store import "github.com/manishrjain/gocrud/x" var log = x.Log("store") type Store interface { Init(dbtype string, tablename string) Commit(tablePrefix string, its []*x.Instruction) error IsNew(tablePrefix string, subject string) bool GetEntity(tablePrefix string, subject string) ([]x.Instruction, error) }
package main import ( "fmt" "math/rand" "net/http" "time" "github.com/manishrjain/gocrud/api" "github.com/manishrjain/gocrud/helper" "github.com/manishrjain/gocrud/req" "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" ) var log = x.Log("server") var c *req.Context func read(w http.ResponseWriter, r *http.Request) { id, ok := x.ParseIdFromUrl(r, "/read/") if !ok { return } // API usage to read data. q := api.NewQuery("hack", id).UptoDepth(10) result, err := q.Run(c) if err != nil { x.SetStatus(w, x.E_ERROR, err.Error()) return }
_ "github.com/go-sql-driver/mysql" "github.com/gocql/gocql" _ "github.com/lib/pq" "github.com/manishrjain/gocrud/api" "github.com/manishrjain/gocrud/req" "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" ) var storeType = flag.String("store", "leveldb", "Available stores are cass for cassandra, "+ "sql for MySQL, leveldb for LevelDB, "+ "datastore for Google Datastore. "+ "LevelDB is the default.") var log = x.Log("social") var c *req.Context type Like struct { Id string `json:"id,omitempty"` } type Comment struct { Id string `json:"id,omitempty"` Comment []Comment `json:"Comment,omitempty"` Like []Like `json:"Like,omitempty"` } type Post struct { Id string `json:"id,omitempty"` Comment []Comment `json:"Comment,omitempty"`
// This package is the initialization point for the api. // In particular, in your init (/main) function, the flow // is to create a req.Context and fill in required options. // Setting table prefix, length for unique strings generated // to assign to new entities, and setting the storage system. package req import "github.com/manishrjain/gocrud/x" var log = x.Log("req") type Context struct { NumCharsUnique int // 62^num unique strings Updates chan x.Entity HasIndexer bool } func NewContext(numChars int) *Context { ctx := new(Context) ctx.NumCharsUnique = numChars ctx.HasIndexer = false ctx.Updates = nil return ctx } func NewContextWithUpdates(numChars, buffer int) *Context { ctx := new(Context) ctx.NumCharsUnique = numChars ctx.Updates = make(chan x.Entity, buffer) ctx.HasIndexer = true return ctx
// Package search provides a way to index entities and run relatively // complicated search queries, best served outside of data stores, and // by specialized search engines like ElasticSearch or Solr etc. // // This tackles the limitations caused by gocrud in terms of filtering // and sort operations which would otherwise would need to be done at // application level. package search import "github.com/manishrjain/gocrud/x" var log = x.Log("search") // All the search operations are run via this Search interface. // Implement this interface to add support for a search engine. // Note that the term Entity is being used interchangeably with // the term Subject. An Entity has a kind, and has an id. // Query interface provides the search api encapsulator, responsible for // generating the right query for the engine, and then running it. type Query interface { // NewAndFilter would return a filter which would run AND operation // among individual filter queries. NewAndFilter() FilterQuery // NewOrFilter would return a filter which would run OR operation // among individual filter queries. NewOrFilter() FilterQuery // From would set the offset from the first result. Use it along // with Limit(int) to do pagination.
// To test this mongodb integration, run mongodb in docker // docker run -d --name mongo -p 27017:27017 mongo:latest // If on Mac, find the IP address of the docker host // $ boot2docker ip // 192.168.59.103 // For linux it's 127.0.0.1. import ( "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" "labix.org/v2/mgo" "labix.org/v2/mgo/bson" ) var log = x.Log("mongodb") // MongoDB store backed by MongoDB type MongoDB struct { session *mgo.Session database string collection string } // Init setup a new collection using the name provided func (mdb *MongoDB) Init(args ...string) { if len(args) != 3 { log.WithField("args", args).Fatal("Invalid arguments") return }
package memsearch import ( "errors" "fmt" "reflect" "regexp" "sort" "strings" "github.com/Sirupsen/logrus" "github.com/manishrjain/gocrud/search" "github.com/manishrjain/gocrud/x" ) var log = x.Log("memsearch") type MemSearch struct { docs map[string]x.Doc } type MemQuery struct { kind string Docs []x.Doc filter *MemFilter filterType int // 0 = no filter, 1 = AND, 2 = OR from int limit int order string }
import ( "fmt" "io/ioutil" "time" _ "github.com/manishrjain/gocrud/drivers/leveldb" _ "github.com/manishrjain/gocrud/drivers/memsearch" "github.com/manishrjain/gocrud/indexer" "github.com/manishrjain/gocrud/req" "github.com/manishrjain/gocrud/search" "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" ) var log = x.Log("usage") func ExampleStore() { path, err := ioutil.TempDir("", "gocrudldb_") if err != nil { x.LogErr(log, err).Fatal("Opening file") return } store.Get().Init(path) // leveldb // Update some data. c := req.NewContext(10) // 62^10 permutations err = store.NewUpdate("Root", "bigbang").SetSource("author"). Set("when", "13.8 billion years ago").Set("explosive", true).Execute(c) if err != nil { x.LogErr(log, err).Fatal("Commiting update")
package sqlstore import ( "database/sql" "fmt" "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" ) var log = x.Log("sqlstore") type Sql struct { db *sql.DB } var sqlInsert *sql.Stmt var sqlIsNew, sqlSelect string func (s *Sql) Init(args ...string) { if len(args) != 3 { log.WithField("args", args).Fatal("Invalid arguments") return } dbtype := args[0] source := args[1] tablename := args[2] var err error s.db, err = sql.Open(dbtype, source)
package elasticsearch import ( "errors" "reflect" "github.com/manishrjain/gocrud/search" "github.com/manishrjain/gocrud/x" "gopkg.in/olivere/elastic.v2" ) var log = x.Log("elasticsearch") // Elastic encapsulates elastic search client, and implements methods declared // by search.Engine. type Elastic struct { client *elastic.Client } // ElasticQuery implements methods declared by search.Query. type ElasticQuery struct { client *elastic.Client sort string from int limit int kind string filter *ElasticFilter filterType int // 0 = no filter, 1 = AND, 2 = OR } type ElasticFilter struct {
// Cassandra driver can now be imported, and initialized in social.go, // or any other client. // import _ "github.com/manishrjain/gocrud/drivers/cassandra" // Initialize in main(): // store.Get().Init("cassone", "crudtest", "instructions") package cassandra import ( "fmt" "github.com/gocql/gocql" "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" ) var log = x.Log("cassandra") type Cassandra struct { session *gocql.Session } var kIsNew, kInsert, kSelect, kScan string func (cs *Cassandra) SetSession(session *gocql.Session) { cs.session = session } func (cs *Cassandra) Init(args ...string) { if len(args) != 3 && len(args) != 5 { log.WithField("args", args).Fatal("Invalid arguments") return
package indexer import ( "sort" "sync" "github.com/manishrjain/gocrud/req" "github.com/manishrjain/gocrud/search" "github.com/manishrjain/gocrud/x" ) var log = x.Log("indexer") // Indexer functions are called automatically by store operations. // These functions are used to determine which entities need updating, // and then re-generate their corresponding documents, which then get // re-indexed into search engine, overwriting past // (using versioning, if available) documents. type Indexer interface { // OnUpdate is called when an entity is updated due to a Commit // on either itself, or it's direct children. Note that each // child entity would also be called with OnUpdate. This function // should return the Entity Ids, which need regeneration. OnUpdate(x.Entity) []x.Entity // Regenerate would be called on entities which need to be reprocessed // due to a change. The workflow is: // store.Commit -> search.OnUpdate -> Regenerate Regenerate(x.Entity) x.Doc }
package api import ( "encoding/json" "errors" "fmt" "time" "github.com/Sirupsen/logrus" "github.com/manishrjain/gocrud/req" "github.com/manishrjain/gocrud/x" ) var log = x.Log("api") type Node struct { kind string id string source string children []*Node parent *Node edges map[string]interface{} Timestamp int64 } func Get(kind, id string) *Node { log.WithFields(logrus.Fields{ "func": "GetNode", "kind": kind, "id": id, }).Debug("Called Get")
// If on Mac, find the IP address of the docker host // $ boot2docker ip // 192.168.59.103 // For linux it's 127.0.0.1. // Now you can go to 192.168.59.103:8080 (or 127.0.0.1:8080) and create // table 'instructions'. Once created, create an index by going to // 'Data Explorer', and running this: // r.db('test').table('instructions').indexCreate('SubjectId') import ( r "github.com/dancannon/gorethink" "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" ) var log = x.Log("rethinkdb") type RethinkDB struct { session *r.Session table string } func (rdb *RethinkDB) SetSession(session *r.Session) { rdb.session = session } func (rdb *RethinkDB) Init(args ...string) { if len(args) != 3 { log.WithField("args", args).Fatal("Invalid arguments") return }
package leveldb import ( "errors" "fmt" "github.com/manishrjain/gocrud/store" "github.com/manishrjain/gocrud/x" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/filter" "github.com/syndtr/goleveldb/leveldb/opt" "github.com/syndtr/goleveldb/leveldb/util" ) var log = x.Log("leveldb") type Leveldb struct { db *leveldb.DB opt *opt.Options } func (l *Leveldb) SetBloomFilter(bits int) { l.opt = &opt.Options{ Filter: filter.NewBloomFilter(bits), } } func (l *Leveldb) Init(args ...string) { if len(args) != 1 { log.WithField("args", args).Fatal("Invalid arguments") return