blob: ae849c9a1108a7d5bcdb00d5309c47e54861e136 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package server
import (
"v.io/syncbase/v23/services/syncbase"
"v.io/syncbase/x/ref/services/syncbase/store"
"v.io/v23/rpc"
"v.io/v23/vdl"
"v.io/v23/verror"
)
// TODO(sadovsky): Extend data layout to support version tracking for sync.
// See go/vanadium-local-structured-store.
type item struct {
encodedKey string
t *table
}
var _ syncbase.ItemServerMethods = (*item)(nil)
func (i *item) Get(call rpc.ServerCall) (*vdl.Value, error) {
var value *vdl.Value
if err := store.RunInTransaction(i.t.d.u.s.st, func(st store.Store) error {
var err error
value, err = i.get(call, st)
return err
}); err != nil {
return nil, err
}
return value, nil
}
func (i *item) Put(call rpc.ServerCall, value *vdl.Value) error {
return store.RunInTransaction(i.t.d.u.s.st, func(st store.Store) error {
return i.put(call, st, value)
})
}
func (i *item) Delete(call rpc.ServerCall) error {
return store.RunInTransaction(i.t.d.u.s.st, func(st store.Store) error {
return i.del(call, st)
})
}
////////////////////////////////////////
// Internal helpers
func (i *item) keyPart() string {
return joinKeyParts(i.t.keyPart(), i.encodedKey)
}
func (i *item) key() string {
return joinKeyParts("$item", i.keyPart())
}
// Performs authorization check (against the database Permissions) and checks that this
// item's table exists in the database schema. Returns the schema and a
// VDL-compatible error.
func (i *item) checkAccess(call rpc.ServerCall, st store.Store) (syncbase.Schema, error) {
data, err := i.t.d.get(call, st, true)
if err != nil {
return nil, err
}
if _, ok := data.Schema[i.t.name]; !ok {
return nil, verror.NewErrNoExist(call.Context())
}
return data.Schema, nil
}
// Reads data from the storage engine.
// Performs authorization check. Returns a VDL-compatible error.
func (i *item) get(call rpc.ServerCall, st store.Store) (*vdl.Value, error) {
if _, err := i.checkAccess(call, st); err != nil {
return nil, err
}
value := &vdl.Value{}
if err := getObject(st, i.key(), value); err != nil {
if _, ok := err.(*store.ErrUnknownKey); ok {
// We've already done an auth check, so here we can safely return NoExist
// rather than NoExistOrNoAccess.
return nil, verror.NewErrNoExist(call.Context())
}
return nil, verror.New(verror.ErrInternal, call.Context(), err)
}
return value, nil
}
// Writes data to the storage engine.
// Performs authorization check. Returns a VDL-compatible error.
func (i *item) put(call rpc.ServerCall, st store.Store, value *vdl.Value) error {
// TODO(sadovsky): Check that value's primary key field matches i.encodedKey.
if _, err := i.checkAccess(call, st); err != nil {
return err
}
if err := putObject(st, i.key(), &value); err != nil {
return verror.New(verror.ErrInternal, call.Context(), err)
}
return nil
}
// Deletes data from the storage engine.
// Performs authorization check. Returns a VDL-compatible error.
func (i *item) del(call rpc.ServerCall, st store.Store) error {
if _, err := i.checkAccess(call, st); err != nil {
return err
}
if err := st.Delete(i.key()); err != nil {
return verror.New(verror.ErrInternal, call.Context(), err)
}
return nil
}