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

chore(prisma): upgrade prisma to v5.19.0 #1331

Merged
merged 3 commits into from
Aug 27, 2024
Merged
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
4 changes: 2 additions & 2 deletions binaries/version.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package binaries

// PrismaVersion is a hardcoded version of the Prisma CLI.
const PrismaVersion = "5.16.2"
const PrismaVersion = "5.19.0"

// EngineVersion is a hardcoded version of the Prisma Engine.
// The versions can be found under https://github.com/prisma/prisma-engines/commits/main
const EngineVersion = "34ace0eb2704183d2c05b60b52fba5c43c13f303"
const EngineVersion = "5fe21811a6ba0b952a3bc71400666511fe3b902f"
4 changes: 2 additions & 2 deletions engine/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (e *QueryEngine) Do(ctx context.Context, payload interface{}, v interface{}
return fmt.Errorf("internal error: %s", e.RawMessage())
}

response.Data.Result, err = transformResponse(response.Data.Result)
response.Data.Result, err = TransformResponse(response.Data.Result)
if err != nil {
return fmt.Errorf("transform response: %w", err)
}
Expand All @@ -69,7 +69,7 @@ func (e *QueryEngine) Batch(ctx context.Context, payload interface{}, v interfac
return fmt.Errorf("request failed: %w", err)
}

body, err = transformResponse(body)
body, err = TransformResponse(body)
if err != nil {
return fmt.Errorf("transform response: %w", err)
}
Expand Down
124 changes: 26 additions & 98 deletions engine/transform.go
Original file line number Diff line number Diff line change
@@ -1,115 +1,43 @@
package engine

import (
"encoding/base64"
"encoding/json"
"fmt"

"github.com/steebchen/prisma-client-go/logger"
"strings"
)

