dictyBase/modware-user

View on GitHub
server/role.go

Summary

Maintainability
F
1 wk
Test Coverage
package server

import (
    "context"
    "fmt"

    "google.golang.org/grpc"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/metadata"
    "google.golang.org/grpc/status"

    "github.com/dictyBase/apihelpers/aphgrpc"
    "github.com/dictyBase/go-genproto/dictybaseapis/api/jsonapi"
    "github.com/dictyBase/go-genproto/dictybaseapis/user"
    "github.com/fatih/structs"
    "github.com/golang/protobuf/ptypes"
    "github.com/golang/protobuf/ptypes/any"
    "github.com/golang/protobuf/ptypes/empty"
    dat "gopkg.in/mgutz/dat.v2/dat"
    runner "gopkg.in/mgutz/dat.v2/sqlx-runner"
)

const (
    roleDbTable    = "auth_role"
    roleDbTblAlias = "auth_role role"
)

var roleCols = []string{"auth_role_id", "role", "created_at", "updated_at"}

type dbRole struct {
    AuthRoleId  int64        `db:"auth_role_id"`
    Role        string       `db:"role"`
    Description string       `db:"description"`
    CreatedAt   dat.NullTime `db:"created_at"`
    UpdatedAt   dat.NullTime `db:"updated_at"`
}

type RoleService struct {
    *aphgrpc.Service
}

func roleServiceOptions() *aphgrpc.ServiceOptions {
    return &aphgrpc.ServiceOptions{
        Resource:   "roles",
        PathPrefix: "roles",
        Include:    []string{"users", "permissions"},
        FilToColumns: map[string]string{
            "role":        "role.role",
            "description": "role.description",
        },
        FieldsToColumns: map[string]string{
            "role":        "role.role",
            "description": "role.description",
            "created_at":  "role.created_at",
            "updated_at":  "role.updated_at",
        },
        ReqAttrs: []string{"Role"},
    }
}

func NewRoleService(dbh *runner.DB, opt ...aphgrpc.Option) *RoleService {
    so := roleServiceOptions()
    for _, optfn := range opt {
        optfn(so)
    }
    srv := &aphgrpc.Service{Dbh: dbh}
    aphgrpc.AssignFieldsToStructs(so, srv)
    return &RoleService{srv}
}

func (s *RoleService) GetRole(ctx context.Context, r *jsonapi.GetRequest) (*user.Role, error) {
    params, md, err := aphgrpc.ValidateAndParseGetParams(s, r)
    if err != nil {
        grpc.SetTrailer(ctx, md)
        return &user.Role{}, status.Error(codes.InvalidArgument, err.Error())
    }
    gctx := aphgrpc.GetReqCtx(params, r)
    switch {
    case params.HasFields && params.HasInclude:
        role, err := s.getResourceWithSelectedAttr(gctx, r.Id)
        if err != nil {
            return &user.Role{}, aphgrpc.HandleError(ctx, err)
        }
        err = s.buildResourceRelationships(gctx, r.Id, role)
        if err != nil {
            return &user.Role{}, aphgrpc.HandleError(ctx, err)
        }
        return role, nil
    case params.HasFields:
        role, err := s.getResourceWithSelectedAttr(gctx, r.Id)
        if err != nil {
            return &user.Role{}, aphgrpc.HandleError(ctx, err)
        }
        return role, nil
    case params.HasInclude:
        role, err := s.getResource(gctx, r.Id)
        if err != nil {
            return &user.Role{}, aphgrpc.HandleError(ctx, err)
        }
        err = s.buildResourceRelationships(gctx, r.Id, role)
        if err != nil {
            return &user.Role{}, aphgrpc.HandleError(ctx, err)
        }
        return role, nil
    default:
        role, err := s.getResource(gctx, r.Id)
        if err != nil {
            return &user.Role{}, aphgrpc.HandleError(ctx, err)
        }
        return role, nil
    }
}

