Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(marshal): smartUnmarshalRaw1 to handle raw query single return result including THROW statement errors #120

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func (s *SurrealDBTestSuite) TestDelete() {

func (s *SurrealDBTestSuite) TestInsert() {
s.Run("raw map works", func() {
userData, err := s.db.Insert("user", map[string]interface{}{
userData, err := s.db.Insert("users", map[string]interface{}{
agufagit marked this conversation as resolved.
Show resolved Hide resolved
"username": "johnny",
"password": "123",
})
Expand All @@ -244,7 +244,7 @@ func (s *SurrealDBTestSuite) TestInsert() {
})

s.Run("Single insert works", func() {
userData, err := s.db.Insert("user", testUser{
userData, err := s.db.Insert("users", testUser{
agufagit marked this conversation as resolved.
Show resolved Hide resolved
Username: "johnny",
Password: "123",
})
Expand All @@ -268,7 +268,7 @@ func (s *SurrealDBTestSuite) TestInsert() {
Username: "johnny2",
Password: "123",
})
userData, err := s.db.Insert("user", userInsert)
userData, err := s.db.Insert("users", userInsert)
agufagit marked this conversation as resolved.
Show resolved Hide resolved
s.Require().NoError(err)

// unmarshal the data into a user struct
Expand Down Expand Up @@ -574,6 +574,46 @@ func (s *SurrealDBTestSuite) TestSmartUnMarshalQuery() {
})
}

func (s *SurrealDBTestSuite) TestSmartUnMarshalRaw1Query() {
user := testUser{
Username: "electwix",
Password: "1234",
}

s.Run("raw create query", func() {
QueryStr := "CREATE ONLY users SET Username = $user, Password = $pass"
data, err := marshal.SmartUnmarshalRaw1[testUser](s.db.Query(QueryStr, map[string]interface{}{
"user": user.Username,
"pass": user.Password,
}))

s.Require().NoError(err)
s.Equal("electwix", data.Username)
user = data
})

s.Run("raw select query", func() {
dataArr, err := marshal.SmartUnmarshalRaw1[[]testUser](s.db.Query("SELECT * FROM $record", map[string]interface{}{
"record": user.ID,
}))

s.Require().NoError(err)
s.Equal("electwix", dataArr[0].Username)
})

s.Run("raw THROW query", func() {
_, err := marshal.SmartUnmarshalRaw1[[]testUser](s.db.Query(
`BEGIN;
THROW 'blocked';
COMMIT;
`,
map[string]interface{}{}))

s.Require().Error(err)
s.Require().Contains(err.Error(), "blocked")
})
}

func (s *SurrealDBTestSuite) TestSmartMarshalQuery() {
user := []testUser{{
Username: "electwix",
Expand Down
55 changes: 55 additions & 0 deletions pkg/marshal/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ type RawQuery[I any] struct {
Detail string `json:"detail"`
}

type RawQuerySingle[I any] struct {
Status string `json:"status"`
Time string `json:"time"`
Result I `json:"result"`
Detail string `json:"detail"`
}

// Unmarshal loads a SurrealDB response into a struct.
func Unmarshal(data, v interface{}) (err error) {
var jsonBytes []byte
Expand Down Expand Up @@ -110,6 +117,54 @@ func SmartUnmarshal[I any](respond interface{}, wrapperError error) (outputs []I
return outputs, err
}

// SmartUnmarshalRaw1 using generics for return desired type.
// Supports only raw queries with 1 returned result.
// example: [map[result:true status:OK time:4.219606ms]]
// handles THROW errors: [map[result:An error occurred: blocked status:ERR time:4.219606ms]]
func SmartUnmarshalRaw1[I any](respond interface{}, wrapperError error) (output I, err error) {
// Handle delete
if respond == nil || wrapperError != nil {
return output, wrapperError
}
data, err := json.Marshal(respond)
if err != nil {
return output, err
}

var rawArr []RawQuerySingle[I]
if err = json.Unmarshal(data, &rawArr); err == nil {
if len(rawArr) == 1 {
raw := rawArr[0]
if raw.Status != StatusOK {
err = errors.Join(err, errors.New(raw.Detail))
} else {
output = raw.Result
}
} else {
err = errors.New("invalid response")
}
} else {
// Error in Result field
unmarshalError := err
var rawError []RawQuerySingle[string]
if err = json.Unmarshal(data, &rawError); err == nil {
if len(rawError) == 1 {
if rawError[0].Status != StatusOK {
err = errors.Join(err, errors.New(rawError[0].Result))
} else {
err = errors.Join(err, unmarshalError)
}
} else {
err = errors.New("invalid response")
}
} else {
err = errors.Join(err, unmarshalError)
}
}

return output, err
}

// Used for define table name, it has no value.
type Basemodel struct{}

Expand Down
Loading