// transformResponse for raw queries
// transforms all custom prisma types into native go types, such as
// [{"prisma__type":"string","prisma__value":"asdf"},{"prisma__type":"null","prisma__value":null}]
// ->
// ["asdf", null]
func transformResponse(data []byte) ([]byte, error) {
var m interface{}
if err := json.Unmarshal(data, &m); err != nil {
return nil, err
}
type Input struct {
Columns []string `json:"columns"`
Types []string `json:"types"`
Rows [][]interface{} `json:"rows"`
}

forEachValue(&m, func(k *string, i *int, v *interface{}) (interface{}, bool) {
if v == nil {
return nil, false
}
var n = *v
o, isObject := (*v).(map[string]interface{})
if isObject {
var ok bool
n, ok = handleObject(o)
if !ok {
return n, false
}
}
return n, true
})
// TransformResponse for raw queries
func TransformResponse(data []byte) ([]byte, error) {
// TODO properly detect a json response
if !strings.HasPrefix(string(data), `{"columns":[`) {
return data, nil
}

out, err := json.Marshal(m)
var input Input
err := json.Unmarshal(data, &input)
if err != nil {
return nil, fmt.Errorf("transform response marshal: %w", err)
return nil, err
}

logger.Debug.Printf("transformed response: %s", out)

return out, nil
}
output := make([]map[string]interface{}, 0)

func handleObject(o map[string]interface{}) (interface{}, bool) {
if t, ok := o["prisma__type"]; ok {
if t == "bytes" {
// bytes from prisma are base64 encoded
bytes, ok := o["prisma__value"].(string)
if !ok {
panic("expected bytes")
}
dst := make([]byte, base64.StdEncoding.DecodedLen(len(bytes)))
n, err := base64.StdEncoding.Decode(dst, []byte(bytes))
if err != nil {
panic(err)
}
dst = dst[:n]
return dst, false
for _, row := range input.Rows {
m := make(map[string]interface{})
for i, column := range input.Columns {
m[column] = row[i]
}
if t == "array" {
value, ok := o["prisma__value"].([]interface{})
if !ok {
panic("expected array")
}
var items []interface{}
for _, item := range value {
item, _ := handleObject(item.(map[string]interface{}))
items = append(items, item)
}
return items, false
}
return o["prisma__value"], false
output = append(output, m)
}
return o, true
}

func forEachValue(obj *interface{}, handler func(*string, *int, *interface{}) (interface{}, bool)) {
if obj == nil {
return
}
var ok bool
var n = *obj
// Yield all key/value pairs for objects.
o, isObject := (*obj).(map[string]interface{})
if isObject {
for k := range o {
item := o[k]
o[k], ok = handler(&k, nil, &item)
item = o[k]
if ok {
forEachValue(&item, handler)
}
}
n = o
}
// Yield each index/value for arrays.
a, isArray := (*obj).([]interface{})
if isArray {
for i := range a {
item := a[i]
a[i], ok = handler(nil, &i, &item)
item = a[i]
if ok {
forEachValue(&item, handler)
}
}
n = a
o, err := json.Marshal(output)
if err != nil {
return nil, err
}
*obj = n
// Do nothing for primitives since the handler got them.

return o, nil
}
69 changes: 7 additions & 62 deletions engine/transform_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package engine

import (
"reflect"
"testing"

"github.com/stretchr/testify/assert"
)

func Test_transformResponse(t *testing.T) {
Expand All @@ -14,75 +15,19 @@ func Test_transformResponse(t *testing.T) {
args args
want []byte
}{{
name: "replace nulls array",
args: args{
data: []byte(`[{"prisma__type":"string","prisma__value":"asdf"},{"prisma__type":"null","prisma__value":null}]`),
},
want: []byte(`["asdf",null]`),
}, {
name: "replace nulls object",
args: args{
data: []byte(`[{"id":{"prisma__type":"null","prisma__value":null}}]`),
},
want: []byte(`[{"id":null}]`),
}, {
name: "replace string",
args: args{
data: []byte(`[{"id":{"prisma__type":"string","prisma__value":"asdf"}}]`),
},
want: []byte(`[{"id":"asdf"}]`),
}, {
name: "replace string with other objects",
args: args{
data: []byte(`[{"id":{"prisma__type":"string","prisma__value":"asdf"}},{"some":{"other":"object"}},{"value":5}]`),
},
want: []byte(`[{"id":"asdf"},{"some":{"other":"object"}},{"value":5}]`),
}, {
name: "native string",
args: args{
data: []byte(`"asdf"`),
},
want: []byte(`"asdf"`),
}, {
name: "native number",
args: args{
data: []byte(`5`),
},
want: []byte(`5`),
}, { // edge cases which are specifically handled
name: "bytes",
args: args{
data: []byte(`{"item":{"prisma__type":"bytes","prisma__value":"eyJzb21lIjo1fQ=="}}`),
},
want: []byte(`{"item":"eyJzb21lIjo1fQ=="}`),
}, {
name: "bytes",
name: "transform",
args: args{
data: []byte(`[{"prisma__type":"bytes","prisma__value":"eyJzb21lIjp7ImEiOiJiIn19"}]`),
data: []byte(`{"columns":["id","email","username","str","strOpt","date","dateOpt","int","intOpt","float","floatOpt","bool","boolOpt"],"types":["string","string","string","string","string","datetime","datetime","int","int","double","double","int","int"],"rows":[["id1","email1","a","str","strOpt","2020-01-01T00:00:00+00:00","2020-01-01T00:00:00+00:00",5,5,5.5,5.5,1,0],["id2","email2","b","str","strOpt","2020-01-01T00:00:00+00:00","2020-01-01T00:00:00+00:00",5,5,5.5,5.5,1,0]]}`),
},
want: []byte(`["eyJzb21lIjp7ImEiOiJiIn19"]`),
}, {
name: "bytes",
args: args{
data: []byte(`[{"prisma__type":"bytes","prisma__value":"MTIz"}]`),
},
want: []byte(`["MTIz"]`),
}, {
name: "big",
args: args{
data: []byte(`[{"id":{"prisma__type":"string","prisma__value":"id1"},"email":{"prisma__type":"string","prisma__value":"email1"},"username":{"prisma__type":"string","prisma__value":"a"},"str":{"prisma__type":"string","prisma__value":"str"},"strOpt":{"prisma__type":"string","prisma__value":"strOpt"},"strEmpty":{"prisma__type":"null","prisma__value":null},"time":{"prisma__type":"datetime","prisma__value":"2020-01-01T00:00:00+00:00"},"timeOpt":{"prisma__type":"datetime","prisma__value":"2020-01-01T00:00:00+00:00"},"timeEmpty":{"prisma__type":"null","prisma__value":null},"int":{"prisma__type":"int","prisma__value":5},"intOpt":{"prisma__type":"int","prisma__value":5},"intEmpty":{"prisma__type":"null","prisma__value":null},"float":{"prisma__type":"double","prisma__value":5.5},"floatOpt":{"prisma__type":"double","prisma__value":5.5},"floatEmpty":{"prisma__type":"null","prisma__value":null},"bool":{"prisma__type":"bool","prisma__value":true},"boolOpt":{"prisma__type":"bool","prisma__value":false},"boolEmpty":{"prisma__type":"null","prisma__value":null},"decimal":{"prisma__type":"decimal","prisma__value":"5.5"},"decimalOpt":{"prisma__type":"decimal","prisma__value":"5.5"},"decimalEmpty":{"prisma__type":"null","prisma__value":null},"json":{"prisma__type":"json","prisma__value":{"field":"value"}},"jsonOpt":{"prisma__type":"json","prisma__value":{"field":"value"}},"jsonEmpty":{"prisma__type":"null","prisma__value":null},"bytes":{"prisma__type":"bytes","prisma__value":"eyJmaWVsZCI6InZhbHVlIn0="},"bytesOpt":{"prisma__type":"bytes","prisma__value":"eyJmaWVsZCI6InZhbHVlIn0="},"bytesEmpty":{"prisma__type":"null","prisma__value":null}},{"id":{"prisma__type":"string","prisma__value":"id2"},"email":{"prisma__type":"string","prisma__value":"email2"},"username":{"prisma__type":"string","prisma__value":"b"},"str":{"prisma__type":"string","prisma__value":"str"},"strOpt":{"prisma__type":"string","prisma__value":"strOpt"},"strEmpty":{"prisma__type":"null","prisma__value":null},"time":{"prisma__type":"datetime","prisma__value":"2020-01-01T00:00:00+00:00"},"timeOpt":{"prisma__type":"datetime","prisma__value":"2020-01-01T00:00:00+00:00"},"timeEmpty":{"prisma__type":"null","prisma__value":null},"int":{"prisma__type":"int","prisma__value":5},"intOpt":{"prisma__type":"int","prisma__value":5},"intEmpty":{"prisma__type":"null","prisma__value":null},"float":{"prisma__type":"double","prisma__value":5.5},"floatOpt":{"prisma__type":"double","prisma__value":5.5},"floatEmpty":{"prisma__type":"null","prisma__value":null},"bool":{"prisma__type":"bool","prisma__value":true},"boolOpt":{"prisma__type":"bool","prisma__value":false},"boolEmpty":{"prisma__type":"null","prisma__value":null},"decimal":{"prisma__type":"decimal","prisma__value":"5.5"},"decimalOpt":{"prisma__type":"decimal","prisma__value":"5.5"},"decimalEmpty":{"prisma__type":"null","prisma__value":null},"json":{"prisma__type":"json","prisma__value":{"field":"value"}},"jsonOpt":{"prisma__type":"json","prisma__value":{"field":"value"}},"jsonEmpty":{"prisma__type":"null","prisma__value":null},"bytes":{"prisma__type":"bytes","prisma__value":"eyJmaWVsZCI6InZhbHVlIn0="},"bytesOpt":{"prisma__type":"bytes","prisma__value":"eyJmaWVsZCI6InZhbHVlIn0="},"bytesEmpty":{"prisma__type":"null","prisma__value":null}}]`),
},
want: []byte(`[{"bool":true,"boolEmpty":null,"boolOpt":false,"bytes":"eyJmaWVsZCI6InZhbHVlIn0=","bytesEmpty":null,"bytesOpt":"eyJmaWVsZCI6InZhbHVlIn0=","decimal":"5.5","decimalEmpty":null,"decimalOpt":"5.5","email":"email1","float":5.5,"floatEmpty":null,"floatOpt":5.5,"id":"id1","int":5,"intEmpty":null,"intOpt":5,"json":{"field":"value"},"jsonEmpty":null,"jsonOpt":{"field":"value"},"str":"str","strEmpty":null,"strOpt":"strOpt","time":"2020-01-01T00:00:00+00:00","timeEmpty":null,"timeOpt":"2020-01-01T00:00:00+00:00","username":"a"},{"bool":true,"boolEmpty":null,"boolOpt":false,"bytes":"eyJmaWVsZCI6InZhbHVlIn0=","bytesEmpty":null,"bytesOpt":"eyJmaWVsZCI6InZhbHVlIn0=","decimal":"5.5","decimalEmpty":null,"decimalOpt":"5.5","email":"email2","float":5.5,"floatEmpty":null,"floatOpt":5.5,"id":"id2","int":5,"intEmpty":null,"intOpt":5,"json":{"field":"value"},"jsonEmpty":null,"jsonOpt":{"field":"value"},"str":"str","strEmpty":null,"strOpt":"strOpt","time":"2020-01-01T00:00:00+00:00","timeEmpty":null,"timeOpt":"2020-01-01T00:00:00+00:00","username":"b"}]`),
want: []byte(`[{"bool":1,"boolOpt":0,"date":"2020-01-01T00:00:00+00:00","dateOpt":"2020-01-01T00:00:00+00:00","email":"email1","float":5.5,"floatOpt":5.5,"id":"id1","int":5,"intOpt":5,"str":"str","strOpt":"strOpt","username":"a"},{"bool":1,"boolOpt":0,"date":"2020-01-01T00:00:00+00:00","dateOpt":"2020-01-01T00:00:00+00:00","email":"email2","float":5.5,"floatOpt":5.5,"id":"id2","int":5,"intOpt":5,"str":"str","strOpt":"strOpt","username":"b"}]`),
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := transformResponse(tt.args.data)
got, err := TransformResponse(tt.args.data)
if err != nil {
t.Fatalf("transformResponse() error = %v", err)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("transformResponse() = %s, want %s", got, tt.want)
}
assert.Equal(t, string(tt.want), string(got))
})
}
}
5 changes: 5 additions & 0 deletions runtime/transaction/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"

"github.com/steebchen/prisma-client-go/engine"
"github.com/steebchen/prisma-client-go/logger"
)

Expand All @@ -20,6 +21,10 @@ func (r *Result) Get(c <-chan []byte, v interface{}) error {
if !ok {
return fmt.Errorf("result not fetched")
}
data, err := engine.TransformResponse(data)
if err != nil {
return fmt.Errorf("could not transform response: %w", err)
}
res = data
r.cache = data
}
Expand Down
Loading