func (s *RoleService) GetRelatedUsers(ctx context.Context, r *jsonapi.RelationshipRequestWithPagination) (*user.UserCollection, error) {
    // For pagination based data retreival
    // 1. Get count of all rows
    count, err := s.getRelatedUsersCount(r.Id)
    if err != nil {
        return &user.UserCollection{}, aphgrpc.HandleError(ctx, err)
    }
    // 2. Has pagination query paramters
    var pagenum, pagesize int64
    if aphgrpc.HasRelatedPagination(r) {
        if r.Pagenum == 0 {
            pagenum = aphgrpc.DefaultPagenum
        } else if r.Pagesize == 0 {
            pagesize = aphgrpc.DefaultPagesize
        } else {
            pagenum = r.Pagenum
            pagesize = r.Pagesize
        }
        // 3. Without any pagination parameters(use default page parameters)
    } else {
        pagenum = aphgrpc.DefaultPagenum
        pagesize = aphgrpc.DefaultPagesize
    }
    udata, err := s.getUserResourceDataWithPagination(r.Id, pagenum, pagesize)
    if err != nil {
        return &user.UserCollection{}, aphgrpc.HandleError(ctx, err)
    }
    pageLinks, pages := s.GetRelatedPagination(r.Id, count, pagenum, pagesize, "users")
    return &user.UserCollection{
        Data:  udata,
        Links: pageLinks,
        Meta: &jsonapi.Meta{
            Pagination: &jsonapi.Pagination{
                Records: count,
                Total:   pages,
                Size:    pagesize,
                Number:  pagenum,
            },
        },
    }, nil
}

func (s *RoleService) GetRelatedPermissions(ctx context.Context, r *jsonapi.RelationshipRequest) (*user.PermissionCollection, error) {
    pdata, err := s.getPermissionResourceData(r.Id)
    if err != nil {
        return &user.PermissionCollection{}, aphgrpc.HandleError(ctx, err)
    }
    return &user.PermissionCollection{
        Data: pdata,
        Links: &jsonapi.Links{
            Self: s.GenCollResourceRelSelfLink(r.Id, "permissions"),
        },
    }, nil
}

func (s *RoleService) ListRoles(ctx context.Context, r *jsonapi.SimpleListRequest) (*user.RoleCollection, error) {
    params, md, err := aphgrpc.ValidateAndParseSimpleListParams(s, r)
    if err != nil {
        grpc.SetTrailer(ctx, md)
        return &user.RoleCollection{}, status.Error(codes.InvalidArgument, err.Error())
    }
    lctx := aphgrpc.ListReqCtx(
        params,
        &jsonapi.ListRequest{
            Fields:  r.Fields,
            Filter:  r.Filter,
            Include: r.Include,
        })
    // request without any pagination query parameters
    switch {
    case params.HasFields && params.HasFilter && params.HasInclude:
        dbRoles, err := s.getAllSelectedFilteredRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        r, err := s.dbToCollResourceWithRel(lctx, dbRoles)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return r, nil
    case params.HasFields && params.HasFilter:
        dbRoles, err := s.getAllSelectedFilteredRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return s.dbToCollResource(lctx, dbRoles), nil
    case params.HasFields && params.HasInclude:
        dbRoles, err := s.getAllSelectedRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        r, err := s.dbToCollResourceWithRel(lctx, dbRoles)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return r, nil
    case params.HasFilter && params.HasInclude:
        dbRoles, err := s.getAllFilteredRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        r, err := s.dbToCollResourceWithRel(lctx, dbRoles)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return r, nil
    case params.HasFields:
        dbRoles, err := s.getAllSelectedRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return s.dbToCollResource(lctx, dbRoles), nil
    case params.HasFilter:
        dbRoles, err := s.getAllFilteredRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return s.dbToCollResource(lctx, dbRoles), nil
    case params.HasInclude:
        dbRoles, err := s.getAllRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        r, err := s.dbToCollResourceWithRel(lctx, dbRoles)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return r, nil
    default:
        dbRoles, err := s.getAllRows(lctx)
        if err != nil {
            return &user.RoleCollection{}, aphgrpc.HandleError(ctx, err)
        }
        return s.dbToCollResource(lctx, dbRoles), nil
    }
}

