{"id":24437320,"url":"https://github.com/akkoro/rotary","last_synced_at":"2025-09-29T07:50:18.960Z","repository":{"id":46063878,"uuid":"177470886","full_name":"akkoro/rotary","owner":"akkoro","description":"ORM-like query library for DynamoDB","archived":false,"fork":false,"pushed_at":"2021-11-16T21:56:23.000Z","size":115,"stargazers_count":7,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-23T22:58:15.164Z","etag":null,"topics":["aws","dynamodb"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/akkoro.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":"2019-03-24T21:21:53.000Z","updated_at":"2021-07-13T01:47:36.000Z","dependencies_parsed_at":"2022-09-17T23:00:43.386Z","dependency_job_id":null,"html_url":"https://github.com/akkoro/rotary","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/akkoro/rotary","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkoro%2Frotary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkoro%2Frotary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkoro%2Frotary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkoro%2Frotary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/akkoro","download_url":"https://codeload.github.com/akkoro/rotary/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/akkoro%2Frotary/sbom","scorecard":{"id":176300,"data":{"date":"2025-08-11","repo":{"name":"github.com/akkoro/rotary","commit":"f58c8726e6eda4f98e3b16123082706e1851b9b3"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2,"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":"Code-Review","score":0,"reason":"Found 0/11 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":"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":"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":"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":"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":"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":"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU Affero General Public License v3.0: 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":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"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":"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":"Vulnerabilities","score":2,"reason":"8 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-rrc9-gqf8-8rwg","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-776f-qx25-q3cc"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 20 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T17:45:02.434Z","repository_id":46063878,"created_at":"2025-08-16T17:45:02.434Z","updated_at":"2025-08-16T17:45:02.434Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":277483294,"owners_count":25825561,"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-09-29T02:00:09.175Z","response_time":84,"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":["aws","dynamodb"],"created_at":"2025-01-20T18:16:01.399Z","updated_at":"2025-09-29T07:50:18.937Z","avatar_url":"https://github.com/akkoro.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Rotary\n======\n*DynamoDB with rules.*  \n`yarn add @akkoro/rotary`  \n\nRotary is an open-source library for AWS DynamoDB queries. It aims to\nimplement a set of constraints which allow data to be stored\naccording to one or more [\"best-practice\"](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/best-practices.html) strategies.  \nCurrently the project ships with strategies for relational data and time-series data.\n\nIt is written in TypeScript, and builds on both OO and FP principles.  \nIn particular, it is worth noting that Futures are used instead of Promises.\nAll future-returning APIs can be converted to promises by calling `.promise()` instead of `.fork()`.\n\n----------\n\n# Overview\n\n## Quickstart\n\n```\nConfig.tableName = 'myDynamoTable';\n\ninterface UserAddress {\n    city: string;\n    country: string;\n}\n\n@Entity()\nclass User {\n    @Unique\n    email: string;\n\n    @Searchable({composite: true})\n    address: UserAddress;\n\n    @Searchable({signed: false})\n    type: number;\n\n    @Ref(Account)\n    account: Account;\n\n    birthdate: string;\n}\n\n@Entity()\nclass Account {\n    type: string;\n}\n\n@Entity('TimeSeries')\nclass Post {\n    content: string;\n}\n\n// create and store new user entity\nconst user = makeEntity(User)({id: 'myUser'});\nuser.email = 'clem.fandango@scramblestudios.co.uk';\nuser.type = 1;\nuser.country = {\n    city: 'London',\n    country: 'UK'\n};\nuser.store().fork(console.error, console.log);\n\n// create and store a new post\nconst post = makeEntity(Post)({id: 'myUser', timestamp: Date.now()});\npost.content = 'this is some hot content';\npost.store().fork(console.error, console.log);\n\n// query a user by email\nquery(User)\n    .select('email')\n    .equals('clem.fandango@scramblestudios.co.uk')\n    .fork(console.error, console.log)\n;\n\n// query all users who live in the UK\nquery(User)\n    .select('address')\n    .match({country: 'UK'})\n    .fork(console.error, console.log)\n;\n```\n\n## Entities\n\nEntities follow the [Active Record](https://en.wikipedia.org/wiki/Active_record_pattern) pattern,\nand provide the means for modeling data. Entities optionally specify a [Storage Strategy](#storage-strategies) such as\n`Relational` or `TimeSeries` (default is Relational), which determines how the entity is stored in a DynamoDB table.  \nEntity attributes are specified as class fields, and may optionally specify _one_ [Attribute](#attributes) decorator.\n\n## Attributes\n\nAttributes provide additional query and/or storage functionality to an entity field. They are similar to how a primary key \nor foreign key constraint might be specified in a traditional RDBMS ORM such as TypeORM.  \n\nSome attribute types insert an additional row in DynamoDB when the entity is stored to support query operations on that attribute. \nCare should be taken to balance desired functionality with the extra data \u0026 redundancy that is required to support it.  \n\nSome attributes can only be used with a specific [Storage Strategy](#storage-strategies).\n\n### Built-In Attributes\n\nName       | Supported Strategies   | Supported Operations | Details\n-----------|------------------------|----------------------|--------\nUnique     | Relational             | equals               | Specify for attributes which function as a unique identifier. Adds an additional row.\nSearchable | Relational             | equals, match, range | Specify for attributes non-unique attributes requiring query, or for data that can be queried with partial info. Adds an additoinal row.\nRef        | Relational, TimeSeries | N/A                  | Specify that the attribute contains another entity; the referenced entity will be loaded by ID.\n\nAll entities also provide an `id` attribute which can be queried; the supported operations depend on the storage strategy.\n\nTODO: details on Searchable attribute options `composite` and `signed`\n\n## Storage Strategies\n\nStorage Strategies implement higher-level details about [Entity](#entities) storage. For example, entities stored with the `Relational` strategy \nare packed into a single DynamoDB table, while `TimeSeries` entities require their own table.\n\n### Built-In Strategies\n\nName       | Requires LSI | ID Operations | Details\n-----------|--------------|---------------|----------\nRelational | Yes          | equals        | Emulate a traditional RDBMS\nTimeSeries | No           | equals, range | Store multiple items with the same `id` at many `timestamp`s.\n\n# DynamoDB Configuration\n\n## Relational\n\nCreate a table with any name (be sure to specify this name in `Config.tableName`). This table must have:  \n * a Primary Key named `pk` of type `string`\n * a Sort Key named `sk` of type `string`\n * a local secondary index named `sk-data-index` with\n   * a Primary Key named `sk`\n   * a Sort Key named `data`\n \n## TimeSeries\nCreate a table with any base name (specified in `Config.tableName`), with a suffix of `-ENTITYNAME`.  \nFor example, if `tableName` is `rotary` and our entity is called `Content`, the TimeSeries table must be named `rotary-CONTENT`.  \nThis table must have:  \n * a Primary Key named `pk` of type `string`\n * a Sort Key named `sk` of type `number`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakkoro%2Frotary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakkoro%2Frotary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakkoro%2Frotary/lists"}