Crate owoof

source · []
Expand description

owoof is about interacting with a SQLite-backed database using entity-attribute-value triples and pattern matching.

It is inspired by Datomic and I wrote a wordy post on my blog that explains some of the motivation. Although, that post is about an earlier version of this library.

tldr

Consider a database of triplets that looks like …

100 :animal/name  "Cat"
100 :pet/name     "Garfield"
101 :animal/name  "Dog"
101 :pet/name     "Odie"
102 :person/name  "John Arbuckle"
100 :pet/human    102
101 :pet/human    102

And consider this pattern …

?_ :pet/name ?_

If we were to match triplets using this pattern, we’d be asking for triplets with: any entity, for the :pet/name attribute, and any value. And we would get the following two triplets.

100 :pet/name    "Garfield"
101 :pet/name    "Odie"

Those are the triplets that exist that match that pattern.

Now consider this pair of patterns …

?a :pet/name     ?_
?a :animal/name  "Cat"

The first pattern matches the two triplets from earlier. But the second matches just:

100 :animal/name "Cat"

But, we are not interested in every combination of triplets in the sets that matched our patterns. We related the patterns by constraining the entity to the same variable, ?a. (This is often called unification.) This means that we only match the combinations of triplets between sets when they share the same entity. So we end up with one result with two triplets.

100 :pet/name    "Garfield"
100 :animal/name "Cat"

It’s like if we were to say:

Match every triplet where some entity named ?a has the attribute :pet/name with any value. And match triplets on the same entity ?a having the attribute :animal/name with the value “Cat”.

Another one might be:

?p :person/name ?person
?a :pet/human   ?p
?a :pet/name    ?pet

Here, the variables ?human and ?pet don’t relate triplets together, but they’re there so we can refer to them when we want to get information out.

These patterns are saying:

Given each entity ?a having the :pet/name ?pet and each entity ?p having the :person/name ?person, match only combinations of these where there exists some triplet ?a :pet/human ?p. That is, where ?a’s human is ?p.

The point of owoof is to allow us to build a database of triplets and to use pattern matching to ask it questions and get values out – like the values of ?person and ?pet in the above query:

"John Arbuckle" "Garfield"
"John Arbuckle" "Odie"

Here’s a kind of WIP example of the rust API corresponding to the patterns above:

use owoof::{Network, Value, ValueRef, AttributeRef, disperse::just, traits::*};

let mut network = Network::<ValueRef>::default();

let (p, _, person) = network
    .fluent_triples()
    .match_attribute(AttributeRef::from_static(":person/name"))
    .eav();

let (a, _, _) = network
    .fluent_triples()
    .match_attribute(AttributeRef::from_static(":pet/human"))
    .link_value(p)
    .eav();

let (a, _, pet) = network
    .fluent_triples()
    .match_attribute(AttributeRef::from_static(":pet/name"))
    .eav();

let _: Vec<(Value, Value)> = network.select()
       .field(person)
       .field(pet)
       .to_query()
       .disperse((just(), just()), &woof)
       .unwrap();

Check out the network module for some stuff about querying.

The DontWoof type is useful for mutating data.

Crate Features

  • explain – Adds DontWoof::explain() to do EXPLAIN QUERY PLAN. enabled by default
  • cli – Required for bin/owoof. Enables serde & serde_json.
  • serde & serde_json – Required for parse_value() & parse_pattern() and for serializing Value and ValueRef

Re-exports

pub use crate::either::Either;
pub use crate::network::GenericNetwork;
pub use crate::network::Network;
pub use crate::network::Ordering;
pub use crate::network::OwnedNetwork;
pub use crate::retrieve::NamedNetwork;
pub use crate::retrieve::Pattern;
pub use crate::retrieve::Variable;
pub use crate::soup::Encoded;
pub use crate::types::Attribute;
pub use crate::types::AttributeRef;
pub use crate::types::Entity;
pub use crate::types::Value;
pub use crate::types::ValueRef;

Modules

To do with reading values off of rusqlite::Row using FromSqlRow.

rusqlite::types::ToSql and rusqlite::types::FromSql implementations on crate::types. And the TypeTag & FromTypeTagAndSqlValue traits for reading for loading application types from a type-tag and SQLite value pair.

SQLite’s EXPLAIN QUERY PLAN.

For querying data. Describe groups of entity-attribute-value triples and constraints to search.

A higher-level way of adding constraints to a GenericNetwork.

Stuff to do with SQL query building.

This is just supposed to be some helpful traits re-exported but there’s only the one thing in it so there’s not much point…

Relating to types for entities, attributes, and other database values.

Structs

This has a bunch of logic for changing data, use DontWoof::new to make an instance.

Enums

TODO we only have one variant so what’s the point?

Traits

Functions

Simply executes all the statements required to build the schema against the given connection. Run this under a transaction that you manage or use create_schema_in_transaction.

Type Definitions