{"id":32639830,"url":"https://github.com/gigaquads/store","last_synced_at":"2025-10-31T02:16:10.662Z","repository":{"id":57457591,"uuid":"366410386","full_name":"gigaquads/store","owner":"gigaquads","description":"A transactional in-memory SQL-like object store for long running processes, games, analytics, realtime processing and other applications.","archived":false,"fork":false,"pushed_at":"2021-11-19T19:24:27.000Z","size":92,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-20T23:24:10.569Z","etag":null,"topics":["database-management","databases","object-storage","object-store","query-engine","query-language","simulation","store","stores","virtualization"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":false,"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/gigaquads.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}},"created_at":"2021-05-11T14:28:20.000Z","updated_at":"2023-05-30T11:19:29.000Z","dependencies_parsed_at":"2022-09-07T01:53:25.286Z","dependency_job_id":null,"html_url":"https://github.com/gigaquads/store","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gigaquads/store","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigaquads%2Fstore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigaquads%2Fstore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigaquads%2Fstore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigaquads%2Fstore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gigaquads","download_url":"https://codeload.github.com/gigaquads/store/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gigaquads%2Fstore/sbom","scorecard":{"id":426536,"data":{"date":"2025-08-11","repo":{"name":"github.com/gigaquads/store","commit":"20cb11225c93c47f02fe3e07f94f3b33366d2479"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2020-73"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T02:21:28.693Z","repository_id":57457591,"created_at":"2025-08-19T02:21:28.693Z","updated_at":"2025-08-19T02:21:28.693Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281914594,"owners_count":26583095,"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-10-31T02:00:07.401Z","response_time":57,"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":["database-management","databases","object-storage","object-store","query-engine","query-language","simulation","store","stores","virtualization"],"created_at":"2025-10-31T02:15:39.795Z","updated_at":"2025-10-31T02:16:10.657Z","avatar_url":"https://github.com/gigaquads.png","language":"Python","readme":"# Store\nThis library provides a `Store` datatype for Python. Each store looks and feels\nlike an ORM, but unlike an ORM, there is no database on the other end. Instead,\nall data lives in memory, in the form of plain Python dicts and B-tree indices.\nStores support **SQL-like _select_ statements** in the style of SQLAlchemy,\n**atomic transactions** and **multithreading**.\n\nThe source code aims to be rebustly documented, as we encourage open-source\ncollaboration on this Project.\n\n## Use-cases\n- Long-running interactive applications, like games.\n- Automated trading systems with complex internal state management requirements.\n- Stream-processing applications that perform fast _ad hoc_ queries on stream buffers.\n\n## An Example\nImagine a system that generates user input events, like _mouse click_ and _key\npress_. In the following example, we delete _click events_ created after a\nspecified time and capitalize the character asssociated with each _key press_\nwithin a transaction.\n\n```python\nfrom store import Store\n\nevents = Store()\n\n# insert fictitious \"event\" records\nevents.create_many([\n    {'event_type': 'press', 'char': 'x', 'time': 1},\n    {'event_type': 'click', 'button': 'L', 'position': (5, 8), 'time': 2},\n    {'event_type': 'click', 'button': 'R', 'position': (3, 4), 'time': 3},\n    {'event_type': 'press', 'char': 'y', 'time': 4},\n    {'event_type': 'press', 'char': 'p', 'time': 5},\n])\n\nwith events.transaction() as transaction:\n    # delete \"click\" events after specified time\n    transaction.select().where(\n        events.row.event_type == 'click',\n        events.row.time \u003e 2\n    ).delete()\n\n    # capitalize the \"char\" for each selected \"press\" event\n    get_press_events = transaction.select().where(\n        x.event_type == 'press',\n        x.char.one_of(['x', 'y', 'z'])\n    )\n    for event in get_press_events(dtype=list):\n        event['char'] = event['char'].upper()\n```\n\n## State Dicts\nStore methods, like `create` and `update`, return _state dicts_. Unlike regular\ndicts, any change to the keys or values of a state dict results in an update to\nthe store. For example, suppose that `user` is a state dict. As such,\n`user['name'] ='John'` generates a call to `store.update` under the hood. When\nthis happens, any existing reference to the same `user` immediately reflect this\nchange. There is no need to refresh each reference manually (as they are all\nactually the same object). The same is true for other methods, like `update`,\n`setdefault`, etc.\n\nLet's illustrate with an example:\n\n```python\nfrank_1 = store.create({'id': 1, 'name': 'frank'})\nfrank_2 = store.get(1)\n\n# the store manages a singleton reference to frank's StateDict\n# in its internal so-called identity set.\nassert frank_1 is frank_2\n\n# frank_1 and frank_2 are references to the same object,\n# so they should both reflect the same change.\nfrank_1['name'] = 'Franklin'\n\nassert frank_2['name'] == 'Franklin'\n\n# likewise, any subsequent reference should reflect the same change\nfrank_3 = store.get(1)\n\nassert frank_3['name'] == 'Franklin'\n```\n\n### Stateful Methods\nHere is a list of each `dict` method that has been extended to result in an\nupdate to store as a side-effect. On the lefthand side of each arrow is the\n`dict` method. On the righthand side is the corresponding `store` call.\n\n- `state.update(mapping)` ➞ `store.update(state, mapping.keys())`\n- `state.setdefault(key, default)` ➞ `store.update(state, {key})`\n- `state[key] = value` ➞ `store.update(state, {key})`\n- `del state[key]` ➞ `store.delete(state, {key})`\n\n### Indexes\nBy default, all `StateDict` keys are indexed, including those with non-scalar\nvalues -- like lists, sets, dicts, etc. This means that that queries are fast.\n\n## Queries\nYou can query a store like a SQL database, using _select_, _where_, _order_by_,\n_limit_ and _offset_ constraints.\n\n### Symbols\nSelect statements are written with the help of a class called `Symbol`. A symbol\nis a variable used to express what you want to select and how. Suppose you had a\nstore of _user_ records. Then, using a symbol, You could write a query to\nselects all users, created after a certain cut-off date.\n\n```python\nuser = user_store.symbol()\n\nget_users = user_store.select(\n    user.first_name,\n    user.email\n).where(\n    user.created_at \u003e cutoff_date\n)\n\nfor user in get_users(dtype=list):\n    send(message=f'Hello, {user[\"first_name\"]}!', email=user['email'])\n```\n\nAn alternative to instantiating a new symbol for each query is to use a built-in\nproperty, `store.row`. The following query is identical to the one above:\n\n```python\nget_users = user_store.select(\n    user_store.row.first_name,\n    user_store.row.email\n).where(\n    user_store.row.created_at \u003e cutoff_date\n)\n```\n### Select\nBy default, an empty select will select everything, like `select * from...` in\nSQL; however, if you're only interested in a subset of fields, you can\nexplicitly enumerate them.\n\n#### Selecting Everything\n```python\nquery = store.select()\n```\n\n#### Selecting Specific Fields\n```python\nquery = store.select(store.row.name, store.row.email)\n```\n\n### Where (Filtering)\nYou can constrain queries to select only records whose values match a given\nlogical predicate. Predicates can be arbitrarily nested in compound boolean\nexpressions. This is similar to the \"where\" clause in SQL select statements.\n\n### Filtering Non-scalars Values\nUnlike a SQL database, with a store, you can apply predicate logic not only to\nscalar values, like numbers and strings, but also non-scalar types, like dicts,\nlists, and sets.\n\nFor example, this is possible:\n\n```python\n# imagine you have a store with user dicts, and each user dict\n# has a nested dog dict with an \"age\" value.\n\nget_users = store.select().where(store.row.dog \u003c= {'age': 10})\n\nfor user in get_users():\n    assert user['dog']['age'] \u003c= 10\n```\n\nUsing a symbol, here are some example:\n\n#### Conditional Expressions\n```python\nuser = store.symbol()\n\n# equality\npredicate = (user.email == 'elon.musk@gmail.com')\npredicate = (user.email != 'elon.musk@gmail.com')\n\n# inequality\npredicate = (user.age \u003e= 50)\n\n# containment\npredicate = (user.favorite_color.in(['red', 'blue'])\n\n# logical conjunction (AND)\npredicate = (user.scent == 'smelly') \u0026 (user.income \u003c= 20000)\n\n# logical disjunction (OR)\npredicate = (user.scent == 'smelly') | (user.income \u003c= 20000)\n\n# logical conjunction and disjunction combined\npredicate = (\n    ((user.scent == 'smelly') | (user.age \u003c= 20)) \u0026 (user.name == 'Bob')\n)\n```\n\nMoreover, predicates can be built up gradually, like so:\n\n```python\npredicate = (user.age \u003c= 20)\n\nif some_condition:\n    predicate \u0026= (user.income \u003e 100000)   # |= also works\n```\n\nOnce you have your predicate, you can pass it into a query's `where` method:\n\n```python\nquery = store.select().where(\n    (user.age \u003c= 20) | (user.is_member == True)\n)\n```\n\n### Order By\nQuery results can be sorted by one or more values using the `order_by` query\nmethod. For example:\n\n```python\n# sort results by age (in ascending order) first\n# created_at date (in descending order) second.\nquery = store.select().order_by(\n    user.age.asc,\n    user.created_at.desc\n)\n```\n\n#### Ordering By Non-scalar Values\nUnlike SQL, the store can sort non-scalar datatypes, like dicts, lists, and sets\n-- in addition to plain ints and strings. This means that you can do things like\n-- this:\n\n```python\nstore.create_many([\n    {'owner': 'Mohammed', 'dog': {'age': 10}},\n    {'owner': 'Kang Bo', 'dog': {'age': 6}},\n])\n\nget_users = store.select().order_by(store.row.dog.asc)\nusers = get_users(dtype=list)\n\nfor u1, u2 in zip(users, users[1:]):\n    assert u1.dog['age'] \u003c= u2.dog['age']\n```\n\nNote that, when sorting a dict, the dict's items are sorted and compared in the\nresulting order.\n\n### Limit \u0026 Offset\nQueries support pagination via limit and offset parameters. The `limit`\nparameter is an `int` that determines the maximum number of records returned by\nthe query while the `offset` parameter determines the starting index of the\nreturned slice. When using limit and offset, it is important to specify an order, using\n`order_by`.\n\n```python\nquery = store.select(\n    user.email\n).order_by(\n    user.age.desc\n).offset(\n    20\n).limit(\n    10\n)\n```\n\n## Transactions\nStores support transactions as well. If, for some reason you don't already know,\na database transaction is a mechanism that allows you to perform multiple\noperations as if they were all performed int a single step. This way, if one\noperation fails, then they all fail, and the state of the store remains intact.\nThe syntax for creating transactions is straight forward:\n\n```python\nwith user_store.transaction() as user_trans:\n    # update the name of one user and delete another\n    users = user_trans.get_many([1, 2])\n    users[1]['name'] = 'Updated Name'\n    users[2].delete()\n```\n\nAt the end of the `with` block, the transaction commits; otherwise, if an\nexception is raised, the transaction rolls back, clearing its internal state.\n\nAlternate to using the `with` statement, `commit` and `rollback` methods can be\ncalled explicitly.\n\n```python\nuser_trans = user_store.transaction()\n\ntry:\n    users = user_trans.get_many([1, 2])\n    users[1]['name'] = 'Updated Name'\n    users[2].delete()\n    user_trans.commit()\nexcept Exception:\n    user_trans.rollback()\n```","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgigaquads%2Fstore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgigaquads%2Fstore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgigaquads%2Fstore/lists"}