sysRolePermModel.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package roleperm
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "strings"
  7. "github.com/zeromicro/go-zero/core/stores/cache"
  8. "github.com/zeromicro/go-zero/core/stores/sqlx"
  9. )
  10. var _ SysRolePermModel = (*customSysRolePermModel)(nil)
  11. type (
  12. SysRolePermModel interface {
  13. sysRolePermModel
  14. FindPermIdsByRoleId(ctx context.Context, roleId int64) ([]int64, error)
  15. FindPermIdsByRoleIds(ctx context.Context, roleIds []int64) ([]int64, error)
  16. // FindPermIdsByRoleIdTx 是 FindPermIdsByRoleId 的事务内变体:上游 BindRolePerms 在
  17. // LockByIdTx(role) 之后,需要在同一事务里读取当前 existing permIds 再做 diff,否则
  18. // "existing 读-外部 / diff 写-内部" 的窗口会产生第三态(见审计 M-R10-2)。
  19. FindPermIdsByRoleIdTx(ctx context.Context, session sqlx.Session, roleId int64) ([]int64, error)
  20. DeleteByRoleIdTx(ctx context.Context, session sqlx.Session, roleId int64) error
  21. DeleteByRoleIdAndPermIdsTx(ctx context.Context, session sqlx.Session, roleId int64, permIds []int64) error
  22. }
  23. customSysRolePermModel struct {
  24. *defaultSysRolePermModel
  25. }
  26. )
  27. func NewSysRolePermModel(conn sqlx.SqlConn, c cache.CacheConf, cachePrefix string, opts ...cache.Option) SysRolePermModel {
  28. return &customSysRolePermModel{
  29. defaultSysRolePermModel: newSysRolePermModel(conn, c, cachePrefix, opts...),
  30. }
  31. }
  32. func (m *customSysRolePermModel) FindPermIdsByRoleId(ctx context.Context, roleId int64) ([]int64, error) {
  33. var ids []int64
  34. query := fmt.Sprintf("SELECT `permId` FROM %s WHERE `roleId` = ?", m.table)
  35. if err := m.QueryRowsNoCacheCtx(ctx, &ids, query, roleId); err != nil {
  36. return nil, err
  37. }
  38. return ids, nil
  39. }
  40. func (m *customSysRolePermModel) FindPermIdsByRoleIdTx(ctx context.Context, session sqlx.Session, roleId int64) ([]int64, error) {
  41. var ids []int64
  42. query := fmt.Sprintf("SELECT `permId` FROM %s WHERE `roleId` = ?", m.table)
  43. if err := session.QueryRowsCtx(ctx, &ids, query, roleId); err != nil {
  44. return nil, err
  45. }
  46. return ids, nil
  47. }
  48. func (m *customSysRolePermModel) FindPermIdsByRoleIds(ctx context.Context, roleIds []int64) ([]int64, error) {
  49. if len(roleIds) == 0 {
  50. return nil, nil
  51. }
  52. placeholders := make([]string, len(roleIds))
  53. args := make([]interface{}, len(roleIds))
  54. for i, id := range roleIds {
  55. placeholders[i] = "?"
  56. args[i] = id
  57. }
  58. var ids []int64
  59. query := fmt.Sprintf("SELECT DISTINCT `permId` FROM %s WHERE `roleId` IN (%s)", m.table, strings.Join(placeholders, ","))
  60. if err := m.QueryRowsNoCacheCtx(ctx, &ids, query, args...); err != nil {
  61. return nil, err
  62. }
  63. return ids, nil
  64. }
  65. func (m *customSysRolePermModel) buildCacheKeys(list []*SysRolePerm) []string {
  66. keys := make([]string, 0, len(list)*2)
  67. for _, data := range list {
  68. keys = append(keys,
  69. fmt.Sprintf("%s%v", cacheSysRolePermIdPrefix, data.Id),
  70. fmt.Sprintf("%s%v:%v", cacheSysRolePermRoleIdPermIdPrefix, data.RoleId, data.PermId),
  71. )
  72. }
  73. return keys
  74. }
  75. func (m *customSysRolePermModel) DeleteByRoleIdTx(ctx context.Context, session sqlx.Session, roleId int64) error {
  76. var list []*SysRolePerm
  77. findQuery := fmt.Sprintf("SELECT %s FROM %s WHERE `roleId` = ? FOR UPDATE", sysRolePermRows, m.table)
  78. if err := session.QueryRowsCtx(ctx, &list, findQuery, roleId); err != nil {
  79. return err
  80. }
  81. if len(list) == 0 {
  82. return nil
  83. }
  84. keys := m.buildCacheKeys(list)
  85. _, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (sql.Result, error) {
  86. query := fmt.Sprintf("DELETE FROM %s WHERE `roleId` = ?", m.table)
  87. return session.ExecCtx(ctx, query, roleId)
  88. }, keys...)
  89. return err
  90. }
  91. func (m *customSysRolePermModel) DeleteByRoleIdAndPermIdsTx(ctx context.Context, session sqlx.Session, roleId int64, permIds []int64) error {
  92. if len(permIds) == 0 {
  93. return nil
  94. }
  95. placeholders := make([]string, len(permIds))
  96. args := make([]interface{}, 0, len(permIds)+1)
  97. args = append(args, roleId)
  98. for i, id := range permIds {
  99. placeholders[i] = "?"
  100. args = append(args, id)
  101. }
  102. inClause := strings.Join(placeholders, ",")
  103. var list []*SysRolePerm
  104. findQuery := fmt.Sprintf("SELECT %s FROM %s WHERE `roleId` = ? AND `permId` IN (%s) FOR UPDATE", sysRolePermRows, m.table, inClause)
  105. if err := session.QueryRowsCtx(ctx, &list, findQuery, args...); err != nil {
  106. return err
  107. }
  108. if len(list) == 0 {
  109. return nil
  110. }
  111. keys := m.buildCacheKeys(list)
  112. _, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (sql.Result, error) {
  113. query := fmt.Sprintf("DELETE FROM %s WHERE `roleId` = ? AND `permId` IN (%s)", m.table, inClause)
  114. return session.ExecCtx(ctx, query, args...)
  115. }, keys...)
  116. return err
  117. }