{"id":28469799,"url":"https://github.com/answerdotai/fractionalindex","last_synced_at":"2025-07-11T05:37:11.740Z","repository":{"id":269893032,"uuid":"908765574","full_name":"AnswerDotAI/fractionalindex","owner":"AnswerDotAI","description":"A data structure that allows you to insert a new item between any two existing items, or at the start or end","archived":false,"fork":false,"pushed_at":"2025-01-14T00:37:28.000Z","size":23,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-06-14T08:09:27.930Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AnswerDotAI.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-12-26T23:05:10.000Z","updated_at":"2025-04-20T04:09:50.000Z","dependencies_parsed_at":null,"dependency_job_id":"5578eddb-85aa-4972-8bff-7d55808ddd26","html_url":"https://github.com/AnswerDotAI/fractionalindex","commit_stats":null,"previous_names":["answerdotai/fractionalindex"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/AnswerDotAI/fractionalindex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Ffractionalindex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Ffractionalindex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Ffractionalindex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Ffractionalindex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AnswerDotAI","download_url":"https://codeload.github.com/AnswerDotAI/fractionalindex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnswerDotAI%2Ffractionalindex/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260447685,"owners_count":23010548,"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":[],"created_at":"2025-06-07T09:08:42.457Z","updated_at":"2025-07-11T05:37:11.735Z","avatar_url":"https://github.com/AnswerDotAI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FractionalIndex\n\n## Overview\n\nA `FractionalIndex` takes a list of existing items and allows you to insert a new item between any two existing items, or at the start or end.\n\nInternally, it uses the `fractional_indexing` pypi package, which works as follows:\n\n```python\nfirst = generate_key_between(None, None) # 'a0'\nsecond = generate_key_between(first, None) # 'a1' (after 1st)\nthird = generate_key_between(second, None) # 'a2' (after 2nd)\nzeroth = generate_key_between(None, first) # 'Zz' (before 1st)\n```\n\n`FractionalIndex` differs with `fractional_indexing` in how it handles skipping the `before` or `after` parameters. If you only pass `before`, it will insert before the specified item, but after the largest item before that (if there is none, then it will insert at the start). If you only pass `after`, it will insert after the specified item, but before the smallest item after that (if there is none, then it will insert at the end).\n\n```python\nidx = FractionalIndex()\ni1 = idx.insert() # starts a new index\nprint(i1) # 'a0'\ni2 = idx.insert(after=i1) # inserts after i1\ni3 = idx.insert(before=i2) # inserts before i2\ni4 = idx.insert(i3, i2) # inserts between i3 and i2\ni5 = idx.insert() # adds to the end\n```\n\nTo add to the start, you can either pass the first item to `insert(before=...)`, or use `begin()`:\n\n```python\ni6 = idx.begin()\n```\n\nYou can create an index from a list of existing items, which will be sorted:\n\n```python\nidx = FractionalIndex([i1, i2, i3, i4, i5, i6])\n```\n\n## Implementation\n\nInternally, `FractionalIndex` by default uses `IndexingList`, a subclass of `sortedcontainers.SortedList` to store the items. The sort is needed so that `insert` without one of both of `after` or `before` can quickly find the next, previous or start/end item. The subclass adds the following methods (which are the only methods required by `FractionalIndex`):\n\n- `after(item)`: returns the next item after the specified item, or `None` if there is none.\n- `before(item)`: returns the previous item before the specified item, or `None` if there is none.\n- `begin()`: returns the first item.\n- `end()`: returns the last item.\n\n## Alternative Implementations\n\nFractionalIndex comes with a few alternative implementations.\n\n### FileIndex\n\n`FileIndex` uses `FileIndexing` instead of `IndexingList` internally. `FileIndexing` is a simple implementation which uses a list of files in a directory, to identify the correct locations in the index. For instance, consider the following directory contents:\n\n```\na0-create-table.sql\na1-add-column.sql\na2-add-index.sql\n```\n\nIn this case, we can create a suitable `FileIndex` with `idx = FileIndex(directory='.', separator='-')`. Since these are the default values, we can simply call `FileIndex()` to create it. Note that the directory will be re-scanned for the latest files on every method call.\n\nYou can then use it just like a regular FractionalIndex:\n\n```python\nidx = FileIndex(directory='migrations', separator='-')\nnew_id = idx.begin()  # Creates ID before first file\nnew_id = idx.insert()  # Creates ID after last file\nnew_id = idx.insert(after='a0')  # Creates ID between a0 and next file\nnew_id = idx.insert(before='a1')  # Creates ID between previous file and a1\nnew_id = idx.insert('a0', 'a1')  # Creates ID between a0 and a1\n```\n\nWhen you get a new ID, you'll need to create the corresponding file (e.g., `{new_id}-something.sql`) for it to be included in future operations.\n\n### SqliteIndex\n\n`SqliteIndex` indexes a sqlite DB table by using the `SqliteIndexing` class. Generally, the fractional index will be the primary key of the table. To use it, you need to pass a `Connection`, `table` and `column` (defaults to 'id') to the constructor:\n\n```python\nimport sqlite3\n\nconn = sqlite3.connect(\"database.db\")\nconn.execute(\"CREATE TABLE migrations (id TEXT PRIMARY KEY)\")\n\n# Create the index\nidx = SqliteIndex(conn, 'migrations', 'id')\n\n# Use it like any other FractionalIndex\nnew_id = idx.begin()  # Creates ID before first row\nnew_id = idx.insert()  # Creates ID after last row\nnew_id = idx.insert(after='a0')  # Creates ID between a0 and next row\nnew_id = idx.insert(before='a1')  # Creates ID between previous row and a1\nnew_id = idx.insert('a0', 'a1')  # Creates ID between a0 and a1\n\n# Don't forget to insert the new ID into your table\nconn.execute(\"INSERT INTO migrations (id) VALUES (?)\", (new_id,))\nconn.commit()\n```\n\nNote that SqliteIndex will query the database on every operation to ensure it's working with the latest data, but it won't automatically insert new IDs - you need to do that yourself after getting a new ID.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanswerdotai%2Ffractionalindex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanswerdotai%2Ffractionalindex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanswerdotai%2Ffractionalindex/lists"}