user_attribute_repo.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. package repository
  2. import (
  3. "context"
  4. dbent "github.com/Wei-Shaw/sub2api/ent"
  5. "github.com/Wei-Shaw/sub2api/ent/userattributedefinition"
  6. "github.com/Wei-Shaw/sub2api/ent/userattributevalue"
  7. "github.com/Wei-Shaw/sub2api/internal/service"
  8. )
  9. // UserAttributeDefinitionRepository implementation
  10. type userAttributeDefinitionRepository struct {
  11. client *dbent.Client
  12. }
  13. // NewUserAttributeDefinitionRepository creates a new repository instance
  14. func NewUserAttributeDefinitionRepository(client *dbent.Client) service.UserAttributeDefinitionRepository {
  15. return &userAttributeDefinitionRepository{client: client}
  16. }
  17. func (r *userAttributeDefinitionRepository) Create(ctx context.Context, def *service.UserAttributeDefinition) error {
  18. client := clientFromContext(ctx, r.client)
  19. created, err := client.UserAttributeDefinition.Create().
  20. SetKey(def.Key).
  21. SetName(def.Name).
  22. SetDescription(def.Description).
  23. SetType(string(def.Type)).
  24. SetOptions(toEntOptions(def.Options)).
  25. SetRequired(def.Required).
  26. SetValidation(toEntValidation(def.Validation)).
  27. SetPlaceholder(def.Placeholder).
  28. SetEnabled(def.Enabled).
  29. Save(ctx)
  30. if err != nil {
  31. return translatePersistenceError(err, nil, service.ErrAttributeKeyExists)
  32. }
  33. def.ID = created.ID
  34. def.DisplayOrder = created.DisplayOrder
  35. def.CreatedAt = created.CreatedAt
  36. def.UpdatedAt = created.UpdatedAt
  37. return nil
  38. }
  39. func (r *userAttributeDefinitionRepository) GetByID(ctx context.Context, id int64) (*service.UserAttributeDefinition, error) {
  40. client := clientFromContext(ctx, r.client)
  41. e, err := client.UserAttributeDefinition.Query().
  42. Where(userattributedefinition.IDEQ(id)).
  43. Only(ctx)
  44. if err != nil {
  45. return nil, translatePersistenceError(err, service.ErrAttributeDefinitionNotFound, nil)
  46. }
  47. return defEntityToService(e), nil
  48. }
  49. func (r *userAttributeDefinitionRepository) GetByKey(ctx context.Context, key string) (*service.UserAttributeDefinition, error) {
  50. client := clientFromContext(ctx, r.client)
  51. e, err := client.UserAttributeDefinition.Query().
  52. Where(userattributedefinition.KeyEQ(key)).
  53. Only(ctx)
  54. if err != nil {
  55. return nil, translatePersistenceError(err, service.ErrAttributeDefinitionNotFound, nil)
  56. }
  57. return defEntityToService(e), nil
  58. }
  59. func (r *userAttributeDefinitionRepository) Update(ctx context.Context, def *service.UserAttributeDefinition) error {
  60. client := clientFromContext(ctx, r.client)
  61. updated, err := client.UserAttributeDefinition.UpdateOneID(def.ID).
  62. SetName(def.Name).
  63. SetDescription(def.Description).
  64. SetType(string(def.Type)).
  65. SetOptions(toEntOptions(def.Options)).
  66. SetRequired(def.Required).
  67. SetValidation(toEntValidation(def.Validation)).
  68. SetPlaceholder(def.Placeholder).
  69. SetDisplayOrder(def.DisplayOrder).
  70. SetEnabled(def.Enabled).
  71. Save(ctx)
  72. if err != nil {
  73. return translatePersistenceError(err, service.ErrAttributeDefinitionNotFound, service.ErrAttributeKeyExists)
  74. }
  75. def.UpdatedAt = updated.UpdatedAt
  76. return nil
  77. }
  78. func (r *userAttributeDefinitionRepository) Delete(ctx context.Context, id int64) error {
  79. client := clientFromContext(ctx, r.client)
  80. _, err := client.UserAttributeDefinition.Delete().
  81. Where(userattributedefinition.IDEQ(id)).
  82. Exec(ctx)
  83. return translatePersistenceError(err, service.ErrAttributeDefinitionNotFound, nil)
  84. }
  85. func (r *userAttributeDefinitionRepository) List(ctx context.Context, enabledOnly bool) ([]service.UserAttributeDefinition, error) {
  86. client := clientFromContext(ctx, r.client)
  87. q := client.UserAttributeDefinition.Query()
  88. if enabledOnly {
  89. q = q.Where(userattributedefinition.EnabledEQ(true))
  90. }
  91. entities, err := q.Order(dbent.Asc(userattributedefinition.FieldDisplayOrder)).All(ctx)
  92. if err != nil {
  93. return nil, err
  94. }
  95. result := make([]service.UserAttributeDefinition, 0, len(entities))
  96. for _, e := range entities {
  97. result = append(result, *defEntityToService(e))
  98. }
  99. return result, nil
  100. }
  101. func (r *userAttributeDefinitionRepository) UpdateDisplayOrders(ctx context.Context, orders map[int64]int) error {
  102. tx, err := r.client.Tx(ctx)
  103. if err != nil {
  104. return err
  105. }
  106. defer func() { _ = tx.Rollback() }()
  107. for id, order := range orders {
  108. if _, err := tx.UserAttributeDefinition.UpdateOneID(id).
  109. SetDisplayOrder(order).
  110. Save(ctx); err != nil {
  111. return translatePersistenceError(err, service.ErrAttributeDefinitionNotFound, nil)
  112. }
  113. }
  114. return tx.Commit()
  115. }
  116. func (r *userAttributeDefinitionRepository) ExistsByKey(ctx context.Context, key string) (bool, error) {
  117. client := clientFromContext(ctx, r.client)
  118. return client.UserAttributeDefinition.Query().
  119. Where(userattributedefinition.KeyEQ(key)).
  120. Exist(ctx)
  121. }
  122. // UserAttributeValueRepository implementation
  123. type userAttributeValueRepository struct {
  124. client *dbent.Client
  125. }
  126. // NewUserAttributeValueRepository creates a new repository instance
  127. func NewUserAttributeValueRepository(client *dbent.Client) service.UserAttributeValueRepository {
  128. return &userAttributeValueRepository{client: client}
  129. }
  130. func (r *userAttributeValueRepository) GetByUserID(ctx context.Context, userID int64) ([]service.UserAttributeValue, error) {
  131. client := clientFromContext(ctx, r.client)
  132. entities, err := client.UserAttributeValue.Query().
  133. Where(userattributevalue.UserIDEQ(userID)).
  134. All(ctx)
  135. if err != nil {
  136. return nil, err
  137. }
  138. result := make([]service.UserAttributeValue, 0, len(entities))
  139. for _, e := range entities {
  140. result = append(result, service.UserAttributeValue{
  141. ID: e.ID,
  142. UserID: e.UserID,
  143. AttributeID: e.AttributeID,
  144. Value: e.Value,
  145. CreatedAt: e.CreatedAt,
  146. UpdatedAt: e.UpdatedAt,
  147. })
  148. }
  149. return result, nil
  150. }
  151. func (r *userAttributeValueRepository) GetByUserIDs(ctx context.Context, userIDs []int64) ([]service.UserAttributeValue, error) {
  152. if len(userIDs) == 0 {
  153. return []service.UserAttributeValue{}, nil
  154. }
  155. client := clientFromContext(ctx, r.client)
  156. entities, err := client.UserAttributeValue.Query().
  157. Where(userattributevalue.UserIDIn(userIDs...)).
  158. All(ctx)
  159. if err != nil {
  160. return nil, err
  161. }
  162. result := make([]service.UserAttributeValue, 0, len(entities))
  163. for _, e := range entities {
  164. result = append(result, service.UserAttributeValue{
  165. ID: e.ID,
  166. UserID: e.UserID,
  167. AttributeID: e.AttributeID,
  168. Value: e.Value,
  169. CreatedAt: e.CreatedAt,
  170. UpdatedAt: e.UpdatedAt,
  171. })
  172. }
  173. return result, nil
  174. }
  175. func (r *userAttributeValueRepository) UpsertBatch(ctx context.Context, userID int64, inputs []service.UpdateUserAttributeInput) error {
  176. if len(inputs) == 0 {
  177. return nil
  178. }
  179. tx, err := r.client.Tx(ctx)
  180. if err != nil {
  181. return err
  182. }
  183. defer func() { _ = tx.Rollback() }()
  184. for _, input := range inputs {
  185. // Use upsert (ON CONFLICT DO UPDATE)
  186. err := tx.UserAttributeValue.Create().
  187. SetUserID(userID).
  188. SetAttributeID(input.AttributeID).
  189. SetValue(input.Value).
  190. OnConflictColumns(userattributevalue.FieldUserID, userattributevalue.FieldAttributeID).
  191. UpdateValue().
  192. UpdateUpdatedAt().
  193. Exec(ctx)
  194. if err != nil {
  195. return err
  196. }
  197. }
  198. return tx.Commit()
  199. }
  200. func (r *userAttributeValueRepository) DeleteByAttributeID(ctx context.Context, attributeID int64) error {
  201. client := clientFromContext(ctx, r.client)
  202. _, err := client.UserAttributeValue.Delete().
  203. Where(userattributevalue.AttributeIDEQ(attributeID)).
  204. Exec(ctx)
  205. return err
  206. }
  207. func (r *userAttributeValueRepository) DeleteByUserID(ctx context.Context, userID int64) error {
  208. client := clientFromContext(ctx, r.client)
  209. _, err := client.UserAttributeValue.Delete().
  210. Where(userattributevalue.UserIDEQ(userID)).
  211. Exec(ctx)
  212. return err
  213. }
  214. // Helper functions for entity to service conversion
  215. func defEntityToService(e *dbent.UserAttributeDefinition) *service.UserAttributeDefinition {
  216. if e == nil {
  217. return nil
  218. }
  219. return &service.UserAttributeDefinition{
  220. ID: e.ID,
  221. Key: e.Key,
  222. Name: e.Name,
  223. Description: e.Description,
  224. Type: service.UserAttributeType(e.Type),
  225. Options: toServiceOptions(e.Options),
  226. Required: e.Required,
  227. Validation: toServiceValidation(e.Validation),
  228. Placeholder: e.Placeholder,
  229. DisplayOrder: e.DisplayOrder,
  230. Enabled: e.Enabled,
  231. CreatedAt: e.CreatedAt,
  232. UpdatedAt: e.UpdatedAt,
  233. }
  234. }
  235. // Type conversion helpers (map types <-> service types)
  236. func toEntOptions(opts []service.UserAttributeOption) []map[string]any {
  237. if opts == nil {
  238. return []map[string]any{}
  239. }
  240. result := make([]map[string]any, len(opts))
  241. for i, o := range opts {
  242. result[i] = map[string]any{"value": o.Value, "label": o.Label}
  243. }
  244. return result
  245. }
  246. func toServiceOptions(opts []map[string]any) []service.UserAttributeOption {
  247. if opts == nil {
  248. return []service.UserAttributeOption{}
  249. }
  250. result := make([]service.UserAttributeOption, len(opts))
  251. for i, o := range opts {
  252. result[i] = service.UserAttributeOption{
  253. Value: getString(o, "value"),
  254. Label: getString(o, "label"),
  255. }
  256. }
  257. return result
  258. }
  259. func toEntValidation(v service.UserAttributeValidation) map[string]any {
  260. result := map[string]any{}
  261. if v.MinLength != nil {
  262. result["min_length"] = *v.MinLength
  263. }
  264. if v.MaxLength != nil {
  265. result["max_length"] = *v.MaxLength
  266. }
  267. if v.Min != nil {
  268. result["min"] = *v.Min
  269. }
  270. if v.Max != nil {
  271. result["max"] = *v.Max
  272. }
  273. if v.Pattern != nil {
  274. result["pattern"] = *v.Pattern
  275. }
  276. if v.Message != nil {
  277. result["message"] = *v.Message
  278. }
  279. return result
  280. }
  281. func toServiceValidation(v map[string]any) service.UserAttributeValidation {
  282. result := service.UserAttributeValidation{}
  283. if val := getInt(v, "min_length"); val != nil {
  284. result.MinLength = val
  285. }
  286. if val := getInt(v, "max_length"); val != nil {
  287. result.MaxLength = val
  288. }
  289. if val := getInt(v, "min"); val != nil {
  290. result.Min = val
  291. }
  292. if val := getInt(v, "max"); val != nil {
  293. result.Max = val
  294. }
  295. if val := getStringPtr(v, "pattern"); val != nil {
  296. result.Pattern = val
  297. }
  298. if val := getStringPtr(v, "message"); val != nil {
  299. result.Message = val
  300. }
  301. return result
  302. }
  303. // Helper functions for type conversion
  304. func getString(m map[string]any, key string) string {
  305. if v, ok := m[key]; ok {
  306. if s, ok := v.(string); ok {
  307. return s
  308. }
  309. }
  310. return ""
  311. }
  312. func getStringPtr(m map[string]any, key string) *string {
  313. if v, ok := m[key]; ok {
  314. if s, ok := v.(string); ok {
  315. return &s
  316. }
  317. }
  318. return nil
  319. }
  320. func getInt(m map[string]any, key string) *int {
  321. if v, ok := m[key]; ok {
  322. switch n := v.(type) {
  323. case int:
  324. return &n
  325. case int64:
  326. i := int(n)
  327. return &i
  328. case float64:
  329. i := int(n)
  330. return &i
  331. }
  332. }
  333. return nil
  334. }