go-tarantool icon indicating copy to clipboard operation
go-tarantool copied to clipboard

How implement struct for use in crud insert request?

Open siller174 opened this issue 2 years ago • 14 comments

How implement struct for put in crud request?

Example with map

	insert := crud.MakeInsertObjectRequest("user").
			Object(
				crud.MapObject(map[string]interface{}{
					"id":         userUUID,
					"created_at": time.Now().Unix(),
					"buc1ket_id": nil,
				})).
			Context(ctx)

But i want implement myself Object.

I should use this interface:

type encoder = msgpack.Encoder
type decoder = msgpack.Decoder

// Object is an interface to describe object for CRUD methods.
type Object interface {
	EncodeMsgpack(enc *encoder)
}

with private field encoder.

My struct

type Customer struct {
	ID        string `msgpack:"'id'"`
	CreatedAt string `msgpack:"'created_at'"`
	BucketID  *int64 `msgpack:"'bucket_id'"`
}

func (c *Customer) EncodeMsgpack(enc *msgpack.Encoder) {
	enc.Encode(&c)
}

What am i doing wrong?

siller174 avatar Jul 29 '23 10:07 siller174

Hello. Could you please provide more information about the issue you're facing? What specific error message or problem are you encountering?

You could insert a tuple with InsertRequest:

type exampleInsertTuple struct {
	_msgpack struct{} `msgpack:",asArray"` //nolint: structcheck,unused
	ID        uint
	BucketID  *uint	
	Name      string
}

func ExampleInsertRequest() {
	conn := exampleConnect()
	tup := exampleInsertTuple{
		ID:       2024,
		BucketID: nil,
		Name:     "foo",
	}
	req := crud.MakeInsertRequest(exampleSpace).Tuple(tup)

	ret := crud.Result{}
	if err := conn.Do(req).GetTyped(&ret); err != nil {
		fmt.Printf("Failed to execute request: %s", err)
	} else {
		fmt.Println(ret.Metadata)
		fmt.Println(ret.Rows)
	}
	// Output:
	// [{id unsigned false} {bucket_id unsigned true} {name string false}]
	// [[2024 263 foo]]
}

or an object with InsertObjectRequest:

type exampleInsertObject struct {
	ID        uint   `msgpack:"'id'"`
	BucketID  *uint  `msgpack:"'bucket_id'"`	
	Name      string `msgpack:"'name'"`
}

func (e *exampleInsertObject) EncodeMsgpack(enc *msgpack.Encoder) {
	enc.Encode(e)
}

func ExampleInsertObjectRequest() {
	conn := exampleConnect()
	obj := exampleInsertObject{
		ID:       2022,
		BucketID: nil,
		Name:     "foo",
	}
	req := crud.MakeInsertObjectRequest(exampleSpace).Object(&obj)

	ret := crud.Result{}
	if err := conn.Do(req).GetTyped(&ret); err != nil {
		fmt.Printf("Failed to execute request: %s", err)
	} else {
		fmt.Println(ret.Metadata)
		fmt.Println(ret.Rows)
	}
	// Output:
	// [{id unsigned false} {bucket_id unsigned true} {name string false}]
	// [[2022 263 foo]]
}

The examples are works with out test space format:

https://github.com/tarantool/go-tarantool/blob/b30e2b69c9fca74953178afe9a80c38530d85aff/crud/testdata/config.lua#L45-L47

You could add the code into crud/example_test.go and run an example with a command:

$ cd crud && go test -v . -run ExampleInsertRequest

or

$ cd crud && go test -v . -run ExampleInsertObjectRequest

TODO: add an example with *ObjectRequest to crud/example_test.go.

oleg-jukovec avatar Jul 29 '23 15:07 oleg-jukovec

Yes, thank you. Main problem in crud is examples, it's really hard to integrate. Could you also write example for crud.MakeUpsertManyRequest?

siller174 avatar Jul 30 '23 07:07 siller174

Btw, if you mean "put" as "write a record disregarding whether a record with such primary key exist or not", it's Replace operations you are looking for. Insert operations throw error when you're trying to overwrite an existing record.

