{"html_url": "https://github.com/dogsheep/apple-notes-to-sqlite/issues/7#issuecomment-1462693867", "issue_url": "https://api.github.com/repos/dogsheep/apple-notes-to-sqlite/issues/7", "id": 1462693867, "node_id": "IC_kwDOJHON9s5XLu_r", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-03-09T20:01:39Z", "updated_at": "2023-03-09T20:02:11Z", "author_association": "MEMBER", "body": "My `folders` table will have:\r\n\r\n- `id` - rowid\r\n- `long_id` - that long unique string ID\r\n- `name` - the name\r\n- `parent` - foreign key to `id`", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1617769847, "label": "Folder support"}, "performed_via_github_app": null} {"html_url": "https://github.com/dogsheep/apple-notes-to-sqlite/issues/7#issuecomment-1462691466", "issue_url": "https://api.github.com/repos/dogsheep/apple-notes-to-sqlite/issues/7", "id": 1462691466, "node_id": "IC_kwDOJHON9s5XLuaK", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-03-09T19:59:52Z", "updated_at": "2023-03-09T19:59:52Z", "author_association": "MEMBER", "body": "Improved script:\r\n```zsh\r\nosascript -e 'tell application \"Notes\"\r\n set allFolders to folders\r\n repeat with aFolder in allFolders\r\n set folderId to id of aFolder\r\n set folderName to name of aFolder\r\n set folderContainer to container of aFolder\r\n if class of folderContainer is folder then\r\n set folderContainerId to id of folderContainer\r\n else\r\n set folderContainerId to \"\"\r\n end if\r\n log \"ID: \" & folderId\r\n log \"Name: \" & folderName\r\n log \"Container: \" & folderContainerId\r\n log \" \"\r\n end repeat\r\nend tell\r\n'\r\n```\r\n```\r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p6113\r\nName: Blog posts\r\nContainer: \r\n \r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p698\r\nName: JSK\r\nContainer: \r\n \r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p7995\r\nName: Nested inside blog posts\r\nContainer: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p6113\r\n \r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p3526\r\nName: New Folder\r\nContainer: \r\n \r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p3839\r\nName: New Folder 1\r\nContainer: \r\n \r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p2\r\nName: Notes\r\nContainer: \r\n \r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p6059\r\nName: Quick Notes\r\nContainer: \r\n \r\nID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p7283\r\nName: UK Christmas 2022\r\nContainer: \r\n```\r\nI filtered out things where the parent was an account and not a folder using `if class of folderContainer is folder then`.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1617769847, "label": "Folder support"}, "performed_via_github_app": null} {"html_url": "https://github.com/dogsheep/apple-notes-to-sqlite/issues/7#issuecomment-1462682795", "issue_url": "https://api.github.com/repos/dogsheep/apple-notes-to-sqlite/issues/7", "id": 1462682795, "node_id": "IC_kwDOJHON9s5XLsSr", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-03-09T19:52:20Z", "updated_at": "2023-03-09T19:52:44Z", "author_association": "MEMBER", "body": "Created through several rounds with ChatGPT (including hints like \"rewrite that using setdefault()\"):\r\n```python\r\ndef topological_sort(nodes):\r\n children = {}\r\n for node in nodes:\r\n parent_id = node[\"parent\"]\r\n if parent_id is not None:\r\n children.setdefault(parent_id, []).append(node)\r\n\r\n def traverse(node, result):\r\n result.append(node)\r\n if node[\"id\"] in children:\r\n for child in children[node[\"id\"]]:\r\n traverse(child, result)\r\n\r\n sorted_data = []\r\n\r\n for node in nodes:\r\n if node[\"parent\"] is None:\r\n traverse(node, sorted_data)\r\n\r\n return sorted_data\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1617769847, "label": "Folder support"}, "performed_via_github_app": null} {"html_url": "https://github.com/dogsheep/apple-notes-to-sqlite/issues/7#issuecomment-1462570187", "issue_url": "https://api.github.com/repos/dogsheep/apple-notes-to-sqlite/issues/7", "id": 1462570187, "node_id": "IC_kwDOJHON9s5XLQzL", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-03-09T18:30:24Z", "updated_at": "2023-03-09T18:30:24Z", "author_association": "MEMBER", "body": "I used ChatGPT to write this:\r\n```\r\nosascript -e 'tell application \"Notes\"\r\n set allFolders to folders\r\n repeat with aFolder in allFolders\r\n set folderId to id of aFolder\r\n set folderName to name of aFolder\r\n set folderContainer to container of aFolder\r\n set folderContainerName to name of folderContainer\r\n log \"Folder ID: \" & folderId\r\n log \"Folder Name: \" & folderName\r\n log \"Folder Container: \" & folderContainerName\r\n log \" \"\r\n --check for nested folders\r\n if count of folders of aFolder > 0 then\r\n set nestedFolders to folders of aFolder\r\n repeat with aNestedFolder in nestedFolders\r\n set nestedFolderId to id of aNestedFolder\r\n set nestedFolderName to name of aNestedFolder\r\n set nestedFolderContainer to container of aNestedFolder\r\n set nestedFolderContainerName to name of nestedFolderContainer\r\n log \" Nested Folder ID: \" & nestedFolderId\r\n log \" Nested Folder Name: \" & nestedFolderName\r\n log \" Nested Folder Container: \" & nestedFolderContainerName\r\n log \" \"\r\n end repeat\r\n end if\r\n end repeat\r\nend tell\r\n'\r\n```\r\nWhich for my account output this:\r\n```\r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p6113\r\nFolder Name: Blog posts\r\nFolder Container: iCloud\r\n \r\n Nested Folder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p7995\r\n Nested Folder Name: Nested inside blog posts\r\n Nested Folder Container: Blog posts\r\n \r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p698\r\nFolder Name: JSK\r\nFolder Container: iCloud\r\n \r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p7995\r\nFolder Name: Nested inside blog posts\r\nFolder Container: Blog posts\r\n \r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p3526\r\nFolder Name: New Folder\r\nFolder Container: iCloud\r\n \r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p3839\r\nFolder Name: New Folder 1\r\nFolder Container: iCloud\r\n \r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p2\r\nFolder Name: Notes\r\nFolder Container: iCloud\r\n \r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p6059\r\nFolder Name: Quick Notes\r\nFolder Container: iCloud\r\n \r\nFolder ID: x-coredata://D2D50498-BBD1-4097-B122-D15ABD32BDEC/ICFolder/p7283\r\nFolder Name: UK Christmas 2022\r\nFolder Container: iCloud\r\n```\r\nSo I think the correct approach here is to run code at the start to list all of the folders (no need to do fancy recursion though, just a flat list with the parent containers is enough) and create a model of that hierarchy in SQLite.\r\n\r\nThen when I import notes I can foreign key reference them back to their containing folder.\r\n\r\nI'm tempted to use `rowid` for the foreign keys because the official IDs are pretty long.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1617769847, "label": "Folder support"}, "performed_via_github_app": null} {"html_url": "https://github.com/dogsheep/apple-notes-to-sqlite/issues/7#issuecomment-1462564717", "issue_url": "https://api.github.com/repos/dogsheep/apple-notes-to-sqlite/issues/7", "id": 1462564717, "node_id": "IC_kwDOJHON9s5XLPdt", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-03-09T18:25:39Z", "updated_at": "2023-03-09T18:25:39Z", "author_association": "MEMBER", "body": "So it looks like folders can be hierarchical?", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1617769847, "label": "Folder support"}, "performed_via_github_app": null} {"html_url": "https://github.com/dogsheep/apple-notes-to-sqlite/issues/7#issuecomment-1462562735", "issue_url": "https://api.github.com/repos/dogsheep/apple-notes-to-sqlite/issues/7", "id": 1462562735, "node_id": "IC_kwDOJHON9s5XLO-v", "user": {"value": 9599, "label": "simonw"}, "created_at": "2023-03-09T18:23:56Z", "updated_at": "2023-03-09T18:25:22Z", "author_association": "MEMBER", "body": "From the Script Editor library docs:\r\n\r\nA note has a:\r\n\r\n> - `container` (folder), r/o) : the folder of the note\r\n\r\nHere's what a folder looks like:\r\n\r\n> folder\u2002n : a folder containing notes\r\n> elements:\r\n>\r\n> - contains folders, notes; contained by application, accounts, folders.\r\n>\r\n> properties:\r\n>\r\n> - `name` (text) : the name of the folder\r\n> - `id` (text, r/o) : the unique identifier of the folder\r\n> - `shared` (boolean, r/o) : Is the folder shared?\r\n> - `container` (account or folder, r/o) : the container of the folder\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1617769847, "label": "Folder support"}, "performed_via_github_app": null}