ExportWorkspace exports all data for a workspace into a portable format.
(slug string)
| 64 | |
| 65 | // ExportWorkspace exports all data for a workspace into a portable format. |
| 66 | func (s *Store) ExportWorkspace(slug string) (*models.WorkspaceExport, error) { |
| 67 | ws, err := s.GetWorkspaceBySlug(slug) |
| 68 | if err != nil { |
| 69 | return nil, fmt.Errorf("workspace lookup: %w", err) |
| 70 | } |
| 71 | if ws == nil { |
| 72 | return nil, fmt.Errorf("workspace not found: %s", slug) |
| 73 | } |
| 74 | |
| 75 | export := &models.WorkspaceExport{ |
| 76 | Version: 1, |
| 77 | ExportedAt: time.Now().UTC().Format(time.RFC3339), |
| 78 | Workspace: models.WorkspaceExportMeta{ |
| 79 | Name: ws.Name, |
| 80 | Slug: ws.Slug, |
| 81 | Description: ws.Description, |
| 82 | Settings: ws.Settings, |
| 83 | }, |
| 84 | } |
| 85 | |
| 86 | // Collections |
| 87 | rows, err := s.db.Query(s.q(` |
| 88 | SELECT id, name, slug, icon, description, schema, settings, prefix, sort_order, is_default, is_system, created_at, updated_at |
| 89 | FROM collections WHERE workspace_id = ? AND deleted_at IS NULL |
| 90 | ORDER BY sort_order, name`), ws.ID) |
| 91 | if err != nil { |
| 92 | return nil, fmt.Errorf("export collections: %w", err) |
| 93 | } |
| 94 | defer rows.Close() |
| 95 | for rows.Next() { |
| 96 | var c models.CollectionExport |
| 97 | var isDefault, isSystem bool |
| 98 | if err := rows.Scan(&c.ID, &c.Name, &c.Slug, &c.Icon, &c.Description, &c.Schema, &c.Settings, &c.Prefix, &c.SortOrder, &isDefault, &isSystem, &c.CreatedAt, &c.UpdatedAt); err != nil { |
| 99 | return nil, fmt.Errorf("scan collection: %w", err) |
| 100 | } |
| 101 | c.IsDefault = isDefault |
| 102 | c.IsSystem = isSystem |
| 103 | export.Collections = append(export.Collections, c) |
| 104 | } |
| 105 | if err := rows.Err(); err != nil { |
| 106 | return nil, err |
| 107 | } |
| 108 | |
| 109 | // Items |
| 110 | itemRows, err := s.db.Query(s.q(` |
| 111 | SELECT id, collection_id, title, slug, content, fields, tags, pinned, sort_order, |
| 112 | COALESCE(parent_id, ''), created_by, last_modified_by, source, COALESCE(item_number, 0), created_at, updated_at |
| 113 | FROM items WHERE workspace_id = ? AND deleted_at IS NULL |
| 114 | ORDER BY created_at, id`), ws.ID) |
| 115 | if err != nil { |
| 116 | return nil, fmt.Errorf("export items: %w", err) |
| 117 | } |
| 118 | defer itemRows.Close() |
| 119 | for itemRows.Next() { |
| 120 | var it models.ItemExport |
| 121 | var pinned bool |
| 122 | if err := itemRows.Scan(&it.ID, &it.CollectionID, &it.Title, &it.Slug, &it.Content, &it.Fields, &it.Tags, &pinned, &it.SortOrder, &it.ParentID, &it.CreatedBy, &it.LastModifiedBy, &it.Source, &it.ItemNumber, &it.CreatedAt, &it.UpdatedAt); err != nil { |
| 123 | return nil, fmt.Errorf("scan item: %w", err) |