DifferentialOrange avatar Jul 31 '23 07:07 DifferentialOrange

@oleg-jukovec. One more question with crud.

How implement pagination select request?

For example in Lua

s:select({0},{iterator='GT',offset=1,limit=2})

In Options i found this

	// First describes the maximum count of the objects to return.
	First OptInt
	// After is a tuple after which objects should be selected.
	After OptTuple
	// BatchSize is a number of tuples to process per one request to storage.
	BatchSize OptUint

But didn't find offset parameter.

siller174 avatar Jul 31 '23 07:07 siller174

@DifferentialOrange thank you!

siller174 avatar Jul 31 '23 07:07 siller174

@oleg-jukovec. One more question with crud. But didn't find offset parameter.

crud's select does not have the offset parameter:

https://github.com/tarantool/crud/#select

You need to use After + First as it is described for crud:

https://github.com/tarantool/crud/blob/master/doc/select.md#pagination

oleg-jukovec avatar Jul 31 '23 08:07 oleg-jukovec

Okay :( So I should make 2 requests: First for get object for After, Second for make select with pagination?

siller174 avatar Jul 31 '23 08:07 siller174

There is no difference between original crud. A pagination logic wtih crud looks like this:

res, err = crud.select('developers', nil, { first = 5 })
for i = 0; i < 10; i++ then
    res, err = crud.select('developers', nil, { after = res.rows[5], first = 5 })
end

go-tarantool just provides wrappers around Lua's requests without additional logic.

oleg-jukovec avatar Jul 31 '23 08:07 oleg-jukovec

Thank you

siller174 avatar Jul 31 '23 10:07 siller174

I'm very sorry for so many questions.

But I have no idea, what I do wrong

const space = "user"

type User struct {
	_msgpack struct{} `msgpack:",asArray"` //nolint: structcheck,unused

	ID        string `msgpack:"id"`
	CreatedAt string `msgpack:"created_at"`
	BucketID  *uint  `msgpack:"'bucket_id'"`
}

func (e *User) EncodeMsgpack(enc *msgpack.Encoder) {
	enc.Encode(e)
}

func main() {
	var (
		user = "admin"
		pass = "secret-cluster-cookie"
		dsn  = "localhost:3301"

		ctx = context.Background()

		offset = 2
		limit  = 2
	)

	connection, err := tarantool.New(user, pass, dsn)
	if err != nil {
		panic(err)
	}

	if offset == 0 {
		offset = limit
	}

	var (
		req = crud.MakeSelectRequest(space).
			Context(ctx).
			Opts(crud.SelectOpts{
				First: crud.MakeOptInt(limit),
			})
		ret = crud.MakeResult(reflect.TypeOf(User{}))
	)

	if err := connection.Do(req).GetTyped(&ret); err != nil {
		panic(err)
	}

	users := ret.Rows.([]User)
	if len(users) == 0 {
		panic("len(users) == 0")
	}

	u := users[offset-1]

	req = crud.MakeSelectRequest(space).
		Context(ctx).
		Opts(crud.SelectOpts{
			First: crud.MakeOptInt(limit),
			After: crud.MakeOptTuple(&u),
		})

	if err := connection.Do(req).GetTyped(&ret); err != nil {
		panic(err)
	}

	fmt.Println(ret.Metadata)
	fmt.Println(ret.Rows.([]User))
	fmt.Println("len: ", len(ret.Rows.([]User)))
}

siller174 avatar Jul 31 '23 14:07 siller174

Could you please provide more information about the issue you're facing? What specific error message or problem are you encountering?

oleg-jukovec avatar Jul 31 '23 16:07 oleg-jukovec

I just want to implement pagination logic

siller174 avatar Jul 31 '23 17:07 siller174

I just want to implement pagination logic

What specific error message are you encountering?

Is the fix relevant for you problem?

https://github.com/tarantool/go-tarantool/pull/323

oleg-jukovec avatar Jul 31 '23 17:07 oleg-jukovec

@oleg-jukovec yes, i just checked it with fix. Thank you.

siller174 avatar Aug 01 '23 10:08 siller174