Skip to content

Commit

Permalink
fix: Rename Result results_id JSON field name to deal_id (#469)
Browse files Browse the repository at this point in the history
* fix: Rename Result DealID JSON name to deal_id

* chore: Add custom serialization for backwards compatibility

* chore: Rename main data package file

* test: Add roundtrip serialization and compatibility tests
  • Loading branch information
bgins authored Dec 17, 2024
1 parent da719da commit 0050f2c
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 1 deletion.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ require (
k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
lukechampine.com/blake3 v1.3.0 // indirect
pgregory.net/rapid v1.1.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,8 @@ modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
Expand Down
55 changes: 54 additions & 1 deletion pkg/data/types.go → pkg/data/data.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package data

import (
"encoding/json"

"github.com/lilypad-tech/lilypad/pkg/data/bacalhau"
)

Expand Down Expand Up @@ -76,11 +78,62 @@ type Result struct {
ID string `json:"id"`
DealID string `json:"deal_id"`
// the CID of the actual results
DataID string `json:"results_id"`
DataID string `json:"data_id"`
Error string `json:"error"`
InstructionCount uint64 `json:"instruction_count"`
}

// Provides compatibility for older clients that expect the results_id field
func (r Result) MarshalJSON() ([]byte, error) {
// TODO(bgins) Remove when older clients have been deprecated

// Create an auxiliary type to avoid recursively calling json.Marshal
// https://stackoverflow.com/a/23046869
type ResultAux Result

// Add results_id field to the existing Result fields and marshal
return json.Marshal(struct {
ResultAux
ResultsID string `json:"results_id"`
}{
ResultAux: ResultAux(r),
ResultsID: r.DataID,
})
}

// Provides compatibility for newer clients that expect the data_id field
func (r *Result) UnmarshalJSON(data []byte) error {
// TODO(bgins) Remove when older clients have been deprecated

// Create an auxiliary type to avoid recursively calling json.Unmarshal
// https://stackoverflow.com/a/52433660
type ResultAux Result

// Unmarshal into auxiliary type
var aux ResultAux
if err := json.Unmarshal(data, &aux); err != nil {
return err
}

// Cast the auxilliary type to Result
*r = Result(aux)

// Create a raw map to capture the results_id field
var rawMap map[string]interface{}
if err := json.Unmarshal(data, &rawMap); err != nil {
return err
}

// Check if results_id exists and assign it to DataID if so
if resultsID, ok := rawMap["results_id"]; ok {
if strID, ok := resultsID.(string); ok {
r.DataID = strID
}
}

return nil
}

// MarketPrice means - get me the best deal
// job creators will do this by default i.e. "just buy me the cheapest"
// FixedPrice means - take it or leave it
Expand Down
106 changes: 106 additions & 0 deletions pkg/data/data_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//go:build unit

package data

import (
"encoding/json"
"testing"

"github.com/mr-tron/base58"
"pgregory.net/rapid"
)

func TestResultJSONRoundtrip(t *testing.T) {
rapid.Check(t, func(t *rapid.T) {
// Generate a random Result
original := Result{
ID: generateCID(t),
DealID: generateCID(t),
DataID: generateCID(t),
}

// Test marshaling to JSON
data, err := json.Marshal(original)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}

// Test unmarshaling back
var decoded Result
err = json.Unmarshal(data, &decoded)
if err != nil {
t.Fatalf("Unmarshal failed: %v", err)
}

// Verify the roundtrip preserved values
if original != decoded {
t.Errorf("Roundtrip failed: got %v, want %v", decoded, original)
}

// Verify both fields exist in JSON
var rawData map[string]interface{}
err = json.Unmarshal(data, &rawData)
if err != nil {
t.Fatalf("Raw unmarshal failed: %v", err)
}

// Check both data_id and results_id exist and match
dataID, hasDataID := rawData["data_id"]
resultsID, hasResultsID := rawData["results_id"]

if !hasDataID {
t.Error("data_id field missing")
}
if !hasResultsID {
t.Error("results_id field missing")
}
if dataID != resultsID {
t.Errorf("data_id and results_id mismatch: %v != %v", dataID, resultsID)
}
})
}

func TestResultJSONBackwardsCompatibility(t *testing.T) {
rapid.Check(t, func(t *rapid.T) {
expectedDataID := generateCID(t)

// Test old client format (results_id)
oldClientJSON := map[string]interface{}{
"id": generateCID(t),
"results_id": expectedDataID,
}
oldClientData, _ := json.Marshal(oldClientJSON)

var resultFromOld Result
err := json.Unmarshal(oldClientData, &resultFromOld)
if err != nil {
t.Fatalf("Unmarshal of old format failed: %v", err)
}
if resultFromOld.DataID != expectedDataID {
t.Errorf("Old format: got DataID %v, want %v", resultFromOld.DataID, expectedDataID)
}

// Test new client format (data_id)
newClientJSON := map[string]interface{}{
"id": generateCID(t),
"data_id": expectedDataID,
}
newClientData, _ := json.Marshal(newClientJSON)

var resultFromNew Result
err = json.Unmarshal(newClientData, &resultFromNew)
if err != nil {
t.Fatalf("Unmarshal of new format failed: %v", err)
}
if resultFromNew.DataID != expectedDataID {
t.Errorf("New format: got DataID %v, want %v", resultFromNew.DataID, expectedDataID)
}
})
}

// Generators

func generateCID(t *rapid.T) string {
bytes := rapid.SliceOfN(rapid.Byte(), 32, 32).Draw(t, "bytes")
return "Qm" + base58.Encode(bytes)
}

0 comments on commit 0050f2c

Please sign in to comment.