package migrations import ( "encoding/json" "strings" "time" "github.com/pocketbase/pocketbase/core" m "github.com/pocketbase/pocketbase/migrations" ) func init() { m.Register(func(app core.App) error { // create collection `workflow_logs` { jsonData := `{ "createRule": null, "deleteRule": null, "fields": [ { "autogeneratePattern": "[a-z0-9]{15}", "hidden": false, "id": "text3208210256", "max": 15, "min": 15, "name": "id", "pattern": "^[a-z0-9]+$", "presentable": false, "primaryKey": true, "required": true, "system": true, "type": "text" }, { "cascadeDelete": true, "collectionId": "tovyif5ax6j62ur", "hidden": false, "id": "relation3371272342", "maxSelect": 1, "minSelect": 0, "name": "workflowId", "presentable": false, "required": false, "system": false, "type": "relation" }, { "cascadeDelete": true, "collectionId": "qjp8lygssgwyqyz", "hidden": false, "id": "relation821863227", "maxSelect": 1, "minSelect": 0, "name": "runId", "presentable": false, "required": false, "system": false, "type": "relation" }, { "autogeneratePattern": "", "hidden": false, "id": "text157423495", "max": 0, "min": 0, "name": "nodeId", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "autogeneratePattern": "", "hidden": false, "id": "text3227511481", "max": 0, "min": 0, "name": "nodeName", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "hidden": false, "id": "number2782324286", "max": null, "min": null, "name": "timestamp", "onlyInt": false, "presentable": false, "required": false, "system": false, "type": "number" }, { "autogeneratePattern": "", "hidden": false, "id": "text2599078931", "max": 0, "min": 0, "name": "level", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "autogeneratePattern": "", "hidden": false, "id": "text3065852031", "max": 0, "min": 0, "name": "message", "pattern": "", "presentable": false, "primaryKey": false, "required": false, "system": false, "type": "text" }, { "hidden": false, "id": "json2918445923", "maxSize": 0, "name": "data", "presentable": false, "required": false, "system": false, "type": "json" }, { "hidden": false, "id": "autodate2990389176", "name": "created", "onCreate": true, "onUpdate": false, "presentable": false, "system": false, "type": "autodate" } ], "id": "pbc_1682296116", "indexes": [ "CREATE INDEX ` + "`" + `idx_IOlpy6XuJ2` + "`" + ` ON ` + "`" + `workflow_logs` + "`" + ` (` + "`" + `workflowId` + "`" + `)", "CREATE INDEX ` + "`" + `idx_qVlTb2yl7v` + "`" + ` ON ` + "`" + `workflow_logs` + "`" + ` (` + "`" + `runId` + "`" + `)" ], "listRule": null, "name": "workflow_logs", "system": false, "type": "base", "updateRule": null, "viewRule": null }` collection := &core.Collection{} if err := json.Unmarshal([]byte(jsonData), &collection); err != nil { return err } if err := app.Save(collection); err != nil { return err } } // migrate data { workflowRuns, err := app.FindAllRecords("workflow_run") if err != nil { return err } for _, workflowRun := range workflowRuns { type dWorkflowRunLogRecord struct { Time string `json:"time"` Level string `json:"level"` Content string `json:"content"` Error string `json:"error"` } type dWorkflowRunLog struct { NodeId string `json:"nodeId"` NodeName string `json:"nodeName"` Records []dWorkflowRunLogRecord `json:"records"` Error string `json:"error"` } logs := make([]dWorkflowRunLog, 0) if err := workflowRun.UnmarshalJSONField("logs", &logs); err != nil { continue } collection, err := app.FindCollectionByNameOrId("workflow_logs") if err != nil { return err } for _, log := range logs { for _, logRecord := range log.Records { record := core.NewRecord(collection) createdAt, _ := time.Parse(time.RFC3339, logRecord.Time) record.Set("workflowId", workflowRun.Get("workflowId")) record.Set("runId", workflowRun.Get("id")) record.Set("nodeId", log.NodeId) record.Set("nodeName", log.NodeName) record.Set("timestamp", createdAt.UnixMilli()) record.Set("level", logRecord.Level) record.Set("message", strings.TrimSpace(logRecord.Content+" "+logRecord.Error)) record.Set("created", createdAt) if err := app.Save(record); err != nil { return err } } } } } // update collection `workflow_run` { collection, err := app.FindCollectionByNameOrId("workflow_run") if err != nil { return err } if err := collection.Fields.AddMarshaledJSONAt(6, []byte(`{ "hidden": false, "id": "json772177811", "maxSize": 5000000, "name": "detail", "presentable": false, "required": false, "system": false, "type": "json" }`)); err != nil { return err } if err := app.Save(collection); err != nil { return err } } // migrate data { workflowRuns, err := app.FindAllRecords("workflow_run") if err != nil { return err } workflowOutputs, err := app.FindAllRecords("workflow_output") if err != nil { return err } type dWorkflowNode struct { Id string `json:"id"` Type string `json:"type"` Name string `json:"name"` Config map[string]any `json:"config"` Inputs []map[string]any `json:"inputs"` Outputs []map[string]any `json:"outputs"` Next *dWorkflowNode `json:"next,omitempty"` Branches []dWorkflowNode `json:"branches,omitempty"` Validated bool `json:"validated"` } for _, workflowRun := range workflowRuns { node := &dWorkflowNode{} for _, workflowOutput := range workflowOutputs { if workflowOutput.GetString("runId") != workflowRun.Get("id") { continue } if err := workflowOutput.UnmarshalJSONField("node", node); err != nil { continue } if node.Type != "apply" { node = &dWorkflowNode{} continue } } if node.Id == "" { workflow, _ := app.FindRecordById("workflow", workflowRun.GetString("workflowId")) if workflow != nil { workflowRun.Set("detail", workflow.Get("content")) } else { workflowRun.Set("detail", make(map[string]any)) } } else { workflow, _ := app.FindRecordById("workflow", workflowRun.GetString("workflowId")) if workflow != nil { rootNode := &dWorkflowNode{} if err := workflow.UnmarshalJSONField("content", rootNode); err != nil { return err } rootNode.Next = node workflowRun.Set("detail", rootNode) } else { rootNode := &dWorkflowNode{ Id: core.GenerateDefaultRandomId(), Type: "start", Name: "开始", Config: map[string]any{ "trigger": "manual", }, Next: node, Validated: true, } workflowRun.Set("detail", rootNode) } } if err := app.Save(workflowRun); err != nil { return err } } } // update collection `workflow_run` { collection, err := app.FindCollectionByNameOrId("workflow_run") if err != nil { return err } collection.Fields.RemoveByName("logs") if err := app.Save(collection); err != nil { return err } } return nil }, func(app core.App) error { return nil }) }