func (s *RoleService) CreateRole(ctx context.Context, r *user.CreateRoleRequest) (*user.Role, error) {
    dbrole := s.attrTodbRole(r.Data.Attributes)
    rcolumns := aphgrpc.GetDefinedTags(dbrole, "db")
    if len(rcolumns) > 0 {
        err := s.Dbh.InsertInto("auth_role").
            Columns(rcolumns...).
            Record(dbrole).
            Returning(roleCols...).
            QueryStruct(dbrole)
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseInsert)
            return &user.Role{}, status.Error(codes.Internal, err.Error())
        }
    }
    roleId := dbrole.AuthRoleId
    rstruct := structs.New(r).Field("Data").Field("Relationships")
    if !rstruct.IsZero() {
        if !rstruct.Field("Users").IsZero() {
            for _, u := range r.Data.Relationships.Users.Data {
                _, err := s.Dbh.InsertInto("auth_user_role").
                    Columns("auth_user_id", "auth_role_id").
                    Values(u.Id, roleId).Exec()
                if err != nil {
                    grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseInsert)
                    return &user.Role{}, status.Error(codes.Internal, err.Error())
                }
            }
        }
        if !rstruct.Field("Permissions").IsZero() {
            for _, p := range r.Data.Relationships.Permissions.Data {
                _, err := s.Dbh.InsertInto("auth_role_permission").
                    Columns("auth_role_id", "auth_permission_id").
                    Values(roleId, p.Id).Exec()
                if err != nil {
                    grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseInsert)
                    return &user.Role{}, status.Error(codes.Internal, err.Error())
                }
            }
        }
    }
    grpc.SetTrailer(ctx, metadata.Pairs("method", "POST"))
    return s.buildResource(context.TODO(), roleId, s.dbToResourceAttributes(dbrole)), nil
}

func (s *RoleService) CreateUserRelationship(ctx context.Context, r *jsonapi.DataCollection) (*empty.Empty, error) {
    if len(r.Data) == 0 {
        return &empty.Empty{}, aphgrpc.HandleInsertArgError(ctx, fmt.Errorf("no id given"))
    }
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &empty.Empty{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &empty.Empty{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    for _, ud := range r.Data {
        res, err := s.Dbh.Select("aurole.auth_user_role_id").
            From("auth_user_role aurole").
            Where("aurole.auth_role_id = $1 AND aurole.auth_user_role_id = $2", r.Id, ud.Id).
            Exec()
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseInsert)
            return &empty.Empty{}, status.Error(codes.Internal, err.Error())
        }
        if res.RowsAffected != 1 {
            _, err := s.Dbh.InsertInto("auth_user_role").
                Columns("auth_role_id", "auth_user_id").
                Values(r.Id, ud.Id).Exec()
            if err != nil {
                grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseInsert)
                return &empty.Empty{}, status.Error(codes.Internal, err.Error())

            }
        } else {
            return &empty.Empty{},
                aphgrpc.HandleExistError(
                    ctx,
                    fmt.Errorf("relationship with given id %d already exists", ud.Id),
                )
        }
    }
    grpc.SetTrailer(ctx, metadata.Pairs("method", "POST_NO_CONTENT"))
    return &empty.Empty{}, nil
}

func (s *RoleService) CreatePermissionRelationship(ctx context.Context, r *jsonapi.DataCollection) (*empty.Empty, error) {
    if len(r.Data) == 0 {
        return &empty.Empty{}, aphgrpc.HandleInsertArgError(ctx, fmt.Errorf("no id given"))
    }
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &empty.Empty{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &empty.Empty{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    for _, pd := range r.Data {
        res, err := s.Dbh.Select("auth_role_permission.auth_role_permission_id").
            From("auth_role_permission").
            Where("auth_role_permission.auth_role_id = $1 AND auth_role_permission.auth_permission_id = $2", r.Id, pd.Id).
            Exec()
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseInsert)
            return &empty.Empty{}, status.Error(codes.Internal, err.Error())
        }
        if res.RowsAffected != 1 {
            _, err := s.Dbh.InsertInto("auth_role_permission").
                Columns("auth_role_id", "auth_permission_id").
                Values(r.Id, pd.Id).Exec()
            if err != nil {
                grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseInsert)
                return &empty.Empty{}, status.Error(codes.Internal, err.Error())

            }
        } else {
            return &empty.Empty{},
                aphgrpc.HandleExistError(
                    ctx,
                    fmt.Errorf("relationship with given id %d already exists", pd.Id),
                )
        }

    }
    grpc.SetTrailer(ctx, metadata.Pairs("method", "POST_NO_CONTENT"))
    return &empty.Empty{}, nil
}

