Skip to content

Commit

Permalink
api: add CRUD module support
Browse files Browse the repository at this point in the history
This patch provides crud [1] methods as request objects to support CRUD API.
The following methods are supported:

* `insert`
* `insert_object`
* `insert_many`
* `insert_object_many`
* `get`
* `update`
* `delete`
* `replace`
* `replace_object`
* `replace_many`
* `replace_object_many`
* `upsert`
* `upsert_object`
* `upsert_many`
* `upsert_object_many`
* `select`
* `min`
* `max`
* `truncate`
* `len`
* `storage_info`
* `count`
* `stats`
* `unflatten_rows`

1. https://github.com/tarantool/crud

Closes #108
  • Loading branch information
AnaNek authored and oleg-jukovec committed Mar 8, 2023
1 parent 3c93506 commit 1469484
Show file tree
Hide file tree
Showing 38 changed files with 4,185 additions and 64 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release.

- Support pagination (#246)
- A Makefile target to test with race detector (#218)
- Support CRUD API (#108)

### Changed

Expand Down
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ endif

.PHONY: clean
clean:
( cd ./queue; rm -rf .rocks )
( rm -rf queue/testdata/.rocks crud/testdata/.rocks )
rm -f $(COVERAGE_FILE)

.PHONY: deps
deps: clean
( cd ./queue/testdata; $(TTCTL) rocks install queue 1.2.1 )
( cd ./crud/testdata; $(TTCTL) rocks install crud 1.0.0 )

.PHONY: datetime-timezones
datetime-timezones:
Expand Down Expand Up @@ -99,6 +100,13 @@ test-settings:
go clean -testcache
go test -tags "$(TAGS)" ./settings/ -v -p 1

.PHONY: test-crud
test-crud:
@echo "Running tests in crud package"
cd ./crud/testdata && tarantool -e "require('crud')"
go clean -testcache
go test -tags "$(TAGS)" ./crud/ -v -p 1

.PHONY: test-main
test-main:
@echo "Running tests in main package"
Expand Down
95 changes: 95 additions & 0 deletions crud/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Package crud with support of API of Tarantool's CRUD module.
//
// Supported CRUD methods:
//
// - insert
//
// - insert_object
//
// - insert_many
//
// - insert_object_many
//
// - get
//
// - update
//
// - delete
//
// - replace
//
// - replace_object
//
// - replace_many
//
// - replace_object_many
//
// - upsert
//
// - upsert_object
//
// - upsert_many
//
// - upsert_object_many
//
// - select
//
// - min
//
// - max
//
// - truncate
//
// - len
//
// - storage_info
//
// - count
//
// - stats
//
// - unflatten_rows
//
// Since: 1.11.0.
package crud

import (
"context"

"github.com/tarantool/go-tarantool"
)

// Tuple is a type to describe tuple for CRUD methods.
type Tuple = []interface{}

type baseRequest struct {
impl *tarantool.CallRequest
}

func (req *baseRequest) initImpl(methodName string) {
req.impl = tarantool.NewCall17Request(methodName)
}

// Code returns IPROTO code for CRUD request.
func (req *baseRequest) Code() int32 {
return req.impl.Code()
}

// Ctx returns a context of CRUD request.
func (req *baseRequest) Ctx() context.Context {
return req.impl.Ctx()
}

// Async returns is CRUD request expects a response.
func (req *baseRequest) Async() bool {
return req.impl.Async()
}

type spaceRequest struct {
baseRequest
space string
}

func (req *spaceRequest) setSpace(space string) {
req.space = space
}
28 changes: 28 additions & 0 deletions crud/conditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package crud

// Operator is a type to describe operator of operation.
type Operator string

const (
// Eq - comparison operator for "equal".
Eq Operator = "="
// Lt - comparison operator for "less than".
Lt Operator = "<"
// Le - comparison operator for "less than or equal".
Le Operator = "<="
// Gt - comparison operator for "greater than".
Gt Operator = ">"
// Ge - comparison operator for "greater than or equal".
Ge Operator = ">="
)

// Condition describes CRUD condition as a table
// {operator, field-identifier, value}.
type Condition struct {
// Instruct msgpack to pack this struct as array, so no custom packer
// is needed.
_msgpack struct{} `msgpack:",asArray"` //nolint: structcheck,unused
Operator Operator
Field interface{} // Field name, field number or index name.
Value interface{}
}
109 changes: 109 additions & 0 deletions crud/count.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package crud

import (
"context"

"github.com/tarantool/go-tarantool"
)

// CountResult describes result for `crud.count` method.
type CountResult = NumberResult

// CountOpts describes options for `crud.count` method.
type CountOpts struct {
// Timeout is a `vshard.call` timeout and vshard
// master discovery timeout (in seconds).
Timeout OptUint
// VshardRouter is cartridge vshard group name or
// vshard router instance.
VshardRouter OptString
// Mode is a parameter with `write`/`read` possible values,
// if `write` is specified then operation is performed on master.
Mode OptString
// PreferReplica is a parameter to specify preferred target
// as one of the replicas.
PreferReplica OptBool
// Balance is a parameter to use replica according to vshard
// load balancing policy.
Balance OptBool
// YieldEvery describes number of tuples processed to yield after.
YieldEvery OptUint
// BucketId is a bucket ID.
BucketId OptUint
// ForceMapCall describes the map call is performed without any
// optimizations even if full primary key equal condition is specified.
ForceMapCall OptBool
// Fullscan describes if a critical log entry will be skipped on
// potentially long count.
Fullscan OptBool
}

// EncodeMsgpack provides custom msgpack encoder.
func (opts CountOpts) EncodeMsgpack(enc *encoder) error {
const optsCnt = 9

options := [optsCnt]option{opts.Timeout, opts.VshardRouter,
opts.Mode, opts.PreferReplica, opts.Balance,
opts.YieldEvery, opts.BucketId, opts.ForceMapCall,
opts.Fullscan}
names := [optsCnt]string{timeoutOptName, vshardRouterOptName,
modeOptName, preferReplicaOptName, balanceOptName,
yieldEveryOptName, bucketIdOptName, forceMapCallOptName,
fullscanOptName}
values := [optsCnt]interface{}{}

return encodeOptions(enc, options[:], names[:], values[:])
}

// CountRequest helps you to create request object to call `crud.count`
// for execution by a Connection.
type CountRequest struct {
spaceRequest
conditions []Condition
opts CountOpts
}

type countArgs struct {
_msgpack struct{} `msgpack:",asArray"` //nolint: structcheck,unused
Space string
Conditions []Condition
Opts CountOpts
}

// NewCountRequest returns a new empty CountRequest.
func NewCountRequest(space string) *CountRequest {
req := new(CountRequest)
req.initImpl("crud.count")
req.setSpace(space)
req.conditions = nil
req.opts = CountOpts{}
return req
}

// Conditions sets the conditions for the CountRequest request.
// Note: default value is nil.
func (req *CountRequest) Conditions(conditions []Condition) *CountRequest {
req.conditions = conditions
return req
}

// Opts sets the options for the CountRequest request.
// Note: default value is nil.
func (req *CountRequest) Opts(opts CountOpts) *CountRequest {
req.opts = opts
return req
}

// Body fills an encoder with the call request body.
func (req *CountRequest) Body(res tarantool.SchemaResolver, enc *encoder) error {
args := countArgs{Space: req.space, Conditions: req.conditions, Opts: req.opts}
req.impl = req.impl.Args(args)
return req.impl.Body(res, enc)
}

// Context sets a passed context to CRUD request.
func (req *CountRequest) Context(ctx context.Context) *CountRequest {
req.impl = req.impl.Context(ctx)

return req
}
66 changes: 66 additions & 0 deletions crud/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package crud

import (
"context"

"github.com/tarantool/go-tarantool"
)

// DeleteResult describes result for `crud.delete` method.
type DeleteResult = Result

// DeleteOpts describes options for `crud.delete` method.
type DeleteOpts = SimpleOperationOpts

// DeleteRequest helps you to create request object to call `crud.delete`
// for execution by a Connection.
type DeleteRequest struct {
spaceRequest
key Tuple
opts DeleteOpts
}

type deleteArgs struct {
_msgpack struct{} `msgpack:",asArray"` //nolint: structcheck,unused
Space string
Key Tuple
Opts DeleteOpts
}

// NewDeleteRequest returns a new empty DeleteRequest.
func NewDeleteRequest(space string) *DeleteRequest {
req := new(DeleteRequest)
req.initImpl("crud.delete")
req.setSpace(space)
req.key = Tuple{}
req.opts = DeleteOpts{}
return req
}

// Key sets the key for the DeleteRequest request.
// Note: default value is nil.
func (req *DeleteRequest) Key(key Tuple) *DeleteRequest {
req.key = key
return req
}

// Opts sets the options for the DeleteRequest request.
// Note: default value is nil.
func (req *DeleteRequest) Opts(opts DeleteOpts) *DeleteRequest {
req.opts = opts
return req
}

// Body fills an encoder with the call request body.
func (req *DeleteRequest) Body(res tarantool.SchemaResolver, enc *encoder) error {
args := deleteArgs{Space: req.space, Key: req.key, Opts: req.opts}
req.impl = req.impl.Args(args)
return req.impl.Body(res, enc)
}

// Context sets a passed context to CRUD request.
func (req *DeleteRequest) Context(ctx context.Context) *DeleteRequest {
req.impl = req.impl.Context(ctx)

return req
}
Loading

0 comments on commit 1469484

Please sign in to comment.