diff --git a/graph/generated.go b/graph/generated.go index 370d3655..51e575da 100644 --- a/graph/generated.go +++ b/graph/generated.go @@ -100,6 +100,18 @@ type ComplexityRoot struct { Vehicle func(childComplexity int) int } + DCNConnection struct { + Edges func(childComplexity int) int + Nodes func(childComplexity int) int + PageInfo func(childComplexity int) int + TotalCount func(childComplexity int) int + } + + DCNEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int + } + Definition struct { Make func(childComplexity int) int Model func(childComplexity int) int @@ -175,6 +187,7 @@ type ComplexityRoot struct { AftermarketDevice func(childComplexity int, by model.AftermarketDeviceBy) int AftermarketDevices func(childComplexity int, first *int, after *string, last *int, before *string, filterBy *model.AftermarketDevicesFilter) int Dcn func(childComplexity int, by model.DCNBy) int + Dcns func(childComplexity int, first *int, after *string, last *int, before *string, filterBy *model.DCNFilter) int Node func(childComplexity int, id string) int Vehicle func(childComplexity int, tokenID int) int Vehicles func(childComplexity int, first *int, after *string, last *int, before *string, filterBy *model.VehiclesFilter) int @@ -248,6 +261,7 @@ type QueryResolver interface { AftermarketDevice(ctx context.Context, by model.AftermarketDeviceBy) (*model.AftermarketDevice, error) AftermarketDevices(ctx context.Context, first *int, after *string, last *int, before *string, filterBy *model.AftermarketDevicesFilter) (*model.AftermarketDeviceConnection, error) Dcn(ctx context.Context, by model.DCNBy) (*model.Dcn, error) + Dcns(ctx context.Context, first *int, after *string, last *int, before *string, filterBy *model.DCNFilter) (*model.DCNConnection, error) } type VehicleResolver interface { Manufacturer(ctx context.Context, obj *model.Vehicle) (*model.Manufacturer, error) @@ -484,6 +498,48 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.DCN.Vehicle(childComplexity), true + case "DCNConnection.edges": + if e.complexity.DCNConnection.Edges == nil { + break + } + + return e.complexity.DCNConnection.Edges(childComplexity), true + + case "DCNConnection.nodes": + if e.complexity.DCNConnection.Nodes == nil { + break + } + + return e.complexity.DCNConnection.Nodes(childComplexity), true + + case "DCNConnection.pageInfo": + if e.complexity.DCNConnection.PageInfo == nil { + break + } + + return e.complexity.DCNConnection.PageInfo(childComplexity), true + + case "DCNConnection.totalCount": + if e.complexity.DCNConnection.TotalCount == nil { + break + } + + return e.complexity.DCNConnection.TotalCount(childComplexity), true + + case "DCNEdge.cursor": + if e.complexity.DCNEdge.Cursor == nil { + break + } + + return e.complexity.DCNEdge.Cursor(childComplexity), true + + case "DCNEdge.node": + if e.complexity.DCNEdge.Node == nil { + break + } + + return e.complexity.DCNEdge.Node(childComplexity), true + case "Definition.make": if e.complexity.Definition.Make == nil { break @@ -812,6 +868,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.Dcn(childComplexity, args["by"].(model.DCNBy)), true + case "Query.dcns": + if e.complexity.Query.Dcns == nil { + break + } + + args, err := ec.field_Query_dcns_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Dcns(childComplexity, args["first"].(*int), args["after"].(*string), args["last"].(*int), args["before"].(*string), args["filterBy"].(*model.DCNFilter)), true + case "Query.node": if e.complexity.Query.Node == nil { break @@ -1044,6 +1112,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec.unmarshalInputAftermarketDeviceBy, ec.unmarshalInputAftermarketDevicesFilter, ec.unmarshalInputDCNBy, + ec.unmarshalInputDCNFilter, ec.unmarshalInputPrivilegeFilterBy, ec.unmarshalInputVehiclesFilter, ) @@ -1300,6 +1369,57 @@ func (ec *executionContext) field_Query_dcn_args(ctx context.Context, rawArgs ma return args, nil } +func (ec *executionContext) field_Query_dcns_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *int + if tmp, ok := rawArgs["first"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) + arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["first"] = arg0 + var arg1 *string + if tmp, ok := rawArgs["after"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("after")) + arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["after"] = arg1 + var arg2 *int + if tmp, ok := rawArgs["last"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("last")) + arg2, err = ec.unmarshalOInt2ᚖint(ctx, tmp) + if err != nil { + return nil, err + } + } + args["last"] = arg2 + var arg3 *string + if tmp, ok := rawArgs["before"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("before")) + arg3, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["before"] = arg3 + var arg4 *model.DCNFilter + if tmp, ok := rawArgs["filterBy"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("filterBy")) + arg4, err = ec.unmarshalODCNFilter2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNFilter(ctx, tmp) + if err != nil { + return nil, err + } + } + args["filterBy"] = arg4 + return args, nil +} + func (ec *executionContext) field_Query_node_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -2888,6 +3008,314 @@ func (ec *executionContext) fieldContext_DCN_vehicle(ctx context.Context, field return fc, nil } +func (ec *executionContext) _DCNConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *model.DCNConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DCNConnection_totalCount(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TotalCount, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalNInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_DCNConnection_totalCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DCNConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _DCNConnection_edges(ctx context.Context, field graphql.CollectedField, obj *model.DCNConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DCNConnection_edges(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Edges, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.DCNEdge) + fc.Result = res + return ec.marshalNDCNEdge2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNEdgeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_DCNConnection_edges(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DCNConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "cursor": + return ec.fieldContext_DCNEdge_cursor(ctx, field) + case "node": + return ec.fieldContext_DCNEdge_node(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DCNEdge", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _DCNConnection_nodes(ctx context.Context, field graphql.CollectedField, obj *model.DCNConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DCNConnection_nodes(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Nodes, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.Dcn) + fc.Result = res + return ec.marshalNDCN2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDcnᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_DCNConnection_nodes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DCNConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "node": + return ec.fieldContext_DCN_node(ctx, field) + case "owner": + return ec.fieldContext_DCN_owner(ctx, field) + case "expiresAt": + return ec.fieldContext_DCN_expiresAt(ctx, field) + case "mintedAt": + return ec.fieldContext_DCN_mintedAt(ctx, field) + case "name": + return ec.fieldContext_DCN_name(ctx, field) + case "vehicle": + return ec.fieldContext_DCN_vehicle(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DCN", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _DCNConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *model.DCNConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DCNConnection_pageInfo(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PageInfo, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.PageInfo) + fc.Result = res + return ec.marshalNPageInfo2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_DCNConnection_pageInfo(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DCNConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "startCursor": + return ec.fieldContext_PageInfo_startCursor(ctx, field) + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) + case "hasPreviousPage": + return ec.fieldContext_PageInfo_hasPreviousPage(ctx, field) + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _DCNEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *model.DCNEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DCNEdge_cursor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cursor, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_DCNEdge_cursor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DCNEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _DCNEdge_node(ctx context.Context, field graphql.CollectedField, obj *model.DCNEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_DCNEdge_node(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Node, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Dcn) + fc.Result = res + return ec.marshalNDCN2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDcn(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_DCNEdge_node(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "DCNEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "node": + return ec.fieldContext_DCN_node(ctx, field) + case "owner": + return ec.fieldContext_DCN_owner(ctx, field) + case "expiresAt": + return ec.fieldContext_DCN_expiresAt(ctx, field) + case "mintedAt": + return ec.fieldContext_DCN_mintedAt(ctx, field) + case "name": + return ec.fieldContext_DCN_name(ctx, field) + case "vehicle": + return ec.fieldContext_DCN_vehicle(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DCN", field.Name) + }, + } + return fc, nil +} + func (ec *executionContext) _Definition_uri(ctx context.Context, field graphql.CollectedField, obj *model.Definition) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Definition_uri(ctx, field) if err != nil { @@ -5236,20 +5664,85 @@ func (ec *executionContext) fieldContext_Query_dcn(ctx context.Context, field gr IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "node": - return ec.fieldContext_DCN_node(ctx, field) - case "owner": - return ec.fieldContext_DCN_owner(ctx, field) - case "expiresAt": - return ec.fieldContext_DCN_expiresAt(ctx, field) - case "mintedAt": - return ec.fieldContext_DCN_mintedAt(ctx, field) - case "name": - return ec.fieldContext_DCN_name(ctx, field) - case "vehicle": - return ec.fieldContext_DCN_vehicle(ctx, field) + case "node": + return ec.fieldContext_DCN_node(ctx, field) + case "owner": + return ec.fieldContext_DCN_owner(ctx, field) + case "expiresAt": + return ec.fieldContext_DCN_expiresAt(ctx, field) + case "mintedAt": + return ec.fieldContext_DCN_mintedAt(ctx, field) + case "name": + return ec.fieldContext_DCN_name(ctx, field) + case "vehicle": + return ec.fieldContext_DCN_vehicle(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type DCN", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_dcn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_dcns(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_dcns(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Dcns(rctx, fc.Args["first"].(*int), fc.Args["after"].(*string), fc.Args["last"].(*int), fc.Args["before"].(*string), fc.Args["filterBy"].(*model.DCNFilter)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.DCNConnection) + fc.Result = res + return ec.marshalNDCNConnection2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNConnection(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_dcns(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "totalCount": + return ec.fieldContext_DCNConnection_totalCount(ctx, field) + case "edges": + return ec.fieldContext_DCNConnection_edges(ctx, field) + case "nodes": + return ec.fieldContext_DCNConnection_nodes(ctx, field) + case "pageInfo": + return ec.fieldContext_DCNConnection_pageInfo(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type DCN", field.Name) + return nil, fmt.Errorf("no field named %q was found under type DCNConnection", field.Name) }, } defer func() { @@ -5259,7 +5752,7 @@ func (ec *executionContext) fieldContext_Query_dcn(ctx context.Context, field gr } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_dcn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Query_dcns_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } @@ -8646,6 +9139,35 @@ func (ec *executionContext) unmarshalInputDCNBy(ctx context.Context, obj interfa return it, nil } +func (ec *executionContext) unmarshalInputDCNFilter(ctx context.Context, obj interface{}) (model.DCNFilter, error) { + var it model.DCNFilter + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"owner"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "owner": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("owner")) + data, err := ec.unmarshalOAddress2ᚖgithubᚗcomᚋethereumᚋgoᚑethereumᚋcommonᚐAddress(ctx, v) + if err != nil { + return it, err + } + it.Owner = data + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputPrivilegeFilterBy(ctx context.Context, obj interface{}) (model.PrivilegeFilterBy, error) { var it model.PrivilegeFilterBy asMap := map[string]interface{}{} @@ -9189,6 +9711,104 @@ func (ec *executionContext) _DCN(ctx context.Context, sel ast.SelectionSet, obj return out } +var dCNConnectionImplementors = []string{"DCNConnection"} + +func (ec *executionContext) _DCNConnection(ctx context.Context, sel ast.SelectionSet, obj *model.DCNConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dCNConnectionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("DCNConnection") + case "totalCount": + out.Values[i] = ec._DCNConnection_totalCount(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "edges": + out.Values[i] = ec._DCNConnection_edges(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "nodes": + out.Values[i] = ec._DCNConnection_nodes(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "pageInfo": + out.Values[i] = ec._DCNConnection_pageInfo(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var dCNEdgeImplementors = []string{"DCNEdge"} + +func (ec *executionContext) _DCNEdge(ctx context.Context, sel ast.SelectionSet, obj *model.DCNEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, dCNEdgeImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("DCNEdge") + case "cursor": + out.Values[i] = ec._DCNEdge_cursor(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "node": + out.Values[i] = ec._DCNEdge_node(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var definitionImplementors = []string{"Definition"} func (ec *executionContext) _Definition(ctx context.Context, sel ast.SelectionSet, obj *model.Definition) graphql.Marshaler { @@ -9944,6 +10564,28 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "dcns": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_dcns(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "__type": out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { @@ -11003,6 +11645,50 @@ func (ec *executionContext) marshalNDCN2githubᚗcomᚋDIMOᚑNetworkᚋidentity return ec._DCN(ctx, sel, &v) } +func (ec *executionContext) marshalNDCN2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDcnᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Dcn) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNDCN2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDcn(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + func (ec *executionContext) marshalNDCN2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDcn(ctx context.Context, sel ast.SelectionSet, v *model.Dcn) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -11018,6 +11704,74 @@ func (ec *executionContext) unmarshalNDCNBy2githubᚗcomᚋDIMOᚑNetworkᚋiden return res, graphql.ErrorOnPath(ctx, err) } +func (ec *executionContext) marshalNDCNConnection2githubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNConnection(ctx context.Context, sel ast.SelectionSet, v model.DCNConnection) graphql.Marshaler { + return ec._DCNConnection(ctx, sel, &v) +} + +func (ec *executionContext) marshalNDCNConnection2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNConnection(ctx context.Context, sel ast.SelectionSet, v *model.DCNConnection) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._DCNConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalNDCNEdge2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNEdgeᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.DCNEdge) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNDCNEdge2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNEdge(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNDCNEdge2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNEdge(ctx context.Context, sel ast.SelectionSet, v *model.DCNEdge) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._DCNEdge(ctx, sel, v) +} + func (ec *executionContext) marshalNEarning2ᚕᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐEarningᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Earning) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup @@ -11803,6 +12557,14 @@ func (ec *executionContext) marshalODCN2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋident return ec._DCN(ctx, sel, v) } +func (ec *executionContext) unmarshalODCNFilter2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDCNFilter(ctx context.Context, v interface{}) (*model.DCNFilter, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputDCNFilter(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + func (ec *executionContext) marshalODefinition2ᚖgithubᚗcomᚋDIMOᚑNetworkᚋidentityᚑapiᚋgraphᚋmodelᚐDefinition(ctx context.Context, sel ast.SelectionSet, v *model.Definition) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go index c29e3db7..e2b48d1a 100644 --- a/graph/model/models_gen.go +++ b/graph/model/models_gen.go @@ -104,6 +104,23 @@ type DCNBy struct { Name *string `json:"name,omitempty"` } +type DCNConnection struct { + TotalCount int `json:"totalCount"` + Edges []*DCNEdge `json:"edges"` + Nodes []*Dcn `json:"nodes"` + PageInfo *PageInfo `json:"pageInfo"` +} + +type DCNEdge struct { + Cursor string `json:"cursor"` + Node *Dcn `json:"node"` +} + +type DCNFilter struct { + // Filter for DCN owned by this address. + Owner *common.Address `json:"owner,omitempty"` +} + type Definition struct { URI *string `json:"uri,omitempty"` Make *string `json:"make,omitempty"` diff --git a/graph/schema.graphqls b/graph/schema.graphqls index 3edda98b..1ccd64b6 100644 --- a/graph/schema.graphqls +++ b/graph/schema.graphqls @@ -97,6 +97,18 @@ type Query { ): AftermarketDeviceConnection! dcn(by: DCNBy!): DCN! + + """ + List DIMO Canonical Names. + Ordered by mint time, descending. + """ + dcns( + first: Int + after: String + last: Int + before: String + filterBy: DCNFilter + ): DCNConnection! } # Shared Types @@ -373,6 +385,25 @@ type DCN { vehicle: Vehicle } +type DCNEdge { + cursor: String! + node: DCN! +} + +type DCNConnection { + totalCount: Int! + edges: [DCNEdge!]! + nodes: [DCN!]! + pageInfo: PageInfo! +} + +input DCNFilter { + """ + Filter for DCN owned by this address. + """ + owner: Address +} + # Earnings Types type Earnings { diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go index fb8c35b9..f08f631c 100644 --- a/graph/schema.resolvers.go +++ b/graph/schema.resolvers.go @@ -122,6 +122,11 @@ func (r *queryResolver) Dcn(ctx context.Context, by model.DCNBy) (*model.Dcn, er return r.Repo.GetDCN(ctx, by) } +// Dcns is the resolver for the dcns field. +func (r *queryResolver) Dcns(ctx context.Context, first *int, after *string, last *int, before *string, filterBy *model.DCNFilter) (*model.DCNConnection, error) { + return r.Repo.GetDCNs(ctx, first, after, last, before, filterBy) +} + // Manufacturer is the resolver for the manufacturer field. func (r *vehicleResolver) Manufacturer(ctx context.Context, obj *model.Vehicle) (*model.Manufacturer, error) { return loader.GetManufacturerID(ctx, *obj.ManufacturerID) diff --git a/internal/repositories/dcn.go b/internal/repositories/dcn.go index 456898e6..33891f65 100644 --- a/internal/repositories/dcn.go +++ b/internal/repositories/dcn.go @@ -3,14 +3,23 @@ package repositories import ( "context" "errors" + "time" gmodel "github.com/DIMO-Network/identity-api/graph/model" + "github.com/DIMO-Network/identity-api/internal/helpers" "github.com/DIMO-Network/identity-api/models" "github.com/ethereum/go-ethereum/common" "github.com/vektah/gqlparser/v2/gqlerror" "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + "golang.org/x/exp/slices" ) +type DCNCursor struct { + MintedAt time.Time + Node []byte +} + func DCNToAPI(d *models.DCN) *gmodel.Dcn { return &gmodel.Dcn{ Owner: common.BytesToAddress(d.OwnerAddress), @@ -59,3 +68,115 @@ func (r *Repository) GetDCNByName(ctx context.Context, name string) (*gmodel.Dcn return DCNToAPI(dcn), nil } + +var dcnCursorColumnsTuple = "(" + models.DCNColumns.MintedAt + ", " + models.DCNColumns.Node + ")" + +func (r *Repository) GetDCNs(ctx context.Context, first *int, after *string, last *int, before *string, filterBy *gmodel.DCNFilter) (*gmodel.DCNConnection, error) { + var limit int + limit, err := helpers.ValidateFirstLast(first, last, maxPageSize) + if err != nil { + return nil, err + } + + queryMods := []qm.QueryMod{} + if filterBy != nil && filterBy.Owner != nil { + queryMods = append(queryMods, models.DCNWhere.OwnerAddress.EQ(filterBy.Owner.Bytes())) + } + + dcnCount, err := models.DCNS(queryMods...).Count(ctx, r.pdb.DBS().Reader) + if err != nil { + return nil, err + } + + orderBy := " DESC" + if last != nil { + orderBy = " ASC" + } + + queryMods = append(queryMods, + qm.Limit(limit+1), + qm.OrderBy(models.DCNColumns.MintedAt+orderBy+", "+models.DCNColumns.Node+orderBy), + ) + + pHelp := &helpers.PaginationHelper[DCNCursor]{} + if after != nil { + afterT, err := pHelp.DecodeCursor(*after) + if err != nil { + return nil, err + } + queryMods = append(queryMods, + qm.Where(dcnCursorColumnsTuple+" < (?, ?)", afterT.MintedAt, afterT.Node), + ) + } else if before != nil { + beforeT, err := pHelp.DecodeCursor(*before) + if err != nil { + return nil, err + } + queryMods = append(queryMods, + qm.Where(dcnCursorColumnsTuple+" < (?, ?)", beforeT.MintedAt, beforeT.Node), + ) + } + + all, err := models.DCNS(queryMods...).All(ctx, r.pdb.DBS().Reader) + if err != nil { + return nil, err + } + + hasNext := before != nil + hasPrevious := after != nil + + if first != nil && len(all) == limit+1 { + hasNext = true + all = all[:limit] + } else if last != nil && len(all) == limit+1 { + hasPrevious = true + all = all[:limit] + } + + if last != nil { + slices.Reverse(all) + } + + edges := make([]*gmodel.DCNEdge, len(all)) + nodes := make([]*gmodel.Dcn, len(all)) + + for i, dcn := range all { + c, err := pHelp.EncodeCursor(DCNCursor{MintedAt: dcn.MintedAt, Node: dcn.Node}) + if err != nil { + return nil, err + } + edges[i] = &gmodel.DCNEdge{ + Node: &gmodel.Dcn{ + Node: dcn.Node, + Owner: common.Address(dcn.OwnerAddress), + ExpiresAt: &dcn.Expiration.Time, + MintedAt: dcn.MintedAt, + Name: &dcn.Name.String, + VehicleID: &dcn.VehicleID.Int, + }, + Cursor: c, + } + nodes[i] = edges[i].Node + } + + var endCur, startCur *string + + if len(all) != 0 { + startCur = &edges[0].Cursor + endCur = &edges[len(edges)-1].Cursor + } + + res := &gmodel.DCNConnection{ + TotalCount: int(dcnCount), + Edges: edges, + Nodes: nodes, + PageInfo: &gmodel.PageInfo{ + StartCursor: startCur, + EndCursor: endCur, + HasNextPage: hasNext, + HasPreviousPage: hasPrevious, + }, + } + + return res, nil +} diff --git a/internal/repositories/dcn_test.go b/internal/repositories/dcn_test.go index 6ecf9d36..6467de2d 100644 --- a/internal/repositories/dcn_test.go +++ b/internal/repositories/dcn_test.go @@ -4,12 +4,15 @@ import ( "context" "fmt" "testing" + "time" "github.com/DIMO-Network/identity-api/graph/model" "github.com/DIMO-Network/identity-api/internal/config" + "github.com/DIMO-Network/identity-api/internal/helpers" test "github.com/DIMO-Network/identity-api/internal/helpers" "github.com/DIMO-Network/identity-api/models" "github.com/DIMO-Network/shared/db" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/suite" "github.com/testcontainers/testcontainers-go" "github.com/volatiletech/null/v8" @@ -124,3 +127,127 @@ func (o *DCNRepoTestSuite) Test_GetDCNByName_Success() { o.Equal(dcn.Node, node) o.Equal(*dcn.VehicleID, 1) } + +func (o *DCNRepoTestSuite) Test_GetDCNs() { + // Node | Owner | Vehicle ID | Minted At + // --------+-------+------------------------- + // x1 | A | 1 | 2023-11-10 20:46:55 + // x2 | A | 2 | 2023-11-08 20:46:55 + // x3 | B | 3 | 2023-11-08 20:46:55 + _, walletA, err := test.GenerateWallet() + o.NoError(err) + _, walletB, err := test.GenerateWallet() + o.NoError(err) + + mintedAt, err := time.Parse(time.RFC3339, "2023-11-08T20:46:55Z") + o.NoError(err) + + data := []struct { + Owner *common.Address + VehicleID int + MintedAt time.Time + Node []byte + }{ + { + Owner: walletA, + VehicleID: 1, + MintedAt: mintedAt.AddDate(0, 0, 2), + Node: common.LeftPadBytes(common.FromHex("0x1"), 32), + }, + { + Owner: walletA, + VehicleID: 2, + MintedAt: mintedAt, + Node: common.LeftPadBytes(common.FromHex("0x2"), 32), + }, + { + Owner: walletB, + VehicleID: 3, + MintedAt: mintedAt, + Node: common.LeftPadBytes(common.FromHex("0x3"), 32), + }, + } + + for _, d := range data { + veh := models.Vehicle{ + ID: d.VehicleID, + OwnerAddress: d.Owner.Bytes(), + } + err = veh.Insert(o.ctx, o.pdb.DBS().Writer, boil.Infer()) + o.NoError(err) + + dcn := models.DCN{ + Node: d.Node, + OwnerAddress: d.Owner.Bytes(), + VehicleID: null.IntFrom(d.VehicleID), + Name: null.StringFrom(fmt.Sprintf("dcn-%d", d.VehicleID)), + MintedAt: d.MintedAt, + } + + err = dcn.Insert(o.ctx, o.pdb.DBS().Writer.DB, boil.Infer()) + o.NoError(err) + } + + first := 10 + last := 1 + pHelp := &helpers.PaginationHelper[DCNCursor]{} + cursor, err := pHelp.EncodeCursor(DCNCursor{MintedAt: mintedAt.AddDate(0, 0, 2), Node: common.LeftPadBytes(common.FromHex("0x1"), 32)}) + o.NoError(err) + dcnFilter := model.DCNFilter{Owner: walletB} + for _, testCase := range []struct { + Description string + ExpectedResponse struct { + Owner *common.Address + VehicleID int + MintedAt time.Time + Node []byte + } + First *int + Last *int + Cursor *string + Filter *model.DCNFilter + }{ + { + // Node | Owner | Vehicle ID | Minted At + // --------+-------+------------------------- + // x1 | A | 1 | 2023-11-10 20:46:55 + Description: "first record (ordered by default, DESC)", + ExpectedResponse: data[0], + First: &first, + }, + { + // Node | Owner | Vehicle ID | Minted At + // --------+-------+------------------------- + // x2 | A | 2 | 2023-11-08 20:46:55 + Description: "last record (order ASC)", + ExpectedResponse: data[1], + Last: &last, + }, + { + // Node | Owner | Vehicle ID | Minted At + // --------+-------+------------------------- + // x3 | B | 3 | 2023-11-08 20:46:55 + Description: "search after (ordered DESC MintedAt, Node means Token 3 comes before Token 2)", + ExpectedResponse: data[2], + First: &first, + Cursor: &cursor, + }, + { + // Node | Owner | Vehicle ID | Minted At + // --------+-------+------------------------- + // x3 | B | 3 | 2023-11-08 20:46:55 + Description: "filter by owner", + ExpectedResponse: data[2], + First: &first, + Filter: &dcnFilter, + }, + } { + result, err := o.repo.GetDCNs(o.ctx, testCase.First, testCase.Cursor, testCase.Last, nil, testCase.Filter) + o.NoError(err) + + o.Equal(testCase.ExpectedResponse.Owner.Bytes(), result.Nodes[0].Owner.Bytes()) + o.Equal(testCase.ExpectedResponse.Node, result.Nodes[0].Node) + o.Equal(testCase.ExpectedResponse.VehicleID, *result.Nodes[0].VehicleID) + o.Equal(testCase.ExpectedResponse.MintedAt, result.Nodes[0].MintedAt) + } +}