func (s *RoleService) UpdateRole(ctx context.Context, r *user.UpdateRoleRequest) (*user.Role, error) {
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &user.Role{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &user.Role{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    dbrole := s.attrTodbRole(r.Data.Attributes)
    rmap := aphgrpc.GetDefinedTagsWithValue(dbrole, "db")
    if len(rmap) > 0 {
        err := s.Dbh.Update(roleDbTable).SetMap(rmap).
            Where("auth_role_id = $1", r.Data.Id).Returning(roleCols...).
            QueryStruct(dbrole)
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseUpdate)
            return &user.Role{}, status.Error(codes.Internal, err.Error())
        }
    }
    rstruct := structs.New(r).Field("Data").Field("Relationships")
    if !rstruct.IsZero() {
        if !rstruct.Field("Users").IsZero() {
            for _, u := range r.Data.Relationships.Users.Data {
                _, err := s.Dbh.Update("auth_user_role").
                    Set("auth_user_id", u.Id).
                    Where("auth_role_id = $1", r.Data.Id).Exec()
                if err != nil {
                    grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseUpdate)
                    return &user.Role{}, status.Error(codes.Internal, err.Error())
                }
            }
        }
        if !rstruct.Field("Permissions").IsZero() {
            for _, p := range r.Data.Relationships.Permissions.Data {
                _, err := s.Dbh.Update("auth_role_permission").
                    Set("auth_permission_id", p.Id).
                    Where("auth_role_id = $1", r.Data.Id).Exec()
                if err != nil {
                    grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseUpdate)
                    return &user.Role{}, status.Error(codes.Internal, err.Error())
                }
            }
        }
    }
    return s.buildResource(context.TODO(), dbrole.AuthRoleId, s.dbToResourceAttributes(dbrole)), nil
}

func (s *RoleService) UpdateUserRelationship(ctx context.Context, r *jsonapi.DataCollection) (*empty.Empty, error) {
    if len(r.Data) == 0 {
        return &empty.Empty{}, aphgrpc.HandleInsertArgError(ctx, fmt.Errorf("no id given"))
    }
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &empty.Empty{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &empty.Empty{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    _, err = s.Dbh.DeleteFrom("auth_user_role").
        Where("auth_user_role.auth_role_id = $1", r.Id).
        Exec()
    if err != nil {
        grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseUpdate)
        return &empty.Empty{}, status.Error(codes.Internal, err.Error())
    }
    for _, ud := range r.Data {
        _, err := s.Dbh.InsertInto("auth_user_role").
            Columns("auth_role_id", "auth_user_id").
            Values(r.Id, ud.Id).Exec()
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseUpdate)
            return &empty.Empty{}, status.Error(codes.Internal, err.Error())
        }
    }
    return &empty.Empty{}, nil
}

func (s *RoleService) UpdatePermissionRelationship(ctx context.Context, r *jsonapi.DataCollection) (*empty.Empty, error) {
    if len(r.Data) == 0 {
        return &empty.Empty{}, aphgrpc.HandleInsertArgError(ctx, fmt.Errorf("no id given"))
    }
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &empty.Empty{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &empty.Empty{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    _, err = s.Dbh.DeleteFrom("auth_role_permission").
        Where("auth_role_permission.auth_role_id = $1", r.Id).
        Exec()
    if err != nil {
        grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseUpdate)
        return &empty.Empty{}, status.Error(codes.Internal, err.Error())
    }
    for _, pd := range r.Data {
        _, err := s.Dbh.InsertInto("auth_role_permission").
            Columns("auth_role_id", "auth_permission_id").
            Values(r.Id, pd.Id).Exec()
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseUpdate)
            return &empty.Empty{}, status.Error(codes.Internal, err.Error())
        }
    }
    return &empty.Empty{}, nil
}

