1
0

mutate.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. package tools
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "github.com/vektah/gqlparser/v2"
  7. "github.com/vektah/gqlparser/v2/ast"
  8. "gogs.dmsc.dev/arp/graph"
  9. "gogs.dmsc.dev/arp/graph/model"
  10. )
  11. // Mutate executes a GraphQL mutation
  12. func Mutate(ctx context.Context, resolver *graph.Resolver, schema *ast.Schema, args map[string]interface{}) (CallToolResult, error) {
  13. mutationStr, ok := args["mutation"].(string)
  14. if !ok {
  15. return CallToolResult{
  16. Content: []ContentBlock{
  17. {Type: "text", Text: "Missing required 'mutation' parameter"},
  18. },
  19. IsError: true,
  20. }, nil
  21. }
  22. // Parse variables
  23. variables := make(map[string]interface{})
  24. if v, ok := args["variables"].(map[string]interface{}); ok {
  25. variables = v
  26. }
  27. // Parse the mutation
  28. mutationDoc, err := gqlparser.LoadQuery(schema, mutationStr)
  29. if err != nil {
  30. return CallToolResult{
  31. Content: []ContentBlock{
  32. {Type: "text", Text: fmt.Sprintf("Mutation parse error: %v", err)},
  33. },
  34. IsError: true,
  35. }, nil
  36. }
  37. // Execute each operation
  38. var results []interface{}
  39. for _, op := range mutationDoc.Operations {
  40. if op.Operation != ast.Mutation {
  41. continue
  42. }
  43. result, errMsg := executeMutation(ctx, resolver, schema, mutationDoc, op, variables)
  44. if errMsg != "" {
  45. return CallToolResult{
  46. Content: []ContentBlock{
  47. {Type: "text", Text: errMsg},
  48. },
  49. IsError: true,
  50. }, nil
  51. }
  52. results = append(results, result)
  53. }
  54. // Format response
  55. var responseText string
  56. if len(results) == 1 {
  57. bytes, _ := json.MarshalIndent(results[0], "", " ")
  58. responseText = string(bytes)
  59. } else {
  60. bytes, _ := json.MarshalIndent(results, "", " ")
  61. responseText = string(bytes)
  62. }
  63. return CallToolResult{
  64. Content: []ContentBlock{
  65. {Type: "text", Text: responseText},
  66. },
  67. }, nil
  68. }
  69. func executeMutation(ctx context.Context, resolver *graph.Resolver, schema *ast.Schema, doc *ast.QueryDocument, op *ast.OperationDefinition, variables map[string]interface{}) (map[string]interface{}, string) {
  70. result := make(map[string]interface{})
  71. for _, sel := range op.SelectionSet {
  72. field, ok := sel.(*ast.Field)
  73. if !ok {
  74. continue
  75. }
  76. value, errMsg := resolveMutationField(ctx, resolver, schema, field, variables)
  77. if errMsg != "" {
  78. return nil, errMsg
  79. }
  80. result[field.Alias] = value
  81. }
  82. return result, ""
  83. }
  84. func resolveMutationField(ctx context.Context, resolver *graph.Resolver, schema *ast.Schema, field *ast.Field, variables map[string]interface{}) (interface{}, string) {
  85. // Get field arguments
  86. args := make(map[string]interface{})
  87. for _, arg := range field.Arguments {
  88. value, err := arg.Value.Value(variables)
  89. if err != nil {
  90. return nil, fmt.Sprintf("failed to evaluate argument %s: %v", arg.Name, err)
  91. }
  92. args[arg.Name] = value
  93. }
  94. // Resolve based on field name
  95. switch field.Name {
  96. // User mutations
  97. case "createUser":
  98. input := parseNewUser(args["input"])
  99. if input == nil {
  100. return nil, "missing or invalid input for createUser"
  101. }
  102. user, err := resolver.Mutation().CreateUser(ctx, *input)
  103. if err != nil {
  104. return nil, err.Error()
  105. }
  106. return user, ""
  107. case "updateUser":
  108. id, _ := args["id"].(string)
  109. input := parseUpdateUserInput(args["input"])
  110. if input == nil {
  111. return nil, "missing or invalid input for updateUser"
  112. }
  113. user, err := resolver.Mutation().UpdateUser(ctx, id, *input)
  114. if err != nil {
  115. return nil, err.Error()
  116. }
  117. return user, ""
  118. case "deleteUser":
  119. id, _ := args["id"].(string)
  120. user, err := resolver.Mutation().DeleteUser(ctx, id)
  121. if err != nil {
  122. return nil, err.Error()
  123. }
  124. return user, ""
  125. // Note mutations
  126. case "createNote":
  127. input := parseNewNote(args["input"])
  128. if input == nil {
  129. return nil, "missing or invalid input for createNote"
  130. }
  131. note, err := resolver.Mutation().CreateNote(ctx, *input)
  132. if err != nil {
  133. return nil, err.Error()
  134. }
  135. return note, ""
  136. case "updateNote":
  137. id, _ := args["id"].(string)
  138. input := parseUpdateNoteInput(args["input"])
  139. if input == nil {
  140. return nil, "missing or invalid input for updateNote"
  141. }
  142. note, err := resolver.Mutation().UpdateNote(ctx, id, *input)
  143. if err != nil {
  144. return nil, err.Error()
  145. }
  146. return note, ""
  147. case "deleteNote":
  148. id, _ := args["id"].(string)
  149. note, err := resolver.Mutation().DeleteNote(ctx, id)
  150. if err != nil {
  151. return nil, err.Error()
  152. }
  153. return note, ""
  154. // Role mutations
  155. case "createRole":
  156. input := parseNewRole(args["input"])
  157. if input == nil {
  158. return nil, "missing or invalid input for createRole"
  159. }
  160. role, err := resolver.Mutation().CreateRole(ctx, *input)
  161. if err != nil {
  162. return nil, err.Error()
  163. }
  164. return role, ""
  165. case "updateRole":
  166. id, _ := args["id"].(string)
  167. input := parseUpdateRoleInput(args["input"])
  168. if input == nil {
  169. return nil, "missing or invalid input for updateRole"
  170. }
  171. role, err := resolver.Mutation().UpdateRole(ctx, id, *input)
  172. if err != nil {
  173. return nil, err.Error()
  174. }
  175. return role, ""
  176. case "deleteRole":
  177. id, _ := args["id"].(string)
  178. role, err := resolver.Mutation().DeleteRole(ctx, id)
  179. if err != nil {
  180. return nil, err.Error()
  181. }
  182. return role, ""
  183. // Permission mutations
  184. case "createPermission":
  185. input := parseNewPermission(args["input"])
  186. if input == nil {
  187. return nil, "missing or invalid input for createPermission"
  188. }
  189. perm, err := resolver.Mutation().CreatePermission(ctx, *input)
  190. if err != nil {
  191. return nil, err.Error()
  192. }
  193. return perm, ""
  194. case "updatePermission":
  195. id, _ := args["id"].(string)
  196. input := parseUpdatePermissionInput(args["input"])
  197. if input == nil {
  198. return nil, "missing or invalid input for updatePermission"
  199. }
  200. perm, err := resolver.Mutation().UpdatePermission(ctx, id, *input)
  201. if err != nil {
  202. return nil, err.Error()
  203. }
  204. return perm, ""
  205. case "deletePermission":
  206. id, _ := args["id"].(string)
  207. perm, err := resolver.Mutation().DeletePermission(ctx, id)
  208. if err != nil {
  209. return nil, err.Error()
  210. }
  211. return perm, ""
  212. // Service mutations
  213. case "createService":
  214. input := parseNewService(args["input"])
  215. if input == nil {
  216. return nil, "missing or invalid input for createService"
  217. }
  218. service, err := resolver.Mutation().CreateService(ctx, *input)
  219. if err != nil {
  220. return nil, err.Error()
  221. }
  222. return service, ""
  223. case "updateService":
  224. id, _ := args["id"].(string)
  225. input := parseUpdateServiceInput(args["input"])
  226. if input == nil {
  227. return nil, "missing or invalid input for updateService"
  228. }
  229. service, err := resolver.Mutation().UpdateService(ctx, id, *input)
  230. if err != nil {
  231. return nil, err.Error()
  232. }
  233. return service, ""
  234. case "deleteService":
  235. id, _ := args["id"].(string)
  236. service, err := resolver.Mutation().DeleteService(ctx, id)
  237. if err != nil {
  238. return nil, err.Error()
  239. }
  240. return service, ""
  241. // Task mutations
  242. case "createTask":
  243. input := parseNewTask(args["input"])
  244. if input == nil {
  245. return nil, "missing or invalid input for createTask"
  246. }
  247. task, err := resolver.Mutation().CreateTask(ctx, *input)
  248. if err != nil {
  249. return nil, err.Error()
  250. }
  251. return task, ""
  252. case "updateTask":
  253. id, _ := args["id"].(string)
  254. input := parseUpdateTaskInput(args["input"])
  255. if input == nil {
  256. return nil, "missing or invalid input for updateTask"
  257. }
  258. task, err := resolver.Mutation().UpdateTask(ctx, id, *input)
  259. if err != nil {
  260. return nil, err.Error()
  261. }
  262. return task, ""
  263. case "deleteTask":
  264. id, _ := args["id"].(string)
  265. task, err := resolver.Mutation().DeleteTask(ctx, id)
  266. if err != nil {
  267. return nil, err.Error()
  268. }
  269. return task, ""
  270. // TaskStatus mutations
  271. case "createTaskStatus":
  272. input := parseNewTaskStatus(args["input"])
  273. if input == nil {
  274. return nil, "missing or invalid input for createTaskStatus"
  275. }
  276. status, err := resolver.Mutation().CreateTaskStatus(ctx, *input)
  277. if err != nil {
  278. return nil, err.Error()
  279. }
  280. return status, ""
  281. case "updateTaskStatus":
  282. id, _ := args["id"].(string)
  283. input := parseUpdateTaskStatusInput(args["input"])
  284. if input == nil {
  285. return nil, "missing or invalid input for updateTaskStatus"
  286. }
  287. status, err := resolver.Mutation().UpdateTaskStatus(ctx, id, *input)
  288. if err != nil {
  289. return nil, err.Error()
  290. }
  291. return status, ""
  292. case "deleteTaskStatus":
  293. id, _ := args["id"].(string)
  294. status, err := resolver.Mutation().DeleteTaskStatus(ctx, id)
  295. if err != nil {
  296. return nil, err.Error()
  297. }
  298. return status, ""
  299. // Message mutations
  300. case "createMessage":
  301. input := parseNewMessage(args["input"])
  302. if input == nil {
  303. return nil, "missing or invalid input for createMessage"
  304. }
  305. msg, err := resolver.Mutation().CreateMessage(ctx, *input)
  306. if err != nil {
  307. return nil, err.Error()
  308. }
  309. return msg, ""
  310. case "updateMessage":
  311. id, _ := args["id"].(string)
  312. input := parseUpdateMessageInput(args["input"])
  313. if input == nil {
  314. return nil, "missing or invalid input for updateMessage"
  315. }
  316. msg, err := resolver.Mutation().UpdateMessage(ctx, id, *input)
  317. if err != nil {
  318. return nil, err.Error()
  319. }
  320. return msg, ""
  321. case "deleteMessage":
  322. id, _ := args["id"].(string)
  323. msg, err := resolver.Mutation().DeleteMessage(ctx, id)
  324. if err != nil {
  325. return nil, err.Error()
  326. }
  327. return msg, ""
  328. default:
  329. return nil, fmt.Sprintf("unknown mutation: %s", field.Name)
  330. }
  331. }
  332. // Helper functions
  333. func getString(m map[string]interface{}, key string) string {
  334. if v, ok := m[key]; ok {
  335. if s, ok := v.(string); ok {
  336. return s
  337. }
  338. }
  339. return ""
  340. }
  341. func parseStringSlice(v interface{}) []string {
  342. if v == nil {
  343. return nil
  344. }
  345. if arr, ok := v.([]interface{}); ok {
  346. result := make([]string, 0, len(arr))
  347. for _, item := range arr {
  348. if s, ok := item.(string); ok {
  349. result = append(result, s)
  350. }
  351. }
  352. return result
  353. }
  354. if arr, ok := v.([]string); ok {
  355. return arr
  356. }
  357. return nil
  358. }
  359. func parseStringPtr(v interface{}) *string {
  360. if v == nil {
  361. return nil
  362. }
  363. if s, ok := v.(string); ok {
  364. return &s
  365. }
  366. return nil
  367. }
  368. // Input parsing functions
  369. func parseNewUser(v interface{}) *model.NewUser {
  370. if v == nil {
  371. return nil
  372. }
  373. m, ok := v.(map[string]interface{})
  374. if !ok {
  375. return nil
  376. }
  377. return &model.NewUser{
  378. Email: getString(m, "email"),
  379. Password: getString(m, "password"),
  380. Roles: parseStringSlice(m["roles"]),
  381. }
  382. }
  383. func parseUpdateUserInput(v interface{}) *model.UpdateUserInput {
  384. if v == nil {
  385. return nil
  386. }
  387. m, ok := v.(map[string]interface{})
  388. if !ok {
  389. return nil
  390. }
  391. return &model.UpdateUserInput{
  392. Email: parseStringPtr(m["email"]),
  393. Password: parseStringPtr(m["password"]),
  394. Roles: parseStringSlice(m["roles"]),
  395. }
  396. }
  397. func parseNewNote(v interface{}) *model.NewNote {
  398. if v == nil {
  399. return nil
  400. }
  401. m, ok := v.(map[string]interface{})
  402. if !ok {
  403. return nil
  404. }
  405. return &model.NewNote{
  406. Title: getString(m, "title"),
  407. Content: getString(m, "content"),
  408. UserID: getString(m, "userId"),
  409. ServiceID: getString(m, "serviceId"),
  410. }
  411. }
  412. func parseUpdateNoteInput(v interface{}) *model.UpdateNoteInput {
  413. if v == nil {
  414. return nil
  415. }
  416. m, ok := v.(map[string]interface{})
  417. if !ok {
  418. return nil
  419. }
  420. return &model.UpdateNoteInput{
  421. Title: parseStringPtr(m["title"]),
  422. Content: parseStringPtr(m["content"]),
  423. UserID: parseStringPtr(m["userId"]),
  424. ServiceID: parseStringPtr(m["serviceId"]),
  425. }
  426. }
  427. func parseNewRole(v interface{}) *model.NewRole {
  428. if v == nil {
  429. return nil
  430. }
  431. m, ok := v.(map[string]interface{})
  432. if !ok {
  433. return nil
  434. }
  435. return &model.NewRole{
  436. Name: getString(m, "name"),
  437. Description: getString(m, "description"),
  438. Permissions: parseStringSlice(m["permissions"]),
  439. }
  440. }
  441. func parseUpdateRoleInput(v interface{}) *model.UpdateRoleInput {
  442. if v == nil {
  443. return nil
  444. }
  445. m, ok := v.(map[string]interface{})
  446. if !ok {
  447. return nil
  448. }
  449. return &model.UpdateRoleInput{
  450. Name: parseStringPtr(m["name"]),
  451. Description: parseStringPtr(m["description"]),
  452. Permissions: parseStringSlice(m["permissions"]),
  453. }
  454. }
  455. func parseNewPermission(v interface{}) *model.NewPermission {
  456. if v == nil {
  457. return nil
  458. }
  459. m, ok := v.(map[string]interface{})
  460. if !ok {
  461. return nil
  462. }
  463. return &model.NewPermission{
  464. Code: getString(m, "code"),
  465. Description: getString(m, "description"),
  466. }
  467. }
  468. func parseUpdatePermissionInput(v interface{}) *model.UpdatePermissionInput {
  469. if v == nil {
  470. return nil
  471. }
  472. m, ok := v.(map[string]interface{})
  473. if !ok {
  474. return nil
  475. }
  476. return &model.UpdatePermissionInput{
  477. Code: parseStringPtr(m["code"]),
  478. Description: parseStringPtr(m["description"]),
  479. }
  480. }
  481. func parseNewService(v interface{}) *model.NewService {
  482. if v == nil {
  483. return nil
  484. }
  485. m, ok := v.(map[string]interface{})
  486. if !ok {
  487. return nil
  488. }
  489. return &model.NewService{
  490. Name: getString(m, "name"),
  491. Description: parseStringPtr(m["description"]),
  492. CreatedByID: getString(m, "createdById"),
  493. Participants: parseStringSlice(m["participants"]),
  494. }
  495. }
  496. func parseUpdateServiceInput(v interface{}) *model.UpdateServiceInput {
  497. if v == nil {
  498. return nil
  499. }
  500. m, ok := v.(map[string]interface{})
  501. if !ok {
  502. return nil
  503. }
  504. return &model.UpdateServiceInput{
  505. Name: parseStringPtr(m["name"]),
  506. Description: parseStringPtr(m["description"]),
  507. CreatedByID: parseStringPtr(m["createdById"]),
  508. Participants: parseStringSlice(m["participants"]),
  509. }
  510. }
  511. func parseNewTask(v interface{}) *model.NewTask {
  512. if v == nil {
  513. return nil
  514. }
  515. m, ok := v.(map[string]interface{})
  516. if !ok {
  517. return nil
  518. }
  519. return &model.NewTask{
  520. Title: getString(m, "title"),
  521. Content: getString(m, "content"),
  522. CreatedByID: getString(m, "createdById"),
  523. AssigneeID: parseStringPtr(m["assigneeId"]),
  524. StatusID: parseStringPtr(m["statusId"]),
  525. DueDate: parseStringPtr(m["dueDate"]),
  526. Priority: getString(m, "priority"),
  527. }
  528. }
  529. func parseUpdateTaskInput(v interface{}) *model.UpdateTaskInput {
  530. if v == nil {
  531. return nil
  532. }
  533. m, ok := v.(map[string]interface{})
  534. if !ok {
  535. return nil
  536. }
  537. return &model.UpdateTaskInput{
  538. Title: parseStringPtr(m["title"]),
  539. Content: parseStringPtr(m["content"]),
  540. CreatedByID: parseStringPtr(m["createdById"]),
  541. AssigneeID: parseStringPtr(m["assigneeId"]),
  542. StatusID: parseStringPtr(m["statusId"]),
  543. DueDate: parseStringPtr(m["dueDate"]),
  544. Priority: parseStringPtr(m["priority"]),
  545. }
  546. }
  547. func parseNewTaskStatus(v interface{}) *model.NewTaskStatus {
  548. if v == nil {
  549. return nil
  550. }
  551. m, ok := v.(map[string]interface{})
  552. if !ok {
  553. return nil
  554. }
  555. return &model.NewTaskStatus{
  556. Code: getString(m, "code"),
  557. Label: getString(m, "label"),
  558. }
  559. }
  560. func parseUpdateTaskStatusInput(v interface{}) *model.UpdateTaskStatusInput {
  561. if v == nil {
  562. return nil
  563. }
  564. m, ok := v.(map[string]interface{})
  565. if !ok {
  566. return nil
  567. }
  568. return &model.UpdateTaskStatusInput{
  569. Code: parseStringPtr(m["code"]),
  570. Label: parseStringPtr(m["label"]),
  571. }
  572. }
  573. func parseNewMessage(v interface{}) *model.NewMessage {
  574. if v == nil {
  575. return nil
  576. }
  577. m, ok := v.(map[string]interface{})
  578. if !ok {
  579. return nil
  580. }
  581. return &model.NewMessage{
  582. Content: getString(m, "content"),
  583. Receivers: parseStringSlice(m["receivers"]),
  584. }
  585. }
  586. func parseUpdateMessageInput(v interface{}) *model.UpdateMessageInput {
  587. if v == nil {
  588. return nil
  589. }
  590. m, ok := v.(map[string]interface{})
  591. if !ok {
  592. return nil
  593. }
  594. return &model.UpdateMessageInput{
  595. Content: parseStringPtr(m["content"]),
  596. Receivers: parseStringSlice(m["receivers"]),
  597. }
  598. }