Add opts to service proto (#1517)

* Add opts to service proto

* Support database/table opts
This commit is contained in:
Asim Aslam 2020-04-30 22:51:25 +01:00 committed by GitHub
parent fccab8ad27
commit 359b8bc503
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 774 additions and 830 deletions

View File

@ -7,6 +7,7 @@ import (
"net/url" "net/url"
"regexp" "regexp"
"strings" "strings"
"sync"
"time" "time"
"github.com/lib/pq" "github.com/lib/pq"
@ -21,214 +22,51 @@ var (
DefaultTable = "micro" DefaultTable = "micro"
) )
var (
statements = map[string]string{
"list": "SELECT key, value, expiry FROM %s.%s;",
"read": "SELECT key, value, expiry FROM %s.%s WHERE key = $1;",
"readMany": "SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1;",
"readOffset": "SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;",
"write": "INSERT INTO %s.%s(key, value, expiry) VALUES ($1, $2::bytea, $3) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, expiry = EXCLUDED.expiry;",
"delete": "DELETE FROM %s.%s WHERE key = $1;",
}
)
type sqlStore struct { type sqlStore struct {
db *sql.DB
database string
table string
list *sql.Stmt
readOne *sql.Stmt
readMany *sql.Stmt
readOffset *sql.Stmt
write *sql.Stmt
delete *sql.Stmt
options store.Options options store.Options
db *sql.DB
sync.RWMutex
// known databases
databases map[string]bool
} }
func (s *sqlStore) Close() error { func (s *sqlStore) createDB(database, table string) {
closeStmt(s.delete) if len(database) == 0 {
closeStmt(s.list) database = s.options.Database
closeStmt(s.readMany)
closeStmt(s.readOffset)
closeStmt(s.readOne)
closeStmt(s.write)
if s.db != nil {
return s.db.Close()
} }
return nil if len(table) == 0 {
table = s.options.Table
}
s.Lock()
_, ok := s.databases[database+":"+table]
if !ok {
s.initDB(database, table)
s.databases[database+":"+table] = true
}
s.Unlock()
} }
func (s *sqlStore) Init(opts ...store.Option) error { func (s *sqlStore) initDB(database, table string) error {
for _, o := range opts {
o(&s.options)
}
// reconfigure
return s.configure()
}
// List all the known records
func (s *sqlStore) List(opts ...store.ListOption) ([]string, error) {
rows, err := s.list.Query()
var keys []string
var timehelper pq.NullTime
if err != nil {
if err == sql.ErrNoRows {
return keys, nil
}
return nil, err
}
defer rows.Close()
for rows.Next() {
record := &store.Record{}
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
return keys, err
}
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
go s.Delete(record.Key)
} else {
record.Expiry = time.Until(timehelper.Time)
keys = append(keys, record.Key)
}
} else {
keys = append(keys, record.Key)
}
}
rowErr := rows.Close()
if rowErr != nil {
// transaction rollback or something
return keys, rowErr
}
if err := rows.Err(); err != nil {
return keys, err
}
return keys, nil
}
// Read a single key
func (s *sqlStore) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
var options store.ReadOptions
for _, o := range opts {
o(&options)
}
if options.Prefix || options.Suffix {
return s.read(key, options)
}
var records []*store.Record
var timehelper pq.NullTime
row := s.readOne.QueryRow(key)
record := &store.Record{}
if err := row.Scan(&record.Key, &record.Value, &timehelper); err != nil {
if err == sql.ErrNoRows {
return records, store.ErrNotFound
}
return records, err
}
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
go s.Delete(key)
return records, store.ErrNotFound
}
record.Expiry = time.Until(timehelper.Time)
records = append(records, record)
} else {
records = append(records, record)
}
return records, nil
}
// Read Many records
func (s *sqlStore) read(key string, options store.ReadOptions) ([]*store.Record, error) {
pattern := "%"
if options.Prefix {
pattern = key + pattern
}
if options.Suffix {
pattern = pattern + key
}
var rows *sql.Rows
var err error
if options.Limit != 0 {
rows, err = s.readOffset.Query(pattern, options.Limit, options.Offset)
} else {
rows, err = s.readMany.Query(pattern)
}
if err != nil {
if err == sql.ErrNoRows {
return []*store.Record{}, nil
}
return []*store.Record{}, errors.Wrap(err, "sqlStore.read failed")
}
defer rows.Close()
var records []*store.Record
var timehelper pq.NullTime
for rows.Next() {
record := &store.Record{}
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
return records, err
}
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
go s.Delete(record.Key)
} else {
record.Expiry = time.Until(timehelper.Time)
records = append(records, record)
}
} else {
records = append(records, record)
}
}
rowErr := rows.Close()
if rowErr != nil {
// transaction rollback or something
return records, rowErr
}
if err := rows.Err(); err != nil {
return records, err
}
return records, nil
}
// Write records
func (s *sqlStore) Write(r *store.Record, opts ...store.WriteOption) error {
var err error
if r.Expiry != 0 {
_, err = s.write.Exec(r.Key, r.Value, time.Now().Add(r.Expiry))
} else {
_, err = s.write.Exec(r.Key, r.Value, nil)
}
if err != nil {
return errors.Wrap(err, "Couldn't insert record "+r.Key)
}
return nil
}
// Delete records with keys
func (s *sqlStore) Delete(key string, opts ...store.DeleteOption) error {
result, err := s.delete.Exec(key)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
}
func (s *sqlStore) initDB() error {
// Create the namespace's database // Create the namespace's database
_, err := s.db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s ;", s.database)) _, err := s.db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s ;", database))
if err != nil { if err != nil {
return err return err
} }
_, err = s.db.Exec(fmt.Sprintf("SET DATABASE = %s ;", s.database)) _, err = s.db.Exec(fmt.Sprintf("SET DATABASE = %s ;", database))
if err != nil { if err != nil {
return errors.Wrap(err, "Couldn't set database") return errors.Wrap(err, "Couldn't set database")
} }
@ -240,58 +78,17 @@ func (s *sqlStore) initDB() error {
value bytea, value bytea,
expiry timestamp with time zone, expiry timestamp with time zone,
CONSTRAINT %s_pkey PRIMARY KEY (key) CONSTRAINT %s_pkey PRIMARY KEY (key)
);`, s.table, s.table)) );`, table, table))
if err != nil { if err != nil {
return errors.Wrap(err, "Couldn't create table") return errors.Wrap(err, "Couldn't create table")
} }
// Create Index // Create Index
_, err = s.db.Exec(fmt.Sprintf(`CREATE INDEX IF NOT EXISTS "%s" ON %s.%s USING btree ("key");`, "key_index_"+s.table, s.database, s.table)) _, err = s.db.Exec(fmt.Sprintf(`CREATE INDEX IF NOT EXISTS "%s" ON %s.%s USING btree ("key");`, "key_index_"+table, database, table))
if err != nil { if err != nil {
return err return err
} }
list, err := s.db.Prepare(fmt.Sprintf("SELECT key, value, expiry FROM %s.%s;", s.database, s.table))
if err != nil {
return errors.Wrap(err, "List statement couldn't be prepared")
}
closeStmt(s.list)
s.list = list
readOne, err := s.db.Prepare(fmt.Sprintf("SELECT key, value, expiry FROM %s.%s WHERE key = $1;", s.database, s.table))
if err != nil {
return errors.Wrap(err, "ReadOne statement couldn't be prepared")
}
closeStmt(s.readOne)
s.readOne = readOne
readMany, err := s.db.Prepare(fmt.Sprintf("SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1;", s.database, s.table))
if err != nil {
return errors.Wrap(err, "ReadMany statement couldn't be prepared")
}
closeStmt(s.readMany)
s.readMany = readMany
readOffset, err := s.db.Prepare(fmt.Sprintf("SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;", s.database, s.table))
if err != nil {
return errors.Wrap(err, "ReadOffset statement couldn't be prepared")
}
closeStmt(s.readOffset)
s.readOffset = readOffset
write, err := s.db.Prepare(fmt.Sprintf(`INSERT INTO %s.%s(key, value, expiry)
VALUES ($1, $2::bytea, $3)
ON CONFLICT (key)
DO UPDATE
SET value = EXCLUDED.value, expiry = EXCLUDED.expiry;`, s.database, s.table))
if err != nil {
return errors.Wrap(err, "Write statement couldn't be prepared")
}
closeStmt(s.write)
s.write = write
delete, err := s.db.Prepare(fmt.Sprintf("DELETE FROM %s.%s WHERE key = $1;", s.database, s.table))
if err != nil {
return errors.Wrap(err, "Delete statement couldn't be prepared")
}
closeStmt(s.delete)
s.delete = delete
return nil return nil
} }
@ -344,21 +141,286 @@ func (s *sqlStore) configure() error {
// save the values // save the values
s.db = db s.db = db
s.database = database
s.table = table
// initialise the database // initialise the database
return s.initDB() return s.initDB(s.options.Database, s.options.Table)
} }
func (s *sqlStore) String() string { func (s *sqlStore) prepare(database, table, query string) (*sql.Stmt, error) {
return "cockroach" st, ok := statements[query]
if !ok {
return nil, errors.New("unsupported statement")
}
if len(database) == 0 {
database = s.options.Database
}
if len(table) == 0 {
table = s.options.Table
}
q := fmt.Sprintf(st, database, table)
stmt, err := s.db.Prepare(q)
if err != nil {
return nil, err
}
return stmt, nil
}
func (s *sqlStore) Close() error {
if s.db != nil {
return s.db.Close()
}
return nil
}
func (s *sqlStore) Init(opts ...store.Option) error {
for _, o := range opts {
o(&s.options)
}
// reconfigure
return s.configure()
}
// List all the known records
func (s *sqlStore) List(opts ...store.ListOption) ([]string, error) {
var options store.ListOptions
for _, o := range opts {
o(&options)
}
// create the db if not exists
s.createDB(options.Database, options.Table)
st, err := s.prepare(options.Database, options.Table, "list")
if err != nil {
return nil, err
}
defer st.Close()
rows, err := st.Query()
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
defer rows.Close()
var keys []string
var timehelper pq.NullTime
for rows.Next() {
record := &store.Record{}
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
return keys, err
}
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
go s.Delete(record.Key)
} else {
record.Expiry = time.Until(timehelper.Time)
keys = append(keys, record.Key)
}
} else {
keys = append(keys, record.Key)
}
}
rowErr := rows.Close()
if rowErr != nil {
// transaction rollback or something
return keys, rowErr
}
if err := rows.Err(); err != nil {
return keys, err
}
return keys, nil
}
// Read a single key
func (s *sqlStore) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
var options store.ReadOptions
for _, o := range opts {
o(&options)
}
// create the db if not exists
s.createDB(options.Database, options.Table)
if options.Prefix || options.Suffix {
return s.read(key, options)
}
var records []*store.Record
var timehelper pq.NullTime
st, err := s.prepare(options.Database, options.Table, "read")
if err != nil {
return nil, err
}
defer st.Close()
row := st.QueryRow(key)
record := &store.Record{}
if err := row.Scan(&record.Key, &record.Value, &timehelper); err != nil {
if err == sql.ErrNoRows {
return records, store.ErrNotFound
}
return records, err
}
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
go s.Delete(key)
return records, store.ErrNotFound
}
record.Expiry = time.Until(timehelper.Time)
records = append(records, record)
} else {
records = append(records, record)
}
return records, nil
}
// Read Many records
func (s *sqlStore) read(key string, options store.ReadOptions) ([]*store.Record, error) {
pattern := "%"
if options.Prefix {
pattern = key + pattern
}
if options.Suffix {
pattern = pattern + key
}
var rows *sql.Rows
var err error
if options.Limit != 0 {
st, err := s.prepare(options.Database, options.Table, "readOffset")
if err != nil {
return nil, err
}
defer st.Close()
rows, err = st.Query(pattern, options.Limit, options.Offset)
} else {
st, err := s.prepare(options.Database, options.Table, "readMany")
if err != nil {
return nil, err
}
defer st.Close()
rows, err = st.Query(pattern)
}
if err != nil {
if err == sql.ErrNoRows {
return []*store.Record{}, nil
}
return []*store.Record{}, errors.Wrap(err, "sqlStore.read failed")
}
defer rows.Close()
var records []*store.Record
var timehelper pq.NullTime
for rows.Next() {
record := &store.Record{}
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
return records, err
}
if timehelper.Valid {
if timehelper.Time.Before(time.Now()) {
// record has expired
go s.Delete(record.Key)
} else {
record.Expiry = time.Until(timehelper.Time)
records = append(records, record)
}
} else {
records = append(records, record)
}
}
rowErr := rows.Close()
if rowErr != nil {
// transaction rollback or something
return records, rowErr
}
if err := rows.Err(); err != nil {
return records, err
}
return records, nil
}
// Write records
func (s *sqlStore) Write(r *store.Record, opts ...store.WriteOption) error {
var options store.WriteOptions
for _, o := range opts {
o(&options)
}
// create the db if not exists
s.createDB(options.Database, options.Table)
st, err := s.prepare(options.Database, options.Table, "write")
if err != nil {
return err
}
defer st.Close()
if r.Expiry != 0 {
_, err = st.Exec(r.Key, r.Value, time.Now().Add(r.Expiry))
} else {
_, err = st.Exec(r.Key, r.Value, nil)
}
if err != nil {
return errors.Wrap(err, "Couldn't insert record "+r.Key)
}
return nil
}
// Delete records with keys
func (s *sqlStore) Delete(key string, opts ...store.DeleteOption) error {
var options store.DeleteOptions
for _, o := range opts {
o(&options)
}
// create the db if not exists
s.createDB(options.Database, options.Table)
st, err := s.prepare(options.Database, options.Table, "delete")
if err != nil {
return err
}
defer st.Close()
result, err := st.Exec(key)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
} }
func (s *sqlStore) Options() store.Options { func (s *sqlStore) Options() store.Options {
return s.options return s.options
} }
func (s *sqlStore) String() string {
return "cockroach"
}
// NewStore returns a new micro Store backed by sql // NewStore returns a new micro Store backed by sql
func NewStore(opts ...store.Option) store.Store { func NewStore(opts ...store.Option) store.Store {
var options store.Options var options store.Options
@ -370,16 +432,11 @@ func NewStore(opts ...store.Option) store.Store {
s := new(sqlStore) s := new(sqlStore)
// set the options // set the options
s.options = options s.options = options
// mark known databases
s.databases = make(map[string]bool)
// best-effort configure the store // best-effort configure the store
s.configure() s.configure()
// return store // return store
return s return s
} }
func closeStmt(s *sql.Stmt) {
if s != nil {
s.Close()
}
}

View File

@ -7,10 +7,10 @@ import (
"path/filepath" "path/filepath"
"sort" "sort"
"strings" "strings"
"sync"
"time" "time"
"github.com/micro/go-micro/v2/store" "github.com/micro/go-micro/v2/store"
"github.com/pkg/errors"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
) )
@ -29,18 +29,25 @@ var (
// NewStore returns a memory store // NewStore returns a memory store
func NewStore(opts ...store.Option) store.Store { func NewStore(opts ...store.Option) store.Store {
s := &fileStore{} s := &fileStore{
handles: make(map[string]*fileHandle),
}
s.init(opts...) s.init(opts...)
return s return s
} }
type fileStore struct { type fileStore struct {
options store.Options options store.Options
dir string dir string
fileName string
dbPath string
// the database handle // the database handle
db *bolt.DB sync.RWMutex
handles map[string]*fileHandle
}
type fileHandle struct {
key string
db *bolt.DB
} }
// record stored by us // record stored by us
@ -50,8 +57,12 @@ type record struct {
ExpiresAt time.Time ExpiresAt time.Time
} }
func (m *fileStore) delete(key string) error { func key(database, table string) string {
return m.db.Update(func(tx *bolt.Tx) error { return database + ":" + table
}
func (m *fileStore) delete(fd *fileHandle, key string) error {
return fd.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(dataBucket)) b := tx.Bucket([]byte(dataBucket))
if b == nil { if b == nil {
return nil return nil
@ -76,42 +87,63 @@ func (m *fileStore) init(opts ...store.Option) error {
// create a directory /tmp/micro // create a directory /tmp/micro
dir := filepath.Join(DefaultDir, m.options.Database) dir := filepath.Join(DefaultDir, m.options.Database)
// create the database handle
fname := m.options.Table + ".db"
// Ignoring this as the folder might exist. // Ignoring this as the folder might exist.
// Reads/Writes updates will return with sensible error messages // Reads/Writes updates will return with sensible error messages
// about the dir not existing in case this cannot create the path anyway // about the dir not existing in case this cannot create the path anyway
os.MkdirAll(dir, 0700) os.MkdirAll(dir, 0700)
m.dir = dir return nil
m.fileName = fname
m.dbPath = filepath.Join(dir, fname)
// close existing handle
if m.db != nil {
m.db.Close()
}
// create new db handle
db, err := bolt.Open(m.dbPath, 0700, &bolt.Options{Timeout: 5 * time.Second})
if err != nil {
return err
}
// set the new db
m.db = db
// create the table
return db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(dataBucket))
return err
})
} }
func (m *fileStore) list(limit, offset uint) []string { func (f *fileStore) getDB(database, table string) (*fileHandle, error) {
if len(database) == 0 {
database = f.options.Database
}
if len(table) == 0 {
table = f.options.Table
}
k := key(database, table)
f.RLock()
fd, ok := f.handles[k]
f.RUnlock()
// return the file handle
if ok {
return fd, nil
}
// create a directory /tmp/micro
dir := filepath.Join(DefaultDir, database)
// create the database handle
fname := table + ".db"
// make the dir
os.MkdirAll(dir, 0700)
// database path
dbPath := filepath.Join(dir, fname)
// create new db handle
db, err := bolt.Open(dbPath, 0700, &bolt.Options{Timeout: 5 * time.Second})
if err != nil {
return nil, err
}
f.Lock()
fd = &fileHandle{
key: k,
db: db,
}
f.handles[k] = fd
f.Unlock()
return fd, nil
}
func (m *fileStore) list(fd *fileHandle, limit, offset uint) []string {
var allItems []string var allItems []string
m.db.View(func(tx *bolt.Tx) error { fd.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(dataBucket)) b := tx.Bucket([]byte(dataBucket))
// nothing to read // nothing to read
if b == nil { if b == nil {
@ -162,10 +194,10 @@ func (m *fileStore) list(limit, offset uint) []string {
return allKeys return allKeys
} }
func (m *fileStore) get(k string) (*store.Record, error) { func (m *fileStore) get(fd *fileHandle, k string) (*store.Record, error) {
var value []byte var value []byte
m.db.View(func(tx *bolt.Tx) error { fd.db.View(func(tx *bolt.Tx) error {
// @todo this is still very experimental... // @todo this is still very experimental...
b := tx.Bucket([]byte(dataBucket)) b := tx.Bucket([]byte(dataBucket))
if b == nil { if b == nil {
@ -200,7 +232,7 @@ func (m *fileStore) get(k string) (*store.Record, error) {
return newRecord, nil return newRecord, nil
} }
func (m *fileStore) set(r *store.Record) error { func (m *fileStore) set(fd *fileHandle, r *store.Record) error {
// copy the incoming record and then // copy the incoming record and then
// convert the expiry in to a hard timestamp // convert the expiry in to a hard timestamp
item := &record{} item := &record{}
@ -213,7 +245,7 @@ func (m *fileStore) set(r *store.Record) error {
// marshal the data // marshal the data
data, _ := json.Marshal(item) data, _ := json.Marshal(item)
return m.db.Update(func(tx *bolt.Tx) error { return fd.db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(dataBucket)) b := tx.Bucket([]byte(dataBucket))
if b == nil { if b == nil {
var err error var err error
@ -226,53 +258,63 @@ func (m *fileStore) set(r *store.Record) error {
}) })
} }
func (m *fileStore) Close() error { func (f *fileStore) Close() error {
if m.db != nil { f.Lock()
return m.db.Close() defer f.Unlock()
for k, v := range f.handles {
v.db.Close()
delete(f.handles, k)
} }
return nil return nil
} }
func (m *fileStore) Init(opts ...store.Option) error { func (f *fileStore) Init(opts ...store.Option) error {
return m.init(opts...) return f.init(opts...)
} }
func (m *fileStore) Delete(key string, opts ...store.DeleteOption) error { func (m *fileStore) Delete(key string, opts ...store.DeleteOption) error {
deleteOptions := store.DeleteOptions{} var deleteOptions store.DeleteOptions
for _, o := range opts { for _, o := range opts {
o(&deleteOptions) o(&deleteOptions)
} }
return m.delete(key)
fd, err := m.getDB(deleteOptions.Database, deleteOptions.Table)
if err != nil {
return err
}
return m.delete(fd, key)
} }
func (m *fileStore) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) { func (m *fileStore) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
readOpts := store.ReadOptions{} var readOpts store.ReadOptions
for _, o := range opts { for _, o := range opts {
o(&readOpts) o(&readOpts)
} }
fd, err := m.getDB(readOpts.Database, readOpts.Table)
if err != nil {
return nil, err
}
var keys []string var keys []string
// Handle Prefix / suffix // Handle Prefix / suffix
// TODO: do range scan here rather than listing all keys // TODO: do range scan here rather than listing all keys
if readOpts.Prefix || readOpts.Suffix { if readOpts.Prefix || readOpts.Suffix {
var opts []store.ListOption // list the keys
if readOpts.Prefix { k := m.list(fd, readOpts.Limit, readOpts.Offset)
opts = append(opts, store.ListPrefix(key))
}
if readOpts.Suffix {
opts = append(opts, store.ListSuffix(key))
}
opts = append(opts, store.ListLimit(readOpts.Limit)) // check for prefix and suffix
opts = append(opts, store.ListOffset(readOpts.Offset)) for _, v := range k {
if readOpts.Prefix && !strings.HasPrefix(v, key) {
k, err := m.List(opts...) continue
if err != nil { }
return nil, errors.Wrap(err, "FileStore: Read couldn't List()") if readOpts.Suffix && !strings.HasSuffix(v, key) {
continue
}
keys = append(keys, v)
} }
keys = k
} else { } else {
keys = []string{key} keys = []string{key}
} }
@ -280,7 +322,7 @@ func (m *fileStore) Read(key string, opts ...store.ReadOption) ([]*store.Record,
var results []*store.Record var results []*store.Record
for _, k := range keys { for _, k := range keys {
r, err := m.get(k) r, err := m.get(fd, k)
if err != nil { if err != nil {
return results, err return results, err
} }
@ -291,11 +333,16 @@ func (m *fileStore) Read(key string, opts ...store.ReadOption) ([]*store.Record,
} }
func (m *fileStore) Write(r *store.Record, opts ...store.WriteOption) error { func (m *fileStore) Write(r *store.Record, opts ...store.WriteOption) error {
writeOpts := store.WriteOptions{} var writeOpts store.WriteOptions
for _, o := range opts { for _, o := range opts {
o(&writeOpts) o(&writeOpts)
} }
fd, err := m.getDB(writeOpts.Database, writeOpts.Table)
if err != nil {
return err
}
if len(opts) > 0 { if len(opts) > 0 {
// Copy the record before applying options, or the incoming record will be mutated // Copy the record before applying options, or the incoming record will be mutated
newRecord := store.Record{} newRecord := store.Record{}
@ -310,10 +357,10 @@ func (m *fileStore) Write(r *store.Record, opts ...store.WriteOption) error {
newRecord.Expiry = writeOpts.TTL newRecord.Expiry = writeOpts.TTL
} }
return m.set(&newRecord) return m.set(fd, &newRecord)
} }
return m.set(r) return m.set(fd, r)
} }
func (m *fileStore) Options() store.Options { func (m *fileStore) Options() store.Options {
@ -321,14 +368,19 @@ func (m *fileStore) Options() store.Options {
} }
func (m *fileStore) List(opts ...store.ListOption) ([]string, error) { func (m *fileStore) List(opts ...store.ListOption) ([]string, error) {
listOptions := store.ListOptions{} var listOptions store.ListOptions
for _, o := range opts { for _, o := range opts {
o(&listOptions) o(&listOptions)
} }
fd, err := m.getDB(listOptions.Database, listOptions.Table)
if err != nil {
return nil, err
}
// TODO apply prefix/suffix in range query // TODO apply prefix/suffix in range query
allKeys := m.list(listOptions.Limit, listOptions.Offset) allKeys := m.list(fd, listOptions.Limit, listOptions.Offset)
if len(listOptions.Prefix) > 0 { if len(listOptions.Prefix) > 0 {
var prefixKeys []string var prefixKeys []string

View File

@ -2,12 +2,12 @@
package memory package memory
import ( import (
"path/filepath"
"sort" "sort"
"strings" "strings"
"time" "time"
"github.com/micro/go-micro/v2/store" "github.com/micro/go-micro/v2/store"
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -15,8 +15,11 @@ import (
// NewStore returns a memory store // NewStore returns a memory store
func NewStore(opts ...store.Option) store.Store { func NewStore(opts ...store.Option) store.Store {
s := &memoryStore{ s := &memoryStore{
options: store.Options{}, options: store.Options{
store: cache.New(cache.NoExpiration, 5*time.Minute), Database: "micro",
Table: "micro",
},
store: cache.New(cache.NoExpiration, 5*time.Minute),
} }
for _, o := range opts { for _, o := range opts {
o(&s.options) o(&s.options)
@ -30,6 +33,101 @@ type memoryStore struct {
store *cache.Cache store *cache.Cache
} }
type internalRecord struct {
key string
value []byte
expiresAt time.Time
}
func (m *memoryStore) key(prefix, key string) string {
return filepath.Join(prefix, key)
}
func (m *memoryStore) prefix(database, table string) string {
if len(database) == 0 {
database = m.options.Database
}
if len(table) == 0 {
table = m.options.Table
}
return filepath.Join(database, table)
}
func (m *memoryStore) get(prefix, key string) (*store.Record, error) {
key = m.key(prefix, key)
var storedRecord *internalRecord
r, found := m.store.Get(key)
if !found {
return nil, store.ErrNotFound
}
storedRecord, ok := r.(*internalRecord)
if !ok {
return nil, errors.New("Retrieved a non *internalRecord from the cache")
}
// Copy the record on the way out
newRecord := &store.Record{}
newRecord.Key = strings.TrimPrefix(storedRecord.key, prefix+"/")
newRecord.Value = make([]byte, len(storedRecord.value))
copy(newRecord.Value, storedRecord.value)
if !storedRecord.expiresAt.IsZero() {
newRecord.Expiry = time.Until(storedRecord.expiresAt)
}
return newRecord, nil
}
func (m *memoryStore) set(prefix string, r *store.Record) {
key := m.key(prefix, r.Key)
// copy the incoming record and then
// convert the expiry in to a hard timestamp
i := &internalRecord{}
i.key = r.Key
i.value = make([]byte, len(r.Value))
copy(i.value, r.Value)
if r.Expiry != 0 {
i.expiresAt = time.Now().Add(r.Expiry)
}
m.store.Set(key, i, r.Expiry)
}
func (m *memoryStore) delete(prefix, key string) {
key = m.key(prefix, key)
m.store.Delete(key)
}
func (m *memoryStore) list(prefix string, limit, offset uint) []string {
allItems := m.store.Items()
allKeys := make([]string, len(allItems))
i := 0
for k := range allItems {
if !strings.HasPrefix(k, prefix+"/") {
continue
}
allKeys[i] = strings.TrimPrefix(k, prefix+"/")
i++
}
if limit != 0 || offset != 0 {
sort.Slice(allKeys, func(i, j int) bool { return allKeys[i] < allKeys[j] })
min := func(i, j uint) uint {
if i < j {
return i
}
return j
}
return allKeys[offset:min(limit, uint(len(allKeys)))]
}
return allKeys
}
func (m *memoryStore) Close() error { func (m *memoryStore) Close() error {
m.store.Flush() m.store.Flush()
return nil return nil
@ -53,31 +151,33 @@ func (m *memoryStore) Read(key string, opts ...store.ReadOption) ([]*store.Recor
o(&readOpts) o(&readOpts)
} }
prefix := m.prefix(readOpts.Database, readOpts.Table)
var keys []string var keys []string
// Handle Prefix / suffix // Handle Prefix / suffix
if readOpts.Prefix || readOpts.Suffix { if readOpts.Prefix || readOpts.Suffix {
var opts []store.ListOption k := m.list(prefix, readOpts.Limit, readOpts.Offset)
if readOpts.Prefix {
opts = append(opts, store.ListPrefix(key)) for _, kk := range k {
if readOpts.Prefix && !strings.HasPrefix(kk, key) {
continue
}
if readOpts.Suffix && !strings.HasSuffix(kk, key) {
continue
}
keys = append(keys, kk)
} }
if readOpts.Suffix {
opts = append(opts, store.ListSuffix(key))
}
opts = append(opts, store.ListLimit(readOpts.Limit))
opts = append(opts, store.ListOffset(readOpts.Offset))
k, err := m.List(opts...)
if err != nil {
return nil, errors.Wrap(err, "Memory: Read couldn't List()")
}
keys = k
} else { } else {
keys = []string{key} keys = []string{key}
} }
var results []*store.Record var results []*store.Record
for _, k := range keys { for _, k := range keys {
r, err := m.get(k) r, err := m.get(prefix, k)
if err != nil { if err != nil {
return results, err return results, err
} }
@ -87,40 +187,14 @@ func (m *memoryStore) Read(key string, opts ...store.ReadOption) ([]*store.Recor
return results, nil return results, nil
} }
func (m *memoryStore) get(k string) (*store.Record, error) {
if len(m.options.Table) > 0 {
k = m.options.Table + "/" + k
}
if len(m.options.Database) > 0 {
k = m.options.Database + "/" + k
}
var storedRecord *internalRecord
r, found := m.store.Get(k)
if !found {
return nil, store.ErrNotFound
}
storedRecord, ok := r.(*internalRecord)
if !ok {
return nil, errors.New("Retrieved a non *internalRecord from the cache")
}
// Copy the record on the way out
newRecord := &store.Record{}
newRecord.Key = storedRecord.key
newRecord.Value = make([]byte, len(storedRecord.value))
copy(newRecord.Value, storedRecord.value)
if !storedRecord.expiresAt.IsZero() {
newRecord.Expiry = time.Until(storedRecord.expiresAt)
}
return newRecord, nil
}
func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error { func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error {
writeOpts := store.WriteOptions{} writeOpts := store.WriteOptions{}
for _, o := range opts { for _, o := range opts {
o(&writeOpts) o(&writeOpts)
} }
prefix := m.prefix(writeOpts.Database, writeOpts.Table)
if len(opts) > 0 { if len(opts) > 0 {
// Copy the record before applying options, or the incoming record will be mutated // Copy the record before applying options, or the incoming record will be mutated
newRecord := store.Record{} newRecord := store.Record{}
@ -135,52 +209,25 @@ func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error {
if writeOpts.TTL != 0 { if writeOpts.TTL != 0 {
newRecord.Expiry = writeOpts.TTL newRecord.Expiry = writeOpts.TTL
} }
m.set(&newRecord) m.set(prefix, &newRecord)
} else { return nil
m.set(r)
} }
// set
m.set(prefix, r)
return nil return nil
} }
func (m *memoryStore) set(r *store.Record) {
key := r.Key
if len(m.options.Table) > 0 {
key = m.options.Table + "/" + key
}
if len(m.options.Database) > 0 {
key = m.options.Database + "/" + key
}
// copy the incoming record and then
// convert the expiry in to a hard timestamp
i := &internalRecord{}
i.key = r.Key
i.value = make([]byte, len(r.Value))
copy(i.value, r.Value)
if r.Expiry != 0 {
i.expiresAt = time.Now().Add(r.Expiry)
}
m.store.Set(key, i, r.Expiry)
}
func (m *memoryStore) Delete(key string, opts ...store.DeleteOption) error { func (m *memoryStore) Delete(key string, opts ...store.DeleteOption) error {
deleteOptions := store.DeleteOptions{} deleteOptions := store.DeleteOptions{}
for _, o := range opts { for _, o := range opts {
o(&deleteOptions) o(&deleteOptions)
} }
m.delete(key)
return nil
}
func (m *memoryStore) delete(key string) { prefix := m.prefix(deleteOptions.Database, deleteOptions.Table)
if len(m.options.Table) > 0 { m.delete(prefix, key)
key = m.options.Table + "/" + key return nil
}
if len(m.options.Database) > 0 {
key = m.options.Database + "/" + key
}
m.store.Delete(key)
} }
func (m *memoryStore) Options() store.Options { func (m *memoryStore) Options() store.Options {
@ -193,59 +240,29 @@ func (m *memoryStore) List(opts ...store.ListOption) ([]string, error) {
for _, o := range opts { for _, o := range opts {
o(&listOptions) o(&listOptions)
} }
allKeys := m.list(listOptions.Limit, listOptions.Offset)
prefix := m.prefix(listOptions.Database, listOptions.Table)
keys := m.list(prefix, listOptions.Limit, listOptions.Offset)
if len(listOptions.Prefix) > 0 { if len(listOptions.Prefix) > 0 {
var prefixKeys []string var prefixKeys []string
for _, k := range allKeys { for _, k := range keys {
if strings.HasPrefix(k, listOptions.Prefix) { if strings.HasPrefix(k, listOptions.Prefix) {
prefixKeys = append(prefixKeys, k) prefixKeys = append(prefixKeys, k)
} }
} }
allKeys = prefixKeys keys = prefixKeys
} }
if len(listOptions.Suffix) > 0 { if len(listOptions.Suffix) > 0 {
var suffixKeys []string var suffixKeys []string
for _, k := range allKeys { for _, k := range keys {
if strings.HasSuffix(k, listOptions.Suffix) { if strings.HasSuffix(k, listOptions.Suffix) {
suffixKeys = append(suffixKeys, k) suffixKeys = append(suffixKeys, k)
} }
} }
allKeys = suffixKeys keys = suffixKeys
} }
return allKeys, nil return keys, nil
}
func (m *memoryStore) list(limit, offset uint) []string {
allItems := m.store.Items()
allKeys := make([]string, len(allItems))
i := 0
for k := range allItems {
if len(m.options.Database) > 0 {
k = strings.TrimPrefix(k, m.options.Database+"/")
}
if len(m.options.Table) > 0 {
k = strings.TrimPrefix(k, m.options.Table+"/")
}
allKeys[i] = k
i++
}
if limit != 0 || offset != 0 {
sort.Slice(allKeys, func(i, j int) bool { return allKeys[i] < allKeys[j] })
min := func(i, j uint) uint {
if i < j {
return i
}
return j
}
return allKeys[offset:min(limit, uint(len(allKeys)))]
}
return allKeys
}
type internalRecord struct {
key string
value []byte
expiresAt time.Time
} }

View File

@ -259,13 +259,13 @@ func basictest(s store.Store, t *testing.T) {
t.Error(err) t.Error(err)
} else { } else {
if len(results) != 5 { if len(results) != 5 {
t.Error("Expected 5 results, got ", len(results)) t.Fatal("Expected 5 results, got ", len(results))
} }
if results[0].Key != "a0" { if results[0].Key != "a0" {
t.Errorf("Expected a0, got %s", results[0].Key) t.Fatalf("Expected a0, got %s", results[0].Key)
} }
if results[4].Key != "a4" { if results[4].Key != "a4" {
t.Errorf("Expected a4, got %s", results[4].Key) t.Fatalf("Expected a4, got %s", results[4].Key)
} }
} }
if results, err := s.Read("a", store.ReadLimit(30), store.ReadOffset(5), store.ReadPrefix()); err != nil { if results, err := s.Read("a", store.ReadLimit(30), store.ReadOffset(5), store.ReadPrefix()); err != nil {

View File

@ -1,15 +1,11 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// source: store/service/proto/store.proto // source: github.com/micro/go-micro/store/service/proto/store.proto
package go_micro_store package go_micro_store
import ( import (
context "context"
fmt "fmt" fmt "fmt"
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
math "math" math "math"
) )
@ -40,7 +36,7 @@ func (m *Record) Reset() { *m = Record{} }
func (m *Record) String() string { return proto.CompactTextString(m) } func (m *Record) String() string { return proto.CompactTextString(m) }
func (*Record) ProtoMessage() {} func (*Record) ProtoMessage() {}
func (*Record) Descriptor() ([]byte, []int) { func (*Record) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{0} return fileDescriptor_42854049893ccb13, []int{0}
} }
func (m *Record) XXX_Unmarshal(b []byte) error { func (m *Record) XXX_Unmarshal(b []byte) error {
@ -83,10 +79,12 @@ func (m *Record) GetExpiry() int64 {
} }
type ReadOptions struct { type ReadOptions struct {
Prefix bool `protobuf:"varint,1,opt,name=prefix,proto3" json:"prefix,omitempty"` Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
Suffix bool `protobuf:"varint,2,opt,name=suffix,proto3" json:"suffix,omitempty"` Table string `protobuf:"bytes,2,opt,name=table,proto3" json:"table,omitempty"`
Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` Prefix bool `protobuf:"varint,3,opt,name=prefix,proto3" json:"prefix,omitempty"`
Offset uint64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` Suffix bool `protobuf:"varint,4,opt,name=suffix,proto3" json:"suffix,omitempty"`
Limit uint64 `protobuf:"varint,5,opt,name=limit,proto3" json:"limit,omitempty"`
Offset uint64 `protobuf:"varint,6,opt,name=offset,proto3" json:"offset,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -96,7 +94,7 @@ func (m *ReadOptions) Reset() { *m = ReadOptions{} }
func (m *ReadOptions) String() string { return proto.CompactTextString(m) } func (m *ReadOptions) String() string { return proto.CompactTextString(m) }
func (*ReadOptions) ProtoMessage() {} func (*ReadOptions) ProtoMessage() {}
func (*ReadOptions) Descriptor() ([]byte, []int) { func (*ReadOptions) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{1} return fileDescriptor_42854049893ccb13, []int{1}
} }
func (m *ReadOptions) XXX_Unmarshal(b []byte) error { func (m *ReadOptions) XXX_Unmarshal(b []byte) error {
@ -117,6 +115,20 @@ func (m *ReadOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_ReadOptions proto.InternalMessageInfo var xxx_messageInfo_ReadOptions proto.InternalMessageInfo
func (m *ReadOptions) GetDatabase() string {
if m != nil {
return m.Database
}
return ""
}
func (m *ReadOptions) GetTable() string {
if m != nil {
return m.Table
}
return ""
}
func (m *ReadOptions) GetPrefix() bool { func (m *ReadOptions) GetPrefix() bool {
if m != nil { if m != nil {
return m.Prefix return m.Prefix
@ -157,7 +169,7 @@ func (m *ReadRequest) Reset() { *m = ReadRequest{} }
func (m *ReadRequest) String() string { return proto.CompactTextString(m) } func (m *ReadRequest) String() string { return proto.CompactTextString(m) }
func (*ReadRequest) ProtoMessage() {} func (*ReadRequest) ProtoMessage() {}
func (*ReadRequest) Descriptor() ([]byte, []int) { func (*ReadRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{2} return fileDescriptor_42854049893ccb13, []int{2}
} }
func (m *ReadRequest) XXX_Unmarshal(b []byte) error { func (m *ReadRequest) XXX_Unmarshal(b []byte) error {
@ -203,7 +215,7 @@ func (m *ReadResponse) Reset() { *m = ReadResponse{} }
func (m *ReadResponse) String() string { return proto.CompactTextString(m) } func (m *ReadResponse) String() string { return proto.CompactTextString(m) }
func (*ReadResponse) ProtoMessage() {} func (*ReadResponse) ProtoMessage() {}
func (*ReadResponse) Descriptor() ([]byte, []int) { func (*ReadResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{3} return fileDescriptor_42854049893ccb13, []int{3}
} }
func (m *ReadResponse) XXX_Unmarshal(b []byte) error { func (m *ReadResponse) XXX_Unmarshal(b []byte) error {
@ -232,10 +244,12 @@ func (m *ReadResponse) GetRecords() []*Record {
} }
type WriteOptions struct { type WriteOptions struct {
Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
Table string `protobuf:"bytes,2,opt,name=table,proto3" json:"table,omitempty"`
// time.Time // time.Time
Expiry int64 `protobuf:"varint,1,opt,name=expiry,proto3" json:"expiry,omitempty"` Expiry int64 `protobuf:"varint,3,opt,name=expiry,proto3" json:"expiry,omitempty"`
// time.Duration // time.Duration
Ttl int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"` Ttl int64 `protobuf:"varint,4,opt,name=ttl,proto3" json:"ttl,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -245,7 +259,7 @@ func (m *WriteOptions) Reset() { *m = WriteOptions{} }
func (m *WriteOptions) String() string { return proto.CompactTextString(m) } func (m *WriteOptions) String() string { return proto.CompactTextString(m) }
func (*WriteOptions) ProtoMessage() {} func (*WriteOptions) ProtoMessage() {}
func (*WriteOptions) Descriptor() ([]byte, []int) { func (*WriteOptions) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{4} return fileDescriptor_42854049893ccb13, []int{4}
} }
func (m *WriteOptions) XXX_Unmarshal(b []byte) error { func (m *WriteOptions) XXX_Unmarshal(b []byte) error {
@ -266,6 +280,20 @@ func (m *WriteOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_WriteOptions proto.InternalMessageInfo var xxx_messageInfo_WriteOptions proto.InternalMessageInfo
func (m *WriteOptions) GetDatabase() string {
if m != nil {
return m.Database
}
return ""
}
func (m *WriteOptions) GetTable() string {
if m != nil {
return m.Table
}
return ""
}
func (m *WriteOptions) GetExpiry() int64 { func (m *WriteOptions) GetExpiry() int64 {
if m != nil { if m != nil {
return m.Expiry return m.Expiry
@ -292,7 +320,7 @@ func (m *WriteRequest) Reset() { *m = WriteRequest{} }
func (m *WriteRequest) String() string { return proto.CompactTextString(m) } func (m *WriteRequest) String() string { return proto.CompactTextString(m) }
func (*WriteRequest) ProtoMessage() {} func (*WriteRequest) ProtoMessage() {}
func (*WriteRequest) Descriptor() ([]byte, []int) { func (*WriteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{5} return fileDescriptor_42854049893ccb13, []int{5}
} }
func (m *WriteRequest) XXX_Unmarshal(b []byte) error { func (m *WriteRequest) XXX_Unmarshal(b []byte) error {
@ -337,7 +365,7 @@ func (m *WriteResponse) Reset() { *m = WriteResponse{} }
func (m *WriteResponse) String() string { return proto.CompactTextString(m) } func (m *WriteResponse) String() string { return proto.CompactTextString(m) }
func (*WriteResponse) ProtoMessage() {} func (*WriteResponse) ProtoMessage() {}
func (*WriteResponse) Descriptor() ([]byte, []int) { func (*WriteResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{6} return fileDescriptor_42854049893ccb13, []int{6}
} }
func (m *WriteResponse) XXX_Unmarshal(b []byte) error { func (m *WriteResponse) XXX_Unmarshal(b []byte) error {
@ -359,6 +387,8 @@ func (m *WriteResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_WriteResponse proto.InternalMessageInfo var xxx_messageInfo_WriteResponse proto.InternalMessageInfo
type DeleteOptions struct { type DeleteOptions struct {
Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
Table string `protobuf:"bytes,2,opt,name=table,proto3" json:"table,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -368,7 +398,7 @@ func (m *DeleteOptions) Reset() { *m = DeleteOptions{} }
func (m *DeleteOptions) String() string { return proto.CompactTextString(m) } func (m *DeleteOptions) String() string { return proto.CompactTextString(m) }
func (*DeleteOptions) ProtoMessage() {} func (*DeleteOptions) ProtoMessage() {}
func (*DeleteOptions) Descriptor() ([]byte, []int) { func (*DeleteOptions) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{7} return fileDescriptor_42854049893ccb13, []int{7}
} }
func (m *DeleteOptions) XXX_Unmarshal(b []byte) error { func (m *DeleteOptions) XXX_Unmarshal(b []byte) error {
@ -389,6 +419,20 @@ func (m *DeleteOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_DeleteOptions proto.InternalMessageInfo var xxx_messageInfo_DeleteOptions proto.InternalMessageInfo
func (m *DeleteOptions) GetDatabase() string {
if m != nil {
return m.Database
}
return ""
}
func (m *DeleteOptions) GetTable() string {
if m != nil {
return m.Table
}
return ""
}
type DeleteRequest struct { type DeleteRequest struct {
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Options *DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` Options *DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
@ -401,7 +445,7 @@ func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
func (m *DeleteRequest) String() string { return proto.CompactTextString(m) } func (m *DeleteRequest) String() string { return proto.CompactTextString(m) }
func (*DeleteRequest) ProtoMessage() {} func (*DeleteRequest) ProtoMessage() {}
func (*DeleteRequest) Descriptor() ([]byte, []int) { func (*DeleteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{8} return fileDescriptor_42854049893ccb13, []int{8}
} }
func (m *DeleteRequest) XXX_Unmarshal(b []byte) error { func (m *DeleteRequest) XXX_Unmarshal(b []byte) error {
@ -446,7 +490,7 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} }
func (m *DeleteResponse) String() string { return proto.CompactTextString(m) } func (m *DeleteResponse) String() string { return proto.CompactTextString(m) }
func (*DeleteResponse) ProtoMessage() {} func (*DeleteResponse) ProtoMessage() {}
func (*DeleteResponse) Descriptor() ([]byte, []int) { func (*DeleteResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{9} return fileDescriptor_42854049893ccb13, []int{9}
} }
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error { func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
@ -468,10 +512,12 @@ func (m *DeleteResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo
type ListOptions struct { type ListOptions struct {
Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
Suffix string `protobuf:"bytes,2,opt,name=suffix,proto3" json:"suffix,omitempty"` Table string `protobuf:"bytes,2,opt,name=table,proto3" json:"table,omitempty"`
Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` Prefix string `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix,omitempty"`
Offset uint64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"` Suffix string `protobuf:"bytes,4,opt,name=suffix,proto3" json:"suffix,omitempty"`
Limit uint64 `protobuf:"varint,5,opt,name=limit,proto3" json:"limit,omitempty"`
Offset uint64 `protobuf:"varint,6,opt,name=offset,proto3" json:"offset,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -481,7 +527,7 @@ func (m *ListOptions) Reset() { *m = ListOptions{} }
func (m *ListOptions) String() string { return proto.CompactTextString(m) } func (m *ListOptions) String() string { return proto.CompactTextString(m) }
func (*ListOptions) ProtoMessage() {} func (*ListOptions) ProtoMessage() {}
func (*ListOptions) Descriptor() ([]byte, []int) { func (*ListOptions) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{10} return fileDescriptor_42854049893ccb13, []int{10}
} }
func (m *ListOptions) XXX_Unmarshal(b []byte) error { func (m *ListOptions) XXX_Unmarshal(b []byte) error {
@ -502,6 +548,20 @@ func (m *ListOptions) XXX_DiscardUnknown() {
var xxx_messageInfo_ListOptions proto.InternalMessageInfo var xxx_messageInfo_ListOptions proto.InternalMessageInfo
func (m *ListOptions) GetDatabase() string {
if m != nil {
return m.Database
}
return ""
}
func (m *ListOptions) GetTable() string {
if m != nil {
return m.Table
}
return ""
}
func (m *ListOptions) GetPrefix() string { func (m *ListOptions) GetPrefix() string {
if m != nil { if m != nil {
return m.Prefix return m.Prefix
@ -541,7 +601,7 @@ func (m *ListRequest) Reset() { *m = ListRequest{} }
func (m *ListRequest) String() string { return proto.CompactTextString(m) } func (m *ListRequest) String() string { return proto.CompactTextString(m) }
func (*ListRequest) ProtoMessage() {} func (*ListRequest) ProtoMessage() {}
func (*ListRequest) Descriptor() ([]byte, []int) { func (*ListRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{11} return fileDescriptor_42854049893ccb13, []int{11}
} }
func (m *ListRequest) XXX_Unmarshal(b []byte) error { func (m *ListRequest) XXX_Unmarshal(b []byte) error {
@ -580,7 +640,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} }
func (m *ListResponse) String() string { return proto.CompactTextString(m) } func (m *ListResponse) String() string { return proto.CompactTextString(m) }
func (*ListResponse) ProtoMessage() {} func (*ListResponse) ProtoMessage() {}
func (*ListResponse) Descriptor() ([]byte, []int) { func (*ListResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{12} return fileDescriptor_42854049893ccb13, []int{12}
} }
func (m *ListResponse) XXX_Unmarshal(b []byte) error { func (m *ListResponse) XXX_Unmarshal(b []byte) error {
@ -618,7 +678,7 @@ func (m *DatabasesRequest) Reset() { *m = DatabasesRequest{} }
func (m *DatabasesRequest) String() string { return proto.CompactTextString(m) } func (m *DatabasesRequest) String() string { return proto.CompactTextString(m) }
func (*DatabasesRequest) ProtoMessage() {} func (*DatabasesRequest) ProtoMessage() {}
func (*DatabasesRequest) Descriptor() ([]byte, []int) { func (*DatabasesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{13} return fileDescriptor_42854049893ccb13, []int{13}
} }
func (m *DatabasesRequest) XXX_Unmarshal(b []byte) error { func (m *DatabasesRequest) XXX_Unmarshal(b []byte) error {
@ -650,7 +710,7 @@ func (m *DatabasesResponse) Reset() { *m = DatabasesResponse{} }
func (m *DatabasesResponse) String() string { return proto.CompactTextString(m) } func (m *DatabasesResponse) String() string { return proto.CompactTextString(m) }
func (*DatabasesResponse) ProtoMessage() {} func (*DatabasesResponse) ProtoMessage() {}
func (*DatabasesResponse) Descriptor() ([]byte, []int) { func (*DatabasesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{14} return fileDescriptor_42854049893ccb13, []int{14}
} }
func (m *DatabasesResponse) XXX_Unmarshal(b []byte) error { func (m *DatabasesResponse) XXX_Unmarshal(b []byte) error {
@ -689,7 +749,7 @@ func (m *TablesRequest) Reset() { *m = TablesRequest{} }
func (m *TablesRequest) String() string { return proto.CompactTextString(m) } func (m *TablesRequest) String() string { return proto.CompactTextString(m) }
func (*TablesRequest) ProtoMessage() {} func (*TablesRequest) ProtoMessage() {}
func (*TablesRequest) Descriptor() ([]byte, []int) { func (*TablesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{15} return fileDescriptor_42854049893ccb13, []int{15}
} }
func (m *TablesRequest) XXX_Unmarshal(b []byte) error { func (m *TablesRequest) XXX_Unmarshal(b []byte) error {
@ -728,7 +788,7 @@ func (m *TablesResponse) Reset() { *m = TablesResponse{} }
func (m *TablesResponse) String() string { return proto.CompactTextString(m) } func (m *TablesResponse) String() string { return proto.CompactTextString(m) }
func (*TablesResponse) ProtoMessage() {} func (*TablesResponse) ProtoMessage() {}
func (*TablesResponse) Descriptor() ([]byte, []int) { func (*TablesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_1ba364858f5c3cdb, []int{16} return fileDescriptor_42854049893ccb13, []int{16}
} }
func (m *TablesResponse) XXX_Unmarshal(b []byte) error { func (m *TablesResponse) XXX_Unmarshal(b []byte) error {
@ -776,332 +836,48 @@ func init() {
proto.RegisterType((*TablesResponse)(nil), "go.micro.store.TablesResponse") proto.RegisterType((*TablesResponse)(nil), "go.micro.store.TablesResponse")
} }
func init() { proto.RegisterFile("store/service/proto/store.proto", fileDescriptor_1ba364858f5c3cdb) } func init() {
proto.RegisterFile("github.com/micro/go-micro/store/service/proto/store.proto", fileDescriptor_42854049893ccb13)
var fileDescriptor_1ba364858f5c3cdb = []byte{
// 563 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x5d, 0x8f, 0xd2, 0x40,
0x14, 0xa5, 0xb4, 0x74, 0xe9, 0x85, 0x45, 0x9c, 0x18, 0x42, 0x90, 0x55, 0x9c, 0xa7, 0x26, 0x26,
0x65, 0xc5, 0xf8, 0xf1, 0x68, 0x22, 0x1a, 0x35, 0x26, 0x26, 0xa3, 0xd1, 0xc4, 0xb7, 0x02, 0x83,
0x69, 0x60, 0x77, 0x6a, 0x67, 0x20, 0xcb, 0x0f, 0xf4, 0x7f, 0x99, 0xf9, 0x2a, 0xa5, 0xb4, 0x3e,
0xf8, 0x36, 0xf7, 0xcc, 0x9d, 0x73, 0xee, 0xb9, 0xf7, 0xb6, 0xf0, 0x98, 0x0b, 0x96, 0xd1, 0x29,
0xa7, 0xd9, 0x3e, 0x59, 0xd2, 0x69, 0x9a, 0x31, 0xc1, 0xa6, 0x0a, 0x8b, 0xd4, 0x19, 0xf5, 0x7e,
0xb1, 0xe8, 0x26, 0x59, 0x66, 0x2c, 0x52, 0x28, 0xfe, 0x00, 0x3e, 0xa1, 0x4b, 0x96, 0xad, 0x50,
0x1f, 0xdc, 0x0d, 0x3d, 0x0c, 0x9d, 0x89, 0x13, 0x06, 0x44, 0x1e, 0xd1, 0x03, 0x68, 0xed, 0xe3,
0xed, 0x8e, 0x0e, 0x9b, 0x13, 0x27, 0xec, 0x12, 0x1d, 0xa0, 0x01, 0xf8, 0xf4, 0x2e, 0x4d, 0xb2,
0xc3, 0xd0, 0x9d, 0x38, 0xa1, 0x4b, 0x4c, 0x84, 0x37, 0xd0, 0x21, 0x34, 0x5e, 0x7d, 0x49, 0x45,
0xc2, 0x6e, 0xb9, 0x4c, 0x4b, 0x33, 0xba, 0x4e, 0xee, 0x14, 0x63, 0x9b, 0x98, 0x48, 0xe2, 0x7c,
0xb7, 0x96, 0x78, 0x53, 0xe3, 0x3a, 0x92, 0x62, 0xdb, 0xe4, 0x26, 0x11, 0x8a, 0xd5, 0x23, 0x3a,
0x90, 0xd9, 0x6c, 0xbd, 0xe6, 0x54, 0x0c, 0x3d, 0x05, 0x9b, 0x08, 0x7f, 0xd7, 0x62, 0x84, 0xfe,
0xde, 0x51, 0x2e, 0x2a, 0x6a, 0x7f, 0x01, 0x17, 0x4c, 0x57, 0xa2, 0x74, 0x3a, 0xb3, 0x87, 0xd1,
0xa9, 0xf3, 0xa8, 0x50, 0x2c, 0xb1, 0xb9, 0xf8, 0x0d, 0x74, 0x35, 0x2f, 0x4f, 0xd9, 0x2d, 0xa7,
0xe8, 0x1a, 0x2e, 0x32, 0xd5, 0x1e, 0x3e, 0x74, 0x26, 0x6e, 0xd8, 0x99, 0x0d, 0xce, 0x69, 0xe4,
0x35, 0xb1, 0x69, 0xf8, 0x35, 0x74, 0x7f, 0x64, 0x89, 0xa0, 0x85, 0x3e, 0x98, 0x76, 0x39, 0xc5,
0x76, 0xc9, 0x92, 0x85, 0xd8, 0xaa, 0xe2, 0x5c, 0x22, 0x8f, 0x78, 0x6f, 0x5e, 0x5a, 0x53, 0x11,
0xf8, 0x9a, 0x54, 0xbd, 0xac, 0x97, 0x36, 0x59, 0xe8, 0x65, 0xd9, 0xf2, 0xb8, 0xfc, 0xa0, 0x58,
0xd8, 0xd1, 0xf3, 0x3d, 0xb8, 0x34, 0xba, 0xda, 0xb4, 0x04, 0xe6, 0x74, 0x4b, 0xf3, 0x54, 0xfc,
0xd3, 0x02, 0xf5, 0xfd, 0x7e, 0x55, 0x16, 0xbf, 0x2a, 0x8b, 0x9f, 0x50, 0x1e, 0xd5, 0xfb, 0xd0,
0xb3, 0xdc, 0x46, 0x7e, 0x03, 0x9d, 0xcf, 0x09, 0x17, 0xd5, 0x8b, 0x14, 0xd4, 0x2c, 0x52, 0xf0,
0x9f, 0x8b, 0x34, 0xd7, 0x62, 0xd6, 0x58, 0x61, 0x6d, 0x9c, 0xea, 0xb5, 0x29, 0x94, 0x76, 0x34,
0x11, 0x42, 0x57, 0xb3, 0x98, 0xb5, 0x41, 0xe0, 0x6d, 0xe8, 0x41, 0xb6, 0xc2, 0x0d, 0x03, 0xa2,
0xce, 0x9f, 0xbc, 0xb6, 0xd3, 0x6f, 0x62, 0x04, 0xfd, 0x79, 0x2c, 0xe2, 0x45, 0xcc, 0x29, 0x37,
0xa2, 0xf8, 0x19, 0xdc, 0x2f, 0x60, 0x86, 0x62, 0x0c, 0xc1, 0xca, 0x82, 0x6a, 0xf7, 0x02, 0x72,
0x04, 0xf0, 0x53, 0xb8, 0xfc, 0x16, 0x2f, 0xb6, 0x39, 0x07, 0x1a, 0x41, 0xdb, 0xde, 0x9a, 0x3e,
0xe5, 0x31, 0x0e, 0xa1, 0x67, 0x93, 0x0d, 0xf9, 0x00, 0x7c, 0xa1, 0x10, 0xc3, 0x6c, 0xa2, 0xd9,
0x1f, 0x17, 0x5a, 0x5f, 0xa5, 0x4d, 0xf4, 0x16, 0x3c, 0xf9, 0x21, 0xa0, 0xca, 0xcf, 0xc6, 0x88,
0x8e, 0xc6, 0xd5, 0x97, 0x66, 0x8e, 0x0d, 0xf4, 0x1e, 0x5a, 0x6a, 0xb3, 0x50, 0xf5, 0x26, 0x5a,
0x9a, 0xab, 0x9a, 0xdb, 0x9c, 0xe7, 0x23, 0xf8, 0x7a, 0x47, 0x50, 0xcd, 0x56, 0x59, 0xa6, 0x47,
0x75, 0xd7, 0x39, 0xd5, 0x3b, 0xf0, 0xe4, 0xa4, 0x50, 0xe5, 0x5c, 0x6b, 0x7d, 0x15, 0x87, 0x8b,
0x1b, 0xd7, 0x0e, 0x22, 0x10, 0xe4, 0x23, 0x43, 0x93, 0x33, 0xd5, 0xd2, 0x84, 0x47, 0x4f, 0xfe,
0x91, 0x51, 0x74, 0xa9, 0xc7, 0x74, 0xee, 0xf2, 0x64, 0xd6, 0xe7, 0x2e, 0x4f, 0xa7, 0x8b, 0x1b,
0x0b, 0x5f, 0xfd, 0xec, 0x9f, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x04, 0x5f, 0x7c, 0x0f,
0x06, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. var fileDescriptor_42854049893ccb13 = []byte{
var _ context.Context // 598 bytes of a gzipped FileDescriptorProto
var _ grpc.ClientConn 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xdd, 0x8e, 0xd2, 0x40,
0x14, 0xa6, 0xdb, 0xd2, 0xa5, 0x87, 0x1f, 0x71, 0x62, 0x48, 0x83, 0xac, 0xa9, 0x73, 0xd5, 0xc4,
// This is a compile-time assertion to ensure that this generated file 0x58, 0x56, 0x8c, 0x1a, 0xef, 0x34, 0xa2, 0x51, 0x63, 0x62, 0x32, 0x1a, 0x4d, 0xbc, 0x2b, 0x30,
// is compatible with the grpc package it is being compiled against. 0x60, 0x5d, 0xd8, 0x62, 0x67, 0x20, 0xcb, 0xc3, 0xf8, 0x38, 0xbe, 0x97, 0x99, 0x3f, 0x28, 0xd0,
const _ = grpc.SupportPackageIsVersion4 0xee, 0x85, 0xbb, 0x77, 0x73, 0xce, 0x1c, 0xbe, 0x39, 0xdf, 0x4f, 0x03, 0xbc, 0x9c, 0x25, 0xfc,
0xe7, 0x6a, 0x14, 0x8d, 0xd3, 0x45, 0x7f, 0x91, 0x8c, 0xb3, 0xb4, 0x3f, 0x4b, 0x1f, 0xab, 0x03,
// StoreClient is the client API for Store service. 0xe3, 0x69, 0x46, 0xfb, 0x8c, 0x66, 0xeb, 0x64, 0x4c, 0xfb, 0xcb, 0x2c, 0xe5, 0xba, 0x17, 0xc9,
// 0x33, 0x6a, 0xcd, 0xd2, 0x48, 0x4e, 0x46, 0xb2, 0x8b, 0xdf, 0x83, 0x4b, 0xe8, 0x38, 0xcd, 0x26,
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. 0xa8, 0x0d, 0xf6, 0x05, 0xdd, 0xf8, 0x56, 0x60, 0x85, 0x1e, 0x11, 0x47, 0x74, 0x0f, 0xaa, 0xeb,
type StoreClient interface { 0x78, 0xbe, 0xa2, 0xfe, 0x49, 0x60, 0x85, 0x0d, 0xa2, 0x0a, 0xd4, 0x01, 0x97, 0x5e, 0x2d, 0x93,
Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error) 0x6c, 0xe3, 0xdb, 0x81, 0x15, 0xda, 0x44, 0x57, 0xf8, 0x8f, 0x05, 0x75, 0x42, 0xe3, 0xc9, 0xe7,
Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error) 0x25, 0x4f, 0xd2, 0x4b, 0x86, 0xba, 0x50, 0x9b, 0xc4, 0x3c, 0x1e, 0xc5, 0x8c, 0x6a, 0xd0, 0x6d,
Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) 0x2d, 0x90, 0x79, 0x3c, 0x9a, 0x2b, 0x64, 0x8f, 0xa8, 0x42, 0x20, 0x2f, 0x33, 0x3a, 0x4d, 0xae,
List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (Store_ListClient, error) 0x24, 0x72, 0x8d, 0xe8, 0x4a, 0xf4, 0xd9, 0x6a, 0x2a, 0xfa, 0x8e, 0xea, 0xab, 0x4a, 0xa0, 0xcc,
Databases(ctx context.Context, in *DatabasesRequest, opts ...grpc.CallOption) (*DatabasesResponse, error) 0x93, 0x45, 0xc2, 0xfd, 0x6a, 0x60, 0x85, 0x0e, 0x51, 0x85, 0x98, 0x4e, 0xa7, 0x53, 0x46, 0xb9,
Tables(ctx context.Context, in *TablesRequest, opts ...grpc.CallOption) (*TablesResponse, error) 0xef, 0xca, 0xb6, 0xae, 0xf0, 0x37, 0xb5, 0x1e, 0xa1, 0xbf, 0x57, 0x94, 0xf1, 0x02, 0xba, 0xcf,
} 0xe0, 0x34, 0x55, 0xbb, 0xcb, 0xb5, 0xea, 0x83, 0xfb, 0xd1, 0xbe, 0x58, 0x51, 0x8e, 0x1e, 0x31,
0xb3, 0xf8, 0x15, 0x34, 0x14, 0x2e, 0x5b, 0xa6, 0x97, 0x8c, 0xa2, 0x73, 0x38, 0xcd, 0xa4, 0xa2,
type storeClient struct { 0xcc, 0xb7, 0x02, 0x3b, 0xac, 0x0f, 0x3a, 0xc7, 0x30, 0xe2, 0x9a, 0x98, 0x31, 0xfc, 0x0b, 0x1a,
cc *grpc.ClientConn 0xdf, 0xb3, 0x84, 0xd3, 0x1b, 0x29, 0x57, 0xe4, 0x89, 0x20, 0xc9, 0xf9, 0x5c, 0xca, 0x66, 0x13,
} 0x71, 0xc4, 0x6b, 0xfd, 0x96, 0x91, 0x21, 0x02, 0x57, 0xad, 0x21, 0x5f, 0x2a, 0x5f, 0x56, 0x4f,
0xa1, 0xe7, 0x87, 0x22, 0xf5, 0x0e, 0x7f, 0x90, 0xa7, 0xb2, 0x53, 0xe9, 0x0e, 0x34, 0xf5, 0xbb,
func NewStoreClient(cc *grpc.ClientConn) StoreClient { 0x4a, 0x26, 0xfc, 0x1a, 0x9a, 0x43, 0x3a, 0xa7, 0x37, 0x60, 0x8d, 0x7f, 0x18, 0x88, 0x72, 0x4f,
return &storeClient{cc} 0x5f, 0x1c, 0xae, 0x7b, 0x76, 0xb8, 0xee, 0xde, 0x12, 0xbb, 0x7d, 0xdb, 0xd0, 0x32, 0xd8, 0x7a,
} 0x61, 0x91, 0xef, 0x4f, 0x09, 0xe3, 0xb7, 0x95, 0x6f, 0xaf, 0x24, 0xdf, 0xde, 0x7f, 0xe6, 0x7b,
0xa8, 0xd6, 0x33, 0x5a, 0xe4, 0xd2, 0x6c, 0x15, 0xa7, 0x39, 0x47, 0x66, 0xc7, 0x3b, 0x84, 0x86,
func (c *storeClient) Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error) { 0x42, 0xd1, 0x69, 0x46, 0xe0, 0x5c, 0xd0, 0x8d, 0x50, 0xcf, 0x0e, 0x3d, 0x22, 0xcf, 0x1f, 0x9d,
out := new(ReadResponse) 0x9a, 0xd5, 0x3e, 0xc1, 0x08, 0xda, 0x43, 0xcd, 0x97, 0xe9, 0x47, 0xf1, 0x13, 0xb8, 0x9b, 0xeb,
err := c.cc.Invoke(ctx, "/go.micro.store.Store/Read", in, out, opts...) 0x69, 0x88, 0x1e, 0x78, 0x46, 0x18, 0xf5, 0x49, 0x78, 0x64, 0xd7, 0xc0, 0x8f, 0xa0, 0xf9, 0x55,
if err != nil { 0xa8, 0x63, 0x30, 0xae, 0xd3, 0x15, 0x87, 0xd0, 0x32, 0xc3, 0x1a, 0xbc, 0x03, 0xae, 0x14, 0xd7,
return nil, err 0x20, 0xeb, 0x6a, 0xf0, 0xd7, 0x86, 0xea, 0x17, 0x41, 0x13, 0xbd, 0x01, 0x47, 0x7c, 0x9f, 0xa8,
} 0xf0, 0x6b, 0xd6, 0x8f, 0x76, 0x7b, 0xc5, 0x97, 0xda, 0xfa, 0x0a, 0x7a, 0x07, 0x55, 0x19, 0x5f,
return out, nil 0x54, 0x1c, 0x77, 0x03, 0x73, 0x56, 0x72, 0xbb, 0xc5, 0xf9, 0x00, 0xae, 0x8a, 0x15, 0x2a, 0x09,
} 0xa2, 0x41, 0x7a, 0x50, 0x76, 0xbd, 0x85, 0x7a, 0x0b, 0x8e, 0x70, 0x0a, 0x15, 0xfa, 0x5a, 0xca,
0x2b, 0x6f, 0x2e, 0xae, 0x9c, 0x5b, 0x88, 0x80, 0xb7, 0xb5, 0x0c, 0x05, 0x47, 0xaf, 0x1e, 0x38,
func (c *storeClient) Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error) { 0xdc, 0x7d, 0x78, 0xcd, 0x44, 0x9e, 0xa5, 0xb2, 0xe9, 0x98, 0xe5, 0x9e, 0xd7, 0xc7, 0x2c, 0xf7,
out := new(WriteResponse) 0xdd, 0xc5, 0x95, 0x91, 0x2b, 0xff, 0xb6, 0x9e, 0xfe, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xab, 0xcb,
err := c.cc.Invoke(ctx, "/go.micro.store.Store/Write", in, out, opts...) 0x6e, 0xac, 0xf3, 0x06, 0x00, 0x00,
if err != nil {
return nil, err
}
return out, nil
}
func (c *storeClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) {
out := new(DeleteResponse)
err := c.cc.Invoke(ctx, "/go.micro.store.Store/Delete", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storeClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (Store_ListClient, error) {
stream, err := c.cc.NewStream(ctx, &_Store_serviceDesc.Streams[0], "/go.micro.store.Store/List", opts...)
if err != nil {
return nil, err
}
x := &storeListClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Store_ListClient interface {
Recv() (*ListResponse, error)
grpc.ClientStream
}
type storeListClient struct {
grpc.ClientStream
}
func (x *storeListClient) Recv() (*ListResponse, error) {
m := new(ListResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *storeClient) Databases(ctx context.Context, in *DatabasesRequest, opts ...grpc.CallOption) (*DatabasesResponse, error) {
out := new(DatabasesResponse)
err := c.cc.Invoke(ctx, "/go.micro.store.Store/Databases", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storeClient) Tables(ctx context.Context, in *TablesRequest, opts ...grpc.CallOption) (*TablesResponse, error) {
out := new(TablesResponse)
err := c.cc.Invoke(ctx, "/go.micro.store.Store/Tables", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// StoreServer is the server API for Store service.
type StoreServer interface {
Read(context.Context, *ReadRequest) (*ReadResponse, error)
Write(context.Context, *WriteRequest) (*WriteResponse, error)
Delete(context.Context, *DeleteRequest) (*DeleteResponse, error)
List(*ListRequest, Store_ListServer) error
Databases(context.Context, *DatabasesRequest) (*DatabasesResponse, error)
Tables(context.Context, *TablesRequest) (*TablesResponse, error)
}
// UnimplementedStoreServer can be embedded to have forward compatible implementations.
type UnimplementedStoreServer struct {
}
func (*UnimplementedStoreServer) Read(ctx context.Context, req *ReadRequest) (*ReadResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Read not implemented")
}
func (*UnimplementedStoreServer) Write(ctx context.Context, req *WriteRequest) (*WriteResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Write not implemented")
}
func (*UnimplementedStoreServer) Delete(ctx context.Context, req *DeleteRequest) (*DeleteResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
}
func (*UnimplementedStoreServer) List(req *ListRequest, srv Store_ListServer) error {
return status.Errorf(codes.Unimplemented, "method List not implemented")
}
func (*UnimplementedStoreServer) Databases(ctx context.Context, req *DatabasesRequest) (*DatabasesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Databases not implemented")
}
func (*UnimplementedStoreServer) Tables(ctx context.Context, req *TablesRequest) (*TablesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Tables not implemented")
}
func RegisterStoreServer(s *grpc.Server, srv StoreServer) {
s.RegisterService(&_Store_serviceDesc, srv)
}
func _Store_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StoreServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/go.micro.store.Store/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StoreServer).Read(ctx, req.(*ReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Store_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(WriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StoreServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/go.micro.store.Store/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StoreServer).Write(ctx, req.(*WriteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Store_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StoreServer).Delete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/go.micro.store.Store/Delete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StoreServer).Delete(ctx, req.(*DeleteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Store_List_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(ListRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(StoreServer).List(m, &storeListServer{stream})
}
type Store_ListServer interface {
Send(*ListResponse) error
grpc.ServerStream
}
type storeListServer struct {
grpc.ServerStream
}
func (x *storeListServer) Send(m *ListResponse) error {
return x.ServerStream.SendMsg(m)
}
func _Store_Databases_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DatabasesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StoreServer).Databases(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/go.micro.store.Store/Databases",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StoreServer).Databases(ctx, req.(*DatabasesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Store_Tables_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(TablesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StoreServer).Tables(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/go.micro.store.Store/Tables",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StoreServer).Tables(ctx, req.(*TablesRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Store_serviceDesc = grpc.ServiceDesc{
ServiceName: "go.micro.store.Store",
HandlerType: (*StoreServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Read",
Handler: _Store_Read_Handler,
},
{
MethodName: "Write",
Handler: _Store_Write_Handler,
},
{
MethodName: "Delete",
Handler: _Store_Delete_Handler,
},
{
MethodName: "Databases",
Handler: _Store_Databases_Handler,
},
{
MethodName: "Tables",
Handler: _Store_Tables_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "List",
Handler: _Store_List_Handler,
ServerStreams: true,
},
},
Metadata: "store/service/proto/store.proto",
} }

View File

@ -1,5 +1,5 @@
// Code generated by protoc-gen-micro. DO NOT EDIT. // Code generated by protoc-gen-micro. DO NOT EDIT.
// source: store/service/proto/store.proto // source: github.com/micro/go-micro/store/service/proto/store.proto
package go_micro_store package go_micro_store

View File

@ -21,10 +21,12 @@ message Record {
} }
message ReadOptions { message ReadOptions {
bool prefix = 1; string database = 1;
bool suffix = 2; string table = 2;
uint64 limit = 3; bool prefix = 3;
uint64 offset = 4; bool suffix = 4;
uint64 limit = 5;
uint64 offset = 6;
} }
message ReadRequest { message ReadRequest {
@ -37,10 +39,12 @@ message ReadResponse {
} }
message WriteOptions { message WriteOptions {
string database = 1;
string table = 2;
// time.Time // time.Time
int64 expiry = 1; int64 expiry = 3;
// time.Duration // time.Duration
int64 ttl = 2; int64 ttl = 4;
} }
message WriteRequest { message WriteRequest {
@ -50,7 +54,10 @@ message WriteRequest {
message WriteResponse {} message WriteResponse {}
message DeleteOptions {} message DeleteOptions {
string database = 1;
string table = 2;
}
message DeleteRequest { message DeleteRequest {
string key = 1; string key = 1;
@ -60,12 +67,15 @@ message DeleteRequest {
message DeleteResponse {} message DeleteResponse {}
message ListOptions { message ListOptions {
string prefix = 1; string database = 1;
string suffix = 2; string table = 2;
uint64 limit = 3; string prefix = 3;
uint64 offset = 4; string suffix = 4;
uint64 limit = 5;
uint64 offset = 6;
} }
message ListRequest { message ListRequest {
ListOptions options = 1; ListOptions options = 1;
} }

View File

@ -46,23 +46,27 @@ func (s *serviceStore) Init(opts ...store.Option) error {
func (s *serviceStore) Context() context.Context { func (s *serviceStore) Context() context.Context {
ctx := context.Background() ctx := context.Background()
md := make(metadata.Metadata) md := make(metadata.Metadata)
if len(s.Database) > 0 {
md["Micro-Database"] = s.Database
}
if len(s.Table) > 0 {
md["Micro-Table"] = s.Table
}
return metadata.NewContext(ctx, md) return metadata.NewContext(ctx, md)
} }
// Sync all the known records // Sync all the known records
func (s *serviceStore) List(opts ...store.ListOption) ([]string, error) { func (s *serviceStore) List(opts ...store.ListOption) ([]string, error) {
stream, err := s.Client.List(s.Context(), &pb.ListRequest{}, client.WithAddress(s.Nodes...)) var options store.ListOptions
for _, o := range opts {
o(&options)
}
listOpts := &pb.ListOptions{
Database: options.Database,
Table: options.Table,
Prefix: options.Prefix,
Suffix: options.Suffix,
Limit: uint64(options.Limit),
Offset: uint64(options.Offset),
}
stream, err := s.Client.List(s.Context(), &pb.ListRequest{Options: listOpts}, client.WithAddress(s.Nodes...))
if err != nil && errors.Equal(err, errors.NotFound("", "")) { if err != nil && errors.Equal(err, errors.NotFound("", "")) {
return nil, store.ErrNotFound return nil, store.ErrNotFound
} else if err != nil { } else if err != nil {
@ -96,11 +100,18 @@ func (s *serviceStore) Read(key string, opts ...store.ReadOption) ([]*store.Reco
o(&options) o(&options)
} }
readOpts := &pb.ReadOptions{
Database: options.Database,
Table: options.Table,
Prefix: options.Prefix,
Suffix: options.Suffix,
Limit: uint64(options.Limit),
Offset: uint64(options.Offset),
}
rsp, err := s.Client.Read(s.Context(), &pb.ReadRequest{ rsp, err := s.Client.Read(s.Context(), &pb.ReadRequest{
Key: key, Key: key,
Options: &pb.ReadOptions{ Options: readOpts,
Prefix: options.Prefix,
},
}, client.WithAddress(s.Nodes...)) }, client.WithAddress(s.Nodes...))
if err != nil && errors.Equal(err, errors.NotFound("", "")) { if err != nil && errors.Equal(err, errors.NotFound("", "")) {
return nil, store.ErrNotFound return nil, store.ErrNotFound
@ -123,13 +134,23 @@ func (s *serviceStore) Read(key string, opts ...store.ReadOption) ([]*store.Reco
// Write a record // Write a record
func (s *serviceStore) Write(record *store.Record, opts ...store.WriteOption) error { func (s *serviceStore) Write(record *store.Record, opts ...store.WriteOption) error {
var options store.WriteOptions
for _, o := range opts {
o(&options)
}
writeOpts := &pb.WriteOptions{
Database: options.Database,
Table: options.Table,
}
_, err := s.Client.Write(s.Context(), &pb.WriteRequest{ _, err := s.Client.Write(s.Context(), &pb.WriteRequest{
Record: &pb.Record{ Record: &pb.Record{
Key: record.Key, Key: record.Key,
Value: record.Value, Value: record.Value,
Expiry: int64(record.Expiry.Seconds()), Expiry: int64(record.Expiry.Seconds()),
}, },
}, client.WithAddress(s.Nodes...)) Options: writeOpts}, client.WithAddress(s.Nodes...))
if err != nil && errors.Equal(err, errors.NotFound("", "")) { if err != nil && errors.Equal(err, errors.NotFound("", "")) {
return store.ErrNotFound return store.ErrNotFound
} }
@ -139,8 +160,19 @@ func (s *serviceStore) Write(record *store.Record, opts ...store.WriteOption) er
// Delete a record with key // Delete a record with key
func (s *serviceStore) Delete(key string, opts ...store.DeleteOption) error { func (s *serviceStore) Delete(key string, opts ...store.DeleteOption) error {
var options store.DeleteOptions
for _, o := range opts {
o(&options)
}
deleteOpts := &pb.DeleteOptions{
Database: options.Database,
Table: options.Table,
}
_, err := s.Client.Delete(s.Context(), &pb.DeleteRequest{ _, err := s.Client.Delete(s.Context(), &pb.DeleteRequest{
Key: key, Key: key,
Options: deleteOpts,
}, client.WithAddress(s.Nodes...)) }, client.WithAddress(s.Nodes...))
if err != nil && errors.Equal(err, errors.NotFound("", "")) { if err != nil && errors.Equal(err, errors.NotFound("", "")) {
return store.ErrNotFound return store.ErrNotFound