{"id":21169863,"url":"https://github.com/fivesheepco/orderedrelationship","last_synced_at":"2025-07-29T17:06:50.953Z","repository":{"id":217171376,"uuid":"743232317","full_name":"FiveSheepCo/OrderedRelationship","owner":"FiveSheepCo","description":"A Swift macro taking away the pain in adding ordered relationships to SwiftData models","archived":false,"fork":false,"pushed_at":"2024-06-09T14:40:48.000Z","size":16,"stargazers_count":17,"open_issues_count":3,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-09T20:51:41.611Z","etag":null,"topics":["swift","swift-macro","swift-macros","swiftdata","swiftmacro","swiftmacros"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FiveSheepCo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-14T18:13:04.000Z","updated_at":"2025-04-30T21:20:04.000Z","dependencies_parsed_at":"2024-02-02T08:31:20.595Z","dependency_job_id":null,"html_url":"https://github.com/FiveSheepCo/OrderedRelationship","commit_stats":null,"previous_names":["fivesheepco/orderedrelationship"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/FiveSheepCo/OrderedRelationship","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FiveSheepCo%2FOrderedRelationship","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FiveSheepCo%2FOrderedRelationship/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FiveSheepCo%2FOrderedRelationship/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FiveSheepCo%2FOrderedRelationship/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FiveSheepCo","download_url":"https://codeload.github.com/FiveSheepCo/OrderedRelationship/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FiveSheepCo%2FOrderedRelationship/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267722407,"owners_count":24133906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["swift","swift-macro","swift-macros","swiftdata","swiftmacro","swiftmacros"],"created_at":"2024-11-20T15:54:09.264Z","updated_at":"2025-07-29T17:06:50.913Z","avatar_url":"https://github.com/FiveSheepCo.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwiftData-OrderedRelationship\nA Swift macro taking away the pain in adding ordered relationships to SwiftData models.\n\n## Description\nMany SwiftData projects require explicitly ordered relationships. `SwiftData-OrderedRelationship` is a Swift macro that takes away the pain in implementing this and has implicit [CloudKit Sync Conflict Resolution](#conflict-resolution). No special handling on your part is required, when an array with a new order is supplied, `OrderedRelationship` does all the work for you.\n\n## CloudKit Sync\nOrderedRelationship is designed to support CloudKit synchronization, providing [fast syncing](#fast-syncing) and implicit [conflict resolution](#conflict-resolution). \n\n### Fast Syncing\nOrderedRelationship doesn't store the order of its elements as the index of each element. It rather stores each elements position as a random number between `Int.min` and `Int.max`. When `B` gets inserted between `A` and `C` with the positions 100 and 104[^1], the position of `B` will be randomly chosen between 101, 102 and 103. This means only one object needs to be synced per change.\n\n### Conflict Resolution\nAs detailed in [fast syncing](#fast-syncing), elements do not have consecutive position numbers, but are distributed randomly between `Int.min` and `Int.max`. By randomly choosing a new number between the numbers inbetween which a new element is inserted or an existing one is moved, having the same operation take place on two different devices with detached state does not require any explicit conflict resolution or re-assigning of indices after both changes have synced to either device.\n\n## Example\n\nSay you have a `SubItem` model:\n```Swift\n@Model\nclass SubItem {\n    init() {}\n}\n```\n\nThen you can add an ordered relationship to its container `Item`:\n```Swift\n@Model\nfinal class Item {\n    @OrderedRelationship\n    var orderedSubItems: [OrderedSubItem]? = []\n    \n    init() {}\n}\n```\n\nThe type of the variable is an optional array of an undefined type, preferably the type you want to be ordered with a single word prefix. This type (`OrderedSubItem` in this example) will be defined by the `@OrderedRelationship` macro.\n\nNow you add the inverse relationship to the `SubItem` model:\n```Swift\nvar superitem: Item.OrderedSubItem? = nil\n```\n\nThat's it. There is nothing more you need to do.\n\n### Resulting Code\nThe resulting code will contain not only the `OrderedSubItem` model, but also a new variable:\n```Swift\nvar subItems: [SubItem]\n```\nThe variable name is inferred from your custom variable name, removing the first word. You can also specify it explicitly using the [`arrayVariableName` argument](#arrayvariablename). You can both get and set this array. All the work of storing the new order will be performed for you.\n\n## Arguments\nThe `@OrderedRelationship` macro supports arguments to customize its behavior. All of them are optional, as seen in the example above.\n\n### containingClassName\nThe name of the class containing the declaration (`Item` in the example above). If `nil`, this will be inferred by the name of the file in which the macro resides.\n\n### itemClassName\nThe name of the class that the items are. If `nil`, will be inferred by name of the declared array contents without the prefix. In the example above with the array contents being of type `OrderedSubItem`, the type should be `SubItem`.\n\n### inverseRelationshipName\nThe name of the property in `itemClassName` to use for the inverse relationship. Defaults to `superitem`, and in the example above would be `SubItem.superitem`. You are always required to create a property for the inverse relationship, and this argument allows you to tell the macro what it is.\n\n### arrayVariableName\nThe variable name of the resulting array. If `nil`, will be inferred by the name of the declared variable without the prefix. In the example above with the variable name being called `orderedSubItems`, the resulting array will be called `subItems`.\n\n### deleteRule\nThe delete rule to apply to the items. The default value is `.cascade`.\n\n## Why is the macro applied to the ordered items and not the resulting array?\nYou might wonder why the `@OrderedRelationship` macro is applied to the stored array and not the resulting array, like this:\n```Swift\n@Model\nfinal class Item {\n    @OrderedRelationship\n    var subItems: [SubItem]\n    \n    init() {}\n}\n```\nWhile this code is easier to understand, it is simply an impossibility to create such a macro. Macros are expanded alongside each other on a code level basis. This means that the first macro to be expanded in the above code would be the `@Model` macro. The `@Model` macro cannot see the results of the `@OrderedRelationship` macro, since it is expanded after the `@Model` macro. That is why the stored array has to be the one that is declared by the macro user.\n\n\n\n[^1]: The positions being this close to each other is a statistically irrelevant event, this is just an example to showcase the method.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffivesheepco%2Forderedrelationship","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffivesheepco%2Forderedrelationship","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffivesheepco%2Forderedrelationship/lists"}