{"id":20418257,"url":"https://github.com/askonomm/siena","last_synced_at":"2025-04-12T17:25:23.528Z","repository":{"id":65350963,"uuid":"573955120","full_name":"askonomm/siena","owner":"askonomm","description":"A data provider agnostic ORM.","archived":false,"fork":false,"pushed_at":"2024-05-15T13:49:34.000Z","size":69,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T12:51:14.594Z","etag":null,"topics":["database","frontmatter","orm","yaml"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/askonomm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","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":"2022-12-04T00:24:17.000Z","updated_at":"2024-07-31T17:06:14.000Z","dependencies_parsed_at":"2024-05-16T03:02:12.221Z","dependency_job_id":null,"html_url":"https://github.com/askonomm/siena","commit_stats":{"total_commits":38,"total_committers":1,"mean_commits":38.0,"dds":0.0,"last_synced_commit":"7a97d13e1059f0cd3d9bff8c564eb70c597f9020"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askonomm%2Fsiena","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askonomm%2Fsiena/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askonomm%2Fsiena/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askonomm%2Fsiena/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/askonomm","download_url":"https://codeload.github.com/askonomm/siena/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248603288,"owners_count":21131770,"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":["database","frontmatter","orm","yaml"],"created_at":"2024-11-15T06:30:50.033Z","updated_at":"2025-04-12T17:25:23.498Z","avatar_url":"https://github.com/askonomm.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Siena\n\nSiena is data provider agnostic ORM for Rust, enabling you to easily use custom data stores for your application with all the niceties of a quering engine. \n\nSiena comes built-in with a flat-file data provider, `LocalProvider`, supporting YAML and FrontMatter files, but you can easily create your own data provider by implementing the `StoreProvider` trait.\n\n## Install\n\nAdd the following to your Cargo.toml file:\n```TOML\nsiena = \"3.2.1\"\n```\n\n## Changelog\n\nTo see what's changed, check the [changelog](https://github.com/askonomm/siena/blob/master/CHANGELOG.md).\n\n## Usage\n\n### Create store\n\nThe first thing you need to do when using Siena is creating the store. A store is an instance of Siena with the data \nprovider set. A data provider is anything that implements the `StoreProvider` trait (so you can create your own!). \nSiena comes with the `LocalProvider` provider, which works on the local file system.\n\n**Example:**\n\n```rust\nuse siena::providers::local::LocalProvider;\nuse siena::siena::siena;\n\nfn main() {\n    let provider = LocalProvider { directory: \"./path\".to_string() };\n    let store = siena(provider);\n}\n```\n\n### Fetching Records\n\nRecords are placed in collections. A collection is a directory in your store. So let's say \nthat you have a collection called \"blog-posts\", you could fetch them like this:\n\n```rust\nlet posts = store.collection(\"blog-posts\").get_all();\n```\n\nYou can also just get the first record via `get_first()` or the last one via \n`.get_last()`.\n\n### Filtering Records\n\nYou can filter records using numerous `when_*` methods. And yes, you can chain them \nas much as you want. \n\n#### `when_is`\n\nTo filter records by a record key that equals a given value, you can use the `when_is` method, like so:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .when_is(\"status\", \"published\")\n    .get_all();\n```\n\n#### `when_is_not`\n\nSimilarly, to filter records the opposite way, by a record key that does _not_ equal a given value, you can use the \n`when_isnt` method: \n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .when_is_not(\"status\", \"published\")\n    .get_all();\n```\n\n#### `when_has`\n\nTo filter records by the presence of a record key, you can use the `when_has` method, like so:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .when_has(\"status\")\n    .get_all();\n```\n\n#### `when_has_not`\n\nSimilarly, to filter records the opposite way, by the _lack_ of a presence of a record key, you can use the `when_hasnt` method:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .when_has_not(\"status\")\n    .get_all();\n```\n\n#### `when_matches`\n\nTo filter records by a record key that matches a value according to a Regex pattern, you can use the `when_matches` method, like so:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .when_matches(\"date\", r\"2022\\-09\")\n    .get_all();\n```\n\nThere is no opposite method for `when_matches`, because regex gives you the ability to do that yourself.\n\n### Sorting Records\n\nYou can sort records with the `sort` method, like so:\n\n```rust\nuse siena::siena::{RecordSortOrder};\n\nlet posts = store\n    .collection(\"blog-posts\")\n    .sort(\"date\", RecordSortOrder::Desc)\n    .get_all();\n```\n\nThe available ways to sort are:\n\n- `RecordSortOrder::Desc`\n- `RecordSortOrder::Asc`\n\n### Limiting Records\n\nTo limit the result, use the `limit` method:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .limit(10)\n    .get_all();\n```\n\n### Offsetting Records\n\nTo offset the result, use the `offset` method:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .offset(10)\n    .get_all();\n```\n\n### Pagination\n\nWith the combination of `limit` and `offset` method, you can create easy pagination, for example:\n\n```rust\nlet page = 2;\nlet posts_per_page = 10;\n\nlet posts = store\n    .collection(\"blog-posts\")\n    .offset((page - 1) * posts_per_page)\n    .limit(posts_per_page)\n    .get_all();\n```\n\nOr, simply use the `paginate` method which does this work for you, like this:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .paginate(2, 10)\n    .get_all();\n```\n\n### Updating Records\n\nYou can update the result of your query via the `set` method. It doesn't matter if you have one record or multiple records, it will update anything that you have matching your query.\n\nFor example:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .set(Vec::from([(\"status\", \"private\")]));\n```\n\nThis will update all the records in the `blog-post` collection by updating the `status` to `private`.\n\nWhereas this example:\n\n```rust\nlet posts = store\n    .collection(\"blog-posts\")\n    .when_is(\"status\", \"public\")\n    .set(Vec::from([(\"status\", \"private\")]));\n```\n\nWill only update all the records that have `status` as `public` _to_ `private`.\n\n### Creating Records\n\nThe `create` method is what you use for creating a new record. Note however that the \nrecord is not persisted until you use the `set` method to add some data. The `set` method is the only method\nwhich writes data. The `create` method only creates the record in-memory so that the `set` method would know \nwhere to write data.\n\nAn example:\n\n```rust\nstore\n    .create(\"blog-posts\", \"hello-world\")\n    .set(Vec::from([(\"title\", \"Hello, World.\")]));\n```\n\nThe `create` method takes two arguments, the collection name, and the ID of the record, which has to be unique to that collection or it will overwrite an existing record.\n\n### Deleting Records\n\nThe `delete` method is what you use for deleting all the records matching a query, so for example if you want to \ndelete all records matching the status \"draft\", you'd run this:\n\n```rust\nstore\n    .collection(\"blog-posts\")\n    .when_is(\"status\", \"draft\")\n    .delete();\n```\n\n## Providers\n\n### `LocalProvider`\n\nThe `LocalProvider` is a provider that works on the local file system. It supports YAML and Markdown (FrontMatter) files. In the case of Markdown files, the `Record`'s returned will have `content` and `content_raw` String entries, one for the rendered HTML and one for the raw Markdown, respectively.\n\nSupported data types are: \n\n- `String`\n- `usize`\n- `bool`\n- `HashMap\u003cString, RecordData\u003e`\n- `Vec\u003cRecordData\u003e`\n\n### Custom Providers\n\nYou can create your own provider by implementing the `StoreProvider` trait. The trait has three methods that you need to implement:\n\n```rust\npub trait StoreProvider {\n    fn retrieve(\u0026self, name: \u0026str) -\u003e Vec\u003cRecord\u003e;\n    fn set(\u0026self, records: Vec\u003cRecord\u003e, data: Vec\u003c(\u0026str, \u0026RecordData)\u003e) -\u003e Vec\u003cRecord\u003e;\n    fn delete(\u0026self, records: Vec\u003cRecord\u003e);\n}\n```\n\n#### The `retrieve` function\n\nThis function should take in a `name` of a data collection, e.g `posts` and return all `Record`'s for that.\n\n#### The `set` function\n\nThis function should take in a `Vec\u003cRecord\u003e` and a `Vec\u003c(\u0026str, \u0026RecordData)\u003e` and return a `Vec\u003cRecord\u003e`. The `Vec\u003cRecord\u003e` is the records that you want to update, and the `Vec\u003c(\u0026str, \u0026RecordData)\u003e` is the data that you want to update them with. The `\u0026str` is the key of the data, and the `\u0026RecordData` is the value. \n\n#### The `delete` function\n\nThis function should take in a `Vec\u003cRecord\u003e` and delete them.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faskonomm%2Fsiena","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faskonomm%2Fsiena","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faskonomm%2Fsiena/lists"}