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