func (s *RoleService) DeleteRole(ctx context.Context, r *jsonapi.DeleteRequest) (*empty.Empty, error) {
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &empty.Empty{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &empty.Empty{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    _, err = s.Dbh.DeleteFrom(roleDbTable).Where("auth_role_id = $1", r.Id).Exec()
    if err != nil {
        grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseDelete)
        return &empty.Empty{}, status.Error(codes.Internal, err.Error())
    }
    return &empty.Empty{}, nil
}

func (s *RoleService) DeleteUserRelationship(ctx context.Context, r *jsonapi.DataCollection) (*empty.Empty, error) {
    if len(r.Data) == 0 {
        return &empty.Empty{}, aphgrpc.HandleInsertArgError(ctx, fmt.Errorf("no id given"))
    }
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &empty.Empty{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &empty.Empty{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    for _, ud := range r.Data {
        _, err := s.Dbh.DeleteFrom("auth_user_role").
            Where("auth_user_role.auth_role_id = $1 AND auth_user_role.auth_user_id = $2", r.Id, ud.Id).
            Exec()
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseDelete)
            return &empty.Empty{}, status.Error(codes.Internal, err.Error())
        }
    }
    return &empty.Empty{}, nil
}

func (s *RoleService) DeletePermissionRelationship(ctx context.Context, r *jsonapi.DataCollection) (*empty.Empty, error) {
    if len(r.Data) == 0 {
        return &empty.Empty{}, aphgrpc.HandleInsertArgError(ctx, fmt.Errorf("no id given"))
    }
    result, err := s.existsResource(r.Id)
    if err != nil {
        return &empty.Empty{}, aphgrpc.HandleError(ctx, err)
    }
    if !result {
        grpc.SetTrailer(ctx, aphgrpc.ErrNotFound)
        return &empty.Empty{}, status.Error(codes.NotFound, fmt.Sprintf("id %d not found", r.Id))
    }
    for _, pd := range r.Data {
        _, err := s.Dbh.DeleteFrom("auth_role_permission").
            Where("auth_role_permission.auth_role_id = $1 AND auth_role_permission.auth_permission_id = $2", r.Id, pd.Id).
            Exec()
        if err != nil {
            grpc.SetTrailer(ctx, aphgrpc.ErrDatabaseDelete)
            return &empty.Empty{}, status.Error(codes.Internal, err.Error())
        }
    }
    return &empty.Empty{}, nil
}

func (s *RoleService) existsResource(id int64) (bool, error) {
    r, err := s.Dbh.Select("auth_role_id").From("auth_role").
        Where("auth_role_id = $1", id).Exec()
    if err != nil {
        return false, err
    }
    if r.RowsAffected != 1 {
        return false, nil
    }
    return true, nil
}

func (s *RoleService) getResourceWithSelectedAttr(ctx context.Context, id int64) (*user.Role, error) {
    drole := &dbRole{}
    params, ok := ctx.Value(aphgrpc.ContextKeyParams).(*aphgrpc.JSONAPIParams)
    if !ok {
        return &user.Role{}, fmt.Errorf("no params object found in context")
    }
    columns := s.MapFieldsToColumns(params.Fields)
    err := s.Dbh.Select(columns...).From(roleDbTblAlias).
        Where("role.auth_role_id = $1", id).QueryStruct(drole)
    if err != nil {
        return &user.Role{}, err
    }
    return s.buildResource(ctx, id, s.dbToResourceAttributes(drole)), nil
}

func (s *RoleService) getResource(ctx context.Context, id int64) (*user.Role, error) {
    drole := &dbRole{}
    err := s.Dbh.Select("role.*").
        From(roleDbTblAlias).
        Where("role.auth_role_id = $1", id).
        QueryStruct(drole)
    if err != nil {
        return &user.Role{}, err
    }
    return s.buildResource(ctx, id, s.dbToResourceAttributes(drole)), nil
}

func (s *RoleService) getAllRows(ctx context.Context) ([]*dbRole, error) {
    var dbrows []*dbRole
    err := s.Dbh.Select("role.*").
        From(roleDbTblAlias).
        QueryStructs(&dbrows)
    return dbrows, err
}

func (s *RoleService) getAllSelectedRows(ctx context.Context) ([]*dbRole, error) {
    var dbrows []*dbRole
    params, ok := ctx.Value(aphgrpc.ContextKeyParams).(*aphgrpc.JSONAPIParams)
    if !ok {
        return dbrows, fmt.Errorf("no params object found in context")
    }
    columns := s.MapFieldsToColumns(params.Fields)
    err := s.Dbh.Select(columns...).
        From(roleDbTblAlias).
        QueryStructs(&dbrows)
    return dbrows, err
}

func (s *RoleService) getAllFilteredRows(ctx context.Context) ([]*dbRole, error) {
    var dbrows []*dbRole
    params, ok := ctx.Value(aphgrpc.ContextKeyParams).(*aphgrpc.JSONAPIParams)
    if !ok {
        return dbrows, fmt.Errorf("no params object found in context")
    }
    err := s.Dbh.Select("role.*").
        From(roleDbTblAlias).
        Scope(
            aphgrpc.FilterToWhereClause(s, params.Filters),
            aphgrpc.FilterToBindValue(params.Filters)...,
        ).
        QueryStructs(&dbrows)
    return dbrows, err
}

func (s *RoleService) getAllSelectedFilteredRows(ctx context.Context) ([]*dbRole, error) {
    var dbrows []*dbRole
    params, ok := ctx.Value(aphgrpc.ContextKeyParams).(*aphgrpc.JSONAPIParams)
    if !ok {
        return dbrows, fmt.Errorf("no params object found in context")
    }
    columns := s.MapFieldsToColumns(params.Fields)
    err := s.Dbh.Select(columns...).
        From(roleDbTblAlias).
        Scope(
            aphgrpc.FilterToWhereClause(s, params.Filters),
            aphgrpc.FilterToBindValue(params.Filters)...,
        ).
        QueryStructs(&dbrows)
    return dbrows, err
}

func (s *RoleService) getPermissionResourceData(id int64) ([]*user.PermissionData, error) {
    var dbrows []*dbPermission
    var pdata []*user.PermissionData
    err := s.Dbh.Select("perm.*").From(`
            auth_role_permission
            JOIN auth_permission perm
            ON auth_role_permission.auth_permission_id = perm.auth_permission_id
        `).Where("auth_role_permission.auth_role_id = $1", id).QueryStructs(&dbrows)
    if err != nil {
        return pdata, err
    }
    return NewPermissionService(
        s.Dbh,
    ).dbToCollResourceData(context.TODO(), dbrows), nil
}

func (s *RoleService) getRelatedUsersCount(id int64) (int64, error) {
    var count int64
    err := s.Dbh.Select("COUNT(*)").From(`
        auth_user_role
        JOIN auth_user
        ON auth_user_role.auth_user_id = auth_user.auth_user_id
        JOIN auth_user_info
        ON auth_user_info.auth_user_id = auth_user.auth_user_id
        `).Where("auth_user_role.auth_role_id = $1", id).QueryScalar(&count)
    return count, err
}

func (s *RoleService) getUserResourceData(id int64) ([]*user.UserData, error) {
    var dbrows []*dbUser
    var udata []*user.UserData
    err := s.Dbh.SQL(`
            SELECT
                auth_user.auth_user_id,
                CAST(auth_user.email AS TEXT),
                auth_user.first_name,
                auth_user.last_name,
                auth_user.is_active,
                auth_user.created_at,
                auth_user.updated_at,
                uinfo.*
                FROM auth_user_role
                JOIN auth_user
                ON auth_user_role.auth_user_id = auth_user.auth_user_id
                JOIN auth_user_info uinfo
                ON uinfo.auth_user_id = auth_user.auth_user_id
                WHERE auth_user_role.auth_role_id = $1`, id).
        QueryStructs(&dbrows)
    if err != nil {
        return udata, err
    }
    return NewUserService(
        s.Dbh,
    ).dbToCollResourceData(context.TODO(), dbrows), nil
}

func (s *RoleService) getUserResourceDataWithPagination(id, pagenum, pagesize int64) ([]*user.UserData, error) {
    var dbrows []*dbUser
    var udata []*user.UserData
    err := s.Dbh.SQL(
        fmt.Sprintf(
            "%s LIMIT %d OFFSET %d",
            `SELECT auth_user.auth_user_id,
                CAST(auth_user.email AS TEXT),
                auth_user.first_name,
                auth_user.last_name,
                auth_user.is_active,
                auth_user_info.*
                FROM auth_user_role
                JOIN auth_user
                ON auth_user_role.auth_user_id = auth_user.auth_user_id
                JOIN auth_user_info
                ON auth_user_info.auth_user_id = auth_user.auth_user_id
                WHERE auth_user_role.auth_role_id = $1`,
            pagesize,
            (pagenum-1)*pagesize,
        ), id).QueryStructs(&dbrows)
    if err != nil {
        return udata, err
    }
    return NewUserService(
        s.Dbh,
    ).dbToCollResourceData(context.TODO(), dbrows), nil
}

func (s *RoleService) buildUserResourceIdentifiers(users []*user.UserData) []*jsonapi.Data {
    jdata := make([]*jsonapi.Data, len(users))
    for i, r := range users {
        jdata[i] = &jsonapi.Data{
            Type: r.Type,
            Id:   r.Id,
        }
    }
    return jdata
}

func (s *RoleService) buildPermissionResourceIdentifiers(perms []*user.PermissionData) []*jsonapi.Data {
    jdata := make([]*jsonapi.Data, len(perms))
    for i, r := range perms {
        jdata[i] = &jsonapi.Data{
            Type: r.Type,
            Id:   r.Id,
        }
    }
    return jdata
}

func (s *RoleService) buildResourceData(ctx context.Context, id int64, attr *user.RoleAttributes) *user.RoleData {
    return &user.RoleData{
        Type:       s.GetResourceName(),
        Id:         id,
        Attributes: attr,
        Relationships: &user.ExistingRoleRelationships{
            Users: &user.ExistingRoleRelationships_Users{
                Links: &jsonapi.Links{
                    Self:    aphgrpc.GenSelfRelationshipLink(s, "users", id),
                    Related: aphgrpc.GenRelatedRelationshipLink(s, "users", id),
                },
            },
            Permissions: &user.ExistingRoleRelationships_Permissions{
                Links: &jsonapi.Links{
                    Self:    aphgrpc.GenSelfRelationshipLink(s, "permissions", id),
                    Related: aphgrpc.GenRelatedRelationshipLink(s, "permissions", id),
                },
            },
        },
        Links: &jsonapi.Links{
            Self: s.GenResourceSelfLink(ctx, id),
        },
    }
}

func (s *RoleService) buildResource(ctx context.Context, id int64, attr *user.RoleAttributes) *user.Role {
    return &user.Role{
        Data: s.buildResourceData(ctx, id, attr),
        Links: &jsonapi.Links{
            Self: s.GenResourceSelfLink(ctx, id),
        },
    }
}

func (s *RoleService) buildResourceRelationships(ctx context.Context, id int64, role *user.Role) error {
    params, ok := ctx.Value(aphgrpc.ContextKeyParams).(*aphgrpc.JSONAPIParams)
    if !ok {
        return fmt.Errorf("no params object found in context")
    }
    var allInc []*any.Any
    for _, inc := range params.Includes {
        switch inc {
        case "users":
            users, err := s.getUserResourceData(id)
            if err != nil {
                return err
            }
            // included relationships
            incUsers, err := NewUserService(s.Dbh).convertAllToAny(users)
            if err != nil {
                return err
            }
            allInc = append(allInc, incUsers...)
            role.Data.Relationships.Users.Data = s.buildUserResourceIdentifiers(users)
        case "permissions":
            perms, err := s.getPermissionResourceData(id)
            if err != nil {
                return err
            }
            incPerms, err := NewPermissionService(s.Dbh).convertAllToAny(perms)
            if err != nil {
                return err
            }
            allInc = append(allInc, incPerms...)
            role.Data.Relationships.Permissions.Data = s.buildPermissionResourceIdentifiers(perms)
        }
        role.Included = allInc
    }
    return nil
}

func (s *RoleService) dbToResourceAttributes(r *dbRole) *user.RoleAttributes {
    return &user.RoleAttributes{
        Role:        r.Role,
        Description: r.Description,
        CreatedAt:   aphgrpc.NullToTime(r.CreatedAt),
        UpdatedAt:   aphgrpc.NullToTime(r.UpdatedAt),
    }
}

func (s *RoleService) dbToCollResourceData(ctx context.Context, dbrows []*dbRole) []*user.RoleData {
    var rdata []*user.RoleData
    for _, r := range dbrows {
        rdata = append(rdata, s.buildResourceData(ctx, r.AuthRoleId, s.dbToResourceAttributes(r)))
    }
    return rdata
}

func (s *RoleService) dbToCollResource(ctx context.Context, dbrows []*dbRole) *user.RoleCollection {
    return &user.RoleCollection{
        Data: s.dbToCollResourceData(ctx, dbrows),
        Links: &jsonapi.Links{
            Self: s.GenCollResourceSelfLink(ctx),
        },
    }
}

func (s *RoleService) dbToCollResourceWithRel(ctx context.Context, dbrows []*dbRole) (*user.RoleCollection, error) {
    params, ok := ctx.Value(aphgrpc.ContextKeyParams).(*aphgrpc.JSONAPIParams)
    if !ok {
        return &user.RoleCollection{}, fmt.Errorf("no params object found in context")
    }
    rdata := s.dbToCollResourceData(ctx, dbrows)
    var allInc []*any.Any
    // related users
    for _, inc := range params.Includes {
        switch inc {
        case "users":
            var users []*user.UserData
            for i, _ := range rdata {
                u, err := s.getUserResourceData(dbrows[i].AuthRoleId)
                if err != nil {
                    return &user.RoleCollection{}, err
                }
                rdata[i].Relationships.Users.Data = s.buildUserResourceIdentifiers(u)
                users = append(users, u...)
            }
            incUsers, err := NewUserService(s.Dbh).convertAllToAny(users)
            if err != nil {
                return &user.RoleCollection{}, err
            }
            allInc = append(allInc, incUsers...)
        case "permissions":
            var perms []*user.PermissionData
            for i, _ := range rdata {
                p, err := s.getPermissionResourceData(dbrows[i].AuthRoleId)
                if err != nil {
                    return &user.RoleCollection{}, err
                }
                rdata[i].Relationships.Permissions.Data = s.buildPermissionResourceIdentifiers(p)
                perms = append(perms, p...)
            }
            incPerms, err := NewPermissionService(s.Dbh).convertAllToAny(perms)
            if err != nil {
                return &user.RoleCollection{}, err
            }
            allInc = append(allInc, incPerms...)
        }
    }
    return &user.RoleCollection{
        Data: rdata,
        Links: &jsonapi.Links{
            Self: s.GenCollResourceSelfLink(ctx),
        },
        Included: allInc,
    }, nil
}

func (s *RoleService) attrTodbRole(attr *user.RoleAttributes) *dbRole {
    return &dbRole{
        Role:        attr.Role,
        Description: attr.Description,
        CreatedAt:   dat.NullTimeFrom(aphgrpc.ProtoTimeStamp(attr.CreatedAt)),
        UpdatedAt:   dat.NullTimeFrom(aphgrpc.ProtoTimeStamp(attr.UpdatedAt)),
    }
}

func (s *RoleService) convertAllToAny(roles []*user.RoleData) ([]*any.Any, error) {
    aslice := make([]*any.Any, len(roles))
    for i, r := range roles {
        pkg, err := ptypes.MarshalAny(r)
        if err != nil {
            return aslice, err
        }
        aslice[i] = pkg
    }
    return aslice, nil
}