PHPackages                             askonomm/siena - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. askonomm/siena

ActiveLibrary[Database &amp; ORM](/categories/database)

askonomm/siena
==============

A flat-file data store engine and query builder.

v0.0.9(3y ago)014MITRustPHP ^8.1

Since Mar 11Pushed 1y ago1 watchersCompare

[ Source](https://github.com/askonomm/siena)[ Packagist](https://packagist.org/packages/askonomm/siena)[ RSS](/packages/askonomm-siena/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (2)Versions (5)Used By (0)

Siena
=====

[](#siena)

Siena 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.

Siena 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.

Install
-------

[](#install)

Add the following to your Cargo.toml file:

```
siena = "3.2.1"
```

Changelog
---------

[](#changelog)

To see what's changed, check the [changelog](https://github.com/askonomm/siena/blob/master/CHANGELOG.md).

Usage
-----

[](#usage)

### Create store

[](#create-store)

The first thing you need to do when using Siena is creating the store. A store is an instance of Siena with the data provider set. A data provider is anything that implements the `StoreProvider` trait (so you can create your own!). Siena comes with the `LocalProvider` provider, which works on the local file system.

**Example:**

```
use siena::providers::local::LocalProvider;
use siena::siena::siena;

fn main() {
    let provider = LocalProvider { directory: "./path".to_string() };
    let store = siena(provider);
}
```

### Fetching Records

[](#fetching-records)

Records are placed in collections. A collection is a directory in your store. So let's say that you have a collection called "blog-posts", you could fetch them like this:

```
let posts = store.collection("blog-posts").get_all();
```

You can also just get the first record via `get_first()` or the last one via `.get_last()`.

### Filtering Records

[](#filtering-records)

You can filter records using numerous `when_*` methods. And yes, you can chain them as much as you want.

#### `when_is`

[](#when_is)

To filter records by a record key that equals a given value, you can use the `when_is` method, like so:

```
let posts = store
    .collection("blog-posts")
    .when_is("status", "published")
    .get_all();
```

#### `when_is_not`

[](#when_is_not)

Similarly, to filter records the opposite way, by a record key that does *not* equal a given value, you can use the `when_isnt` method:

```
let posts = store
    .collection("blog-posts")
    .when_is_not("status", "published")
    .get_all();
```

#### `when_has`

[](#when_has)

To filter records by the presence of a record key, you can use the `when_has` method, like so:

```
let posts = store
    .collection("blog-posts")
    .when_has("status")
    .get_all();
```

#### `when_has_not`

[](#when_has_not)

Similarly, to filter records the opposite way, by the *lack* of a presence of a record key, you can use the `when_hasnt` method:

```
let posts = store
    .collection("blog-posts")
    .when_has_not("status")
    .get_all();
```

#### `when_matches`

[](#when_matches)

To filter records by a record key that matches a value according to a Regex pattern, you can use the `when_matches` method, like so:

```
let posts = store
    .collection("blog-posts")
    .when_matches("date", r"2022\-09")
    .get_all();
```

There is no opposite method for `when_matches`, because regex gives you the ability to do that yourself.

### Sorting Records

[](#sorting-records)

You can sort records with the `sort` method, like so:

```
use siena::siena::{RecordSortOrder};

let posts = store
    .collection("blog-posts")
    .sort("date", RecordSortOrder::Desc)
    .get_all();
```

The available ways to sort are:

- `RecordSortOrder::Desc`
- `RecordSortOrder::Asc`

### Limiting Records

[](#limiting-records)

To limit the result, use the `limit` method:

```
let posts = store
    .collection("blog-posts")
    .limit(10)
    .get_all();
```

### Offsetting Records

[](#offsetting-records)

To offset the result, use the `offset` method:

```
let posts = store
    .collection("blog-posts")
    .offset(10)
    .get_all();
```

### Pagination

[](#pagination)

With the combination of `limit` and `offset` method, you can create easy pagination, for example:

```
let page = 2;
let posts_per_page = 10;

let posts = store
    .collection("blog-posts")
    .offset((page - 1) * posts_per_page)
    .limit(posts_per_page)
    .get_all();
```

Or, simply use the `paginate` method which does this work for you, like this:

```
let posts = store
    .collection("blog-posts")
    .paginate(2, 10)
    .get_all();
```

### Updating Records

[](#updating-records)

You 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.

For example:

```
let posts = store
    .collection("blog-posts")
    .set(Vec::from([("status", "private")]));
```

This will update all the records in the `blog-post` collection by updating the `status` to `private`.

Whereas this example:

```
let posts = store
    .collection("blog-posts")
    .when_is("status", "public")
    .set(Vec::from([("status", "private")]));
```

Will only update all the records that have `status` as `public` *to* `private`.

### Creating Records

[](#creating-records)

The `create` method is what you use for creating a new record. Note however that the record is not persisted until you use the `set` method to add some data. The `set` method is the only method which writes data. The `create` method only creates the record in-memory so that the `set` method would know where to write data.

An example:

```
store
    .create("blog-posts", "hello-world")
    .set(Vec::from([("title", "Hello, World.")]));
```

The `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.

### Deleting Records

[](#deleting-records)

The `delete` method is what you use for deleting all the records matching a query, so for example if you want to delete all records matching the status "draft", you'd run this:

```
store
    .collection("blog-posts")
    .when_is("status", "draft")
    .delete();
```

Providers
---------

[](#providers)

### `LocalProvider`

[](#localprovider)

The `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.

Supported data types are:

- `String`
- `usize`
- `bool`
- `HashMap`
- `Vec`

### Custom Providers

[](#custom-providers)

You can create your own provider by implementing the `StoreProvider` trait. The trait has three methods that you need to implement:

```
pub trait StoreProvider {
    fn retrieve(&self, name: &str) -> Vec;
    fn set(&self, records: Vec, data: Vec) -> Vec;
    fn delete(&self, records: Vec);
}
```

#### The `retrieve` function

[](#the-retrieve-function)

This function should take in a `name` of a data collection, e.g `posts` and return all `Record`'s for that.

#### The `set` function

[](#the-set-function)

This function should take in a `Vec` and a `Vec` and return a `Vec`. The `Vec` is the records that you want to update, and the `Vec` is the data that you want to update them with. The `&str` is the key of the data, and the `&RecordData` is the value.

#### The `delete` function

[](#the-delete-function)

This function should take in a `Vec` and delete them.

###  Health Score

24

—

LowBetter than 32% of packages

Maintenance26

Infrequent updates — may be unmaintained

Popularity6

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~41 days

Total

4

Last Release

1397d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d16f7263fef5f801e0fb8764cf02747be8f366c1ecaea8d0e10412a6576f311d?d=identicon)[askonomm](/maintainers/askonomm)

---

Top Contributors

[![askonomm](https://avatars.githubusercontent.com/u/84135165?v=4)](https://github.com/askonomm "askonomm (11 commits)")

---

Tags

databasefrontmatterormyaml

### Embed Badge

![Health badge](/badges/askonomm-siena/health.svg)

```
[![Health](https://phpackages.com/badges/askonomm-siena/health.svg)](https://phpackages.com/packages/askonomm-siena)
```

###  Alternatives

[bavix/laravel-wallet

It's easy to work with a virtual wallet.

1.3k1.1M11](/packages/bavix-laravel-wallet)[dyrynda/laravel-model-uuid

This package allows you to easily work with UUIDs in your Laravel models.

4802.8M8](/packages/dyrynda-laravel-model-uuid)[ryangjchandler/orbit

A flat-file database driver for Eloquent.

922256.2k5](/packages/ryangjchandler-orbit)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1022.4k](/packages/rcsofttech-audit-trail-bundle)[formal/orm

324.0k1](/packages/formal-orm)[perplorm/perpl

Perpl is an improved and still maintained fork of Propel2, an open-source Object-Relational Mapping (ORM) for PHP.

203.7k](/packages/perplorm-perpl)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
