{"id":16021297,"url":"https://github.com/tentone/hierarchyid","last_synced_at":"2026-04-28T11:04:33.208Z","repository":{"id":251665058,"uuid":"810198090","full_name":"tentone/hierarchyid","owner":"tentone","description":"Handle hierarchyid type in SQL Server using gorm","archived":false,"fork":false,"pushed_at":"2024-08-20T09:53:21.000Z","size":60,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-10T11:51:15.390Z","etag":null,"topics":["gorm","hierarchyid","sqlserver"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tentone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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-06-04T08:32:20.000Z","updated_at":"2024-08-20T09:53:24.000Z","dependencies_parsed_at":"2024-12-18T09:11:59.147Z","dependency_job_id":"92f87707-e422-4315-bc21-b7e089452a3a","html_url":"https://github.com/tentone/hierarchyid","commit_stats":{"total_commits":46,"total_committers":1,"mean_commits":46.0,"dds":0.0,"last_synced_commit":"3c35bd75c9115ca004636ba4eb5a4fc51a926f0b"},"previous_names":["tentone/gorm-hierarchyid"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tentone%2Fhierarchyid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tentone%2Fhierarchyid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tentone%2Fhierarchyid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tentone%2Fhierarchyid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tentone","download_url":"https://codeload.github.com/tentone/hierarchyid/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247284917,"owners_count":20913691,"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","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":["gorm","hierarchyid","sqlserver"],"created_at":"2024-10-08T18:03:15.516Z","updated_at":"2026-04-28T11:04:33.089Z","avatar_url":"https://github.com/tentone.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gorm hierarchyid\n - Library to handle hierarchyid type in SQL Server and go.\n   - Generation and parsing of hierarchyid type in go.\n   - Type wrapper for usage with gorm ORM.\n - The [hierarchyid](https://learn.microsoft.com/en-us/sql/relational-databases/hierarchical-data-sql-server?view=sql-server-ver16) is data to represent a position in a hierarchy in SQL Server.\n   - It is a variable length type with reduced storage requirements.\n - Encodes the position in the hierarchy as a list of indexes\n   - For example in the tree below the path to `E` is `/1/1/2/`\n   - Indexes can be used to sort elements inside of a tree level.\n \n\u003cimg src=\"./readme/tree.png\" width=\"600\"/\u003e\n\n## How it works\n - The `HierarchyID` is defined as a `[]int64` in go.\n - When serialized into JSON a textual representation is used for readability.\n   - Represented as list separated by `/`. (e.g. `/1/2/3/4/5/`)\n - Each element in the slice represents a level in the hierarchy.\n - An empty slice represents the root of the hierarchy.\n   - Elements placed in the root should not use an empty list.\n   - They should instead by represented by `/1/`, `/2/`, etc.\n\n## Installation\n - The library can be installed using `go get`.\n - \n  ```bash\n  go get github.com/tentone/hierarchyid\n  ```\n\n## Model definition\n - Declare `HierarchyID` type in your gorm model, there is no need to specify the DB data type.\n - Is is recommended to also mark the field as `unique` to avoid duplicates.\n - The library will handle the serialization and deserialization of the field to match the SQL Server `hierarchyid` type.\n    ```go\n    type Model struct {\n        gorm.Model\n\n        Path hierarchyid.HierarchyID `gorm:\"unique;not null;\"`\n    }\n    ```\n - In some scenarios it might be usefull to also keep a tradicional relationship to the parent.\n   - This can be done by adding a `ParentID` field to the model.\n   - It ensures that the tree is consistent and that actions (e.g. delete) are cascaded to the children.\n   - Some operations might also be easier to perform with the parent relationship.\n    ```go\n    type Model struct {\n      gorm.Model\n\n      Path hierarchyid.HierarchyId `gorm:\"unique;not null;\"`\n\n      ParentID uint              `gorm:\"index\"`\n      Parent   *TestParentsTable `foreignKey:\"parent_id;references:id;constraint:OnUpdate:NO ACTION,OnDelete:CASCADE;\"`\n    }\n    ```\n\n## Usage\n\n### Create\n - Elements can be added to the tree as regular entries\n - Just make sure that the tree indexes are filled correctly, indexes dont need to be sequential.\n  ```go\n  db.Create(\u0026Table{Path: hierarchyid.HierarchyID{Data: []int64{1}}})\n  db.Create(\u0026Table{Path: hierarchyid.HierarchyID{Data: []int64{1, 1}}})\n  db.Create(\u0026Table{Path: hierarchyid.HierarchyID{Data: []int64{1, 1, 2}}})\n  ```\n\n### Get Ancestors\n - To get all parents of a node use the `GetAncestors` method.\n - The method will return a slice with all the parents of the node. This can be used as param for a query.\n  ```go\n  db.Model(\u0026Table{}).Where(\"[path] IN (?)\", child.Path.GetAncestors()).Find(\u0026parents)\n  ```\n - Its also possible to get parents with the SQL version of the [`GetAncestor`](https://learn.microsoft.com/en-us/sql/t-sql/data-types/getancestor-database-engine?view=sql-server-ver16) method.\n - Example on getting the parent of an element.\n  ```go\n  db.Model(\u0026Table{}).Where(\"[path] = ?.GetAncestor(1)\", child.Path).Find(\u0026parent)\n  ```\n\n### Get Descendants\n - To get all children of a node use the [`IsDescendantOf`](https://learn.microsoft.com/en-us/sql/t-sql/data-types/isdescendantof-database-engine?view=sql-server-ver16) method in SQL.\n - Example on getting all children of a node (including the node itself).\n  ```go\n  elements := []Table{}\n  db.Where(\"[path].IsDescendantOf(?)=1\", hierarchyid.HierarchyId{Data: []int64{1, 2}}).Find(\u0026elements)\n  ```\n - It is also possible to filter the children based on sub-levels.\n - Example on getting all nodes from root where at least one of the sub-level has a name that contains the text 'de'\n  ```sql\n  SELECT *\n  FROM \"table\" as a\n  WHERE ([path].GetLevel()=1 AND [path].IsDescendantOf('/')=1) AND\n  (SELECT COUNT(*) FROM \"table\" AS b WHERE b.path.IsDescendantOf(a.path)=1 AND b.name LIKE '%de%')\u003e0\n  ```\n - The `GetLevel` method can be used to filter nodes based on their level in the hierarchy. Also available in SQL with the same name [`GetLevel`](https://learn.microsoft.com/en-us/sql/t-sql/data-types/getlevel-database-engine?view=sql-server-ver16).\n - A more generic version of the same code presented above writen in go.\n\n  ```go\n  root := hierarchyid.GetRoot()\n  subQuery := db.Table(\"table AS b\").Select(\"COUNT(*)\").Where(\"[b].[path].IsDescendantOf([a].[path])=1 AND [b].[name] LIKE '%de%'\")\n  conn = db.Table(\"table AS a\").\n    Where(\"[a].[path].GetLevel()=? AND [a].[path].IsDescendantOf(?)=1 AND (?)\u003e0\", root.GetLevel()+1, root, subQuery).\n    Find(\u0026elements)\n  ```\n\n\n### Move nodes\n - To move a node to a new parent there is the `GetReparentedValue` method that receives the old parent and new parent and calculates the new hierarchyid value.\n - Example on moving a node to a new parent.\n  ```go\n  db.Model(\u0026Table{}).Where(\"[id] = ?\", id).Update(\"[path]=?\", node.Path.GetReparentedValue(oldParent.Path, newParent.Path))\n  ```\n\n## Resources\n - [adamil.net - How the SQL Server hierarchyid data type works (kind of)](http://www.adammil.net/blog/v100_how_the_SQL_Server_hierarchyid_data_type_works_kind_of_.html)\n - [hierarchyid data type method reference](https://learn.microsoft.com/en-us/sql/t-sql/data-types/hierarchyid-data-type-method-reference?view=sql-server-ver16\u0026redirectedfrom=MSDN)\n  - .NET Implementation ([Logic](https://github.com/dotMorten/Microsoft.SqlServer.Types/tree/main/src/Microsoft.SqlServer.Types/SqlHierarchy) + [Interface](https://github.com/dotMorten/Microsoft.SqlServer.Types/blob/main/src/Microsoft.SqlServer.Types/SqlHierarchyId.cs))\n\n## License\n - The project is distributed using a MIT license. Available on the project repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftentone%2Fhierarchyid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftentone%2Fhierarchyid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftentone%2Fhierarchyid/lists"}