Skip to content

Commit

Permalink
SI-2166-filter-vehicles-by-owner (#59)
Browse files Browse the repository at this point in the history
* filter vehicle by owner

* error messages

* wrap error msgs

* filter by owned by AND priv rather than owned by OR priv

* add another test and better comments

* fix tests that broke after merging main

* sub tests
  • Loading branch information
Allyson-English committed Nov 14, 2023
1 parent 832620c commit b9fd3c6
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 8 deletions.
11 changes: 10 additions & 1 deletion graph/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions graph/model/models_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions graph/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ input VehiclesFilter {
that this address owns.
"""
privileged: Address
owner: Address
}

input AftermarketDevicesFilter {
Expand Down
135 changes: 135 additions & 0 deletions internal/repositories/owned_vehicles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/DIMO-Network/identity-api/models"
"github.com/DIMO-Network/shared/db"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"github.com/testcontainers/testcontainers-go"
"github.com/volatiletech/null/v8"
Expand Down Expand Up @@ -295,3 +296,137 @@ func (s *OwnedVehiclesRepoTestSuite) Test_GetOwnedVehicles_Pagination_NextPage()

s.Exactly(expected, res.Edges)
}

func Test_GetOwnedVehicles_Filters(t *testing.T) {
// Vehicle | Owner | Privileged Users
// --------+-------+-----------------
// 1 | A | B
// 2 | B | C
// 3 | A |
ctx := context.Background()
assert := assert.New(t)
pdb, _ := helpers.StartContainerDatabase(ctx, t, migrationsDir)

repo := New(pdb, config.Settings{})
_, walletA, err := helpers.GenerateWallet()
assert.NoError(err)
_, walletB, err := helpers.GenerateWallet()
assert.NoError(err)
_, walletC, err := helpers.GenerateWallet()
assert.NoError(err)

data := []struct {
TokenID int
Owner *common.Address
Privileged *common.Address
}{
{
TokenID: 1,
Owner: walletA,
Privileged: walletB,
},
{
TokenID: 2,
Owner: walletB,
Privileged: walletC,
},
{
TokenID: 3,
Owner: walletA,
},
}

for _, v := range data {
vehicle := models.Vehicle{
ID: v.TokenID,
OwnerAddress: v.Owner.Bytes(),
Make: null.StringFrom("Toyota"),
Model: null.StringFrom("Camry"),
Year: null.IntFrom(2022),
MintedAt: time.Now(),
}
if err := vehicle.Insert(ctx, pdb.DBS().Writer, boil.Infer()); err != nil {
assert.NoError(err)
}

if v.Privileged != nil {
privileges := models.Privilege{
TokenID: v.TokenID,
PrivilegeID: 1,
UserAddress: v.Privileged.Bytes(),
SetAt: time.Now(),
ExpiresAt: time.Now().Add(5 * time.Hour),
}

if err := privileges.Insert(ctx, pdb.DBS().Writer, boil.Infer()); err != nil {
assert.NoError(err)
}
}
}

for _, testCases := range []struct {
Name string
Description string
First int
Filter gmodel.VehiclesFilter
ExpectedTotal int
ExpectedTokens []int
ExpectedOwner []*common.Address
}{
{
Description: "Filter By Privileged: priv wallet has both implied (owner) and explicit (granted) privileges",
// Owner | Privileged | Result
// ------+------------+-------
// | B | 1, 2
First: 3,
Filter: gmodel.VehiclesFilter{Privileged: walletB},
ExpectedTotal: 2,
ExpectedTokens: []int{2, 1},
ExpectedOwner: []*common.Address{walletB, walletA},
},
{
Description: "Filter By Owner",
// Owner | Privileged | Result
// ------+------------+-------
// A | | 1, 3
First: 3,
Filter: gmodel.VehiclesFilter{Owner: walletA},
ExpectedTotal: 2,
ExpectedTokens: []int{3, 1},
ExpectedOwner: []*common.Address{walletA, walletA},
},
{
Description: "Filter By Privileged & Owner, result must match both criteria (valid combo)",
// Owner | Privileged | Result
// ------+------------+-------
// A | B | 1
First: 3,
Filter: gmodel.VehiclesFilter{Owner: walletA, Privileged: walletB},
ExpectedTotal: 1,
ExpectedTokens: []int{1},
ExpectedOwner: []*common.Address{walletA},
},
{
Description: "Filter By Privileged & Owner, result must match both criteria (invalid combo)",
// Owner | Privileged | Result
// ------+------------+-------
// C | B |
First: 3,
Filter: gmodel.VehiclesFilter{Owner: walletC, Privileged: walletB},
ExpectedTotal: 0,
ExpectedTokens: []int{},
ExpectedOwner: []*common.Address{},
},
} {
res, err := repo.GetVehicles(ctx, &testCases.First, nil, nil, nil, &testCases.Filter)
assert.NoError(err)

assert.Equal(testCases.ExpectedTotal, res.TotalCount)
for idx, tknID := range testCases.ExpectedTokens {
assert.Equal(tknID, res.Edges[idx].Node.TokenID)
}
for idx, addr := range testCases.ExpectedOwner {
assert.Equal(*addr, res.Edges[idx].Node.Owner)
}
}
}
20 changes: 13 additions & 7 deletions internal/repositories/vehicles.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ func (v *Repository) GetVehicles(ctx context.Context, first *int, after *string,
limit = *last
}

var err error
var totalCount int64
var queryMods []qm.QueryMod

if filterBy != nil && filterBy.Privileged != nil {
addr := *filterBy.Privileged
queryMods = []qm.QueryMod{
Expand All @@ -186,7 +186,10 @@ func (v *Repository) GetVehicles(ctx context.Context, first *int, after *string,
),
}

var err error
if filterBy.Owner != nil {
queryMods = append(queryMods, models.VehicleWhere.OwnerAddress.EQ(filterBy.Owner.Bytes()))
}

totalCount, err = models.Vehicles(
// We're performing this because SQLBoiler doesn't understand DISTINCT ON. If we use
// the original version of queryMods the entire SELECT clause will be replaced by
Expand All @@ -197,15 +200,18 @@ func (v *Repository) GetVehicles(ctx context.Context, first *int, after *string,
return nil, err
}
} else {
// TODO(elffjs): Ugly.
queryMods = []qm.QueryMod{}
var err error
totalCount, err = models.Vehicles().Count(ctx, v.pdb.DBS().Reader)
if filterBy != nil && filterBy.Owner != nil {
queryMods = append(queryMods,
models.VehicleWhere.OwnerAddress.EQ(filterBy.Owner.Bytes()),
)
}

totalCount, err = models.Vehicles(queryMods...).Count(ctx, v.pdb.DBS().Reader)
if err != nil {
return nil, err
}
}

}
if after != nil {
afterID, err := helpers.CursorToID(*after)
if err != nil {
Expand Down

0 comments on commit b9fd3c6

Please sign in to comment.