ycl eav

ycl eav, by PYK, is an entity-attribute-value system for Tcl, built upon sqlite, that features a Tcl-ish interface and query capabilities, traces for maintaining constraints on data and reacting in other ways to record updates, and the ability to traverse logical hierarchies in the data.


In an entity-attribute-value system, structure that might otherwise be found in the database schema is in the data instead. ycl eav provides the features needed to store data in this fashion and to use it as if it were structured into a more traditional relational schema.

An entity-attribute value system easily accomodates hierarchical data such as that represented by XML documents. Nodes in logical hierarchies within a dataset can be discovered using eav find. See below for more information.

As a rule, eav routines process records in the order they were entered. This makes it possible to view a snapshot of the data by limiting results to records that preceded some particular record.


The source code
Includes documentation in prose.

Creating an Eav

eav myeav filename /path/to/some/file

If no filename is provided, the database is created in memory

eav myeav

Creating Entities

To create a new entity, assign one or more attributes and provide the empty string as the entity identifier:

set hydrogen [myeav set {} name hydrogen protons 1]
set oxygen [myeav set {} name oxygen protons 8 phase gas]
set sodium [myeav set {} name sodium protons 11 phase solid]

Removing Entities

To remove an entity:

myeav unset $oxygen

Copying Entities

To copy an entity:

myeav set {} {*}[myeav get $oxygen]

Adding Attributes

To set an additional attribute on an entity:

myeav set $hydrogen phase gas

To add multiple records for an attribute, use insert instead of set

set water [myeav set {} component $hydrogen]
$water insert component $oxygen

Removing Attributes

To unset all records of $oxygen where the attribute is "protons":

myeav unset $oxygen protons

Modifying Attribute Values

To change the value of the last record for some attribute:

myeav set $entity $attribute $value

To increment by 3 the value of the last record for some attribute:

myeav incr $entity $attribute 3 

Retrieving Values

To retrieve the value of an attribute, use set

myeav set $hydrogen component

To retrieve a dictionary of selected values of a entity:

myeav get $hydrogen protons phase

To check if an attribute exists for some entity:

myeav exists $hydrogen phase

If an entity has multiple values for an attribute, only the last value is returned.

To retrieve a list of selected values for an attribute:

myeav list $hydrogen protons phase

Ensuring Such an Entity

To ensure that an entity having a certain profile (set of attributes and associated values) exists:

set nitrogen [myeav ensure name nitrogen protons 7]

Nested Dictionaries

dset, dget, and dexists make it possible to process eav records as nested dictionaries:

set Cronus [myeav set {} name Cronus]
set Apollo [myeav set {} name Apollo]
myeav dset [list $Cronus sons Zeus sons] Apollo $Apollo
puts [myeav dset [list $Cronus sons Zeus sons Apollo] name]

Finding Entities

The first argument to find is a list of attributes to include in the results, and the remaining arguments are operators and their arguments. Each operator consumes a certain number of arguments, and any subsequent argument is another operator. If all operations are true for some entity, it is included in the result set.

To find the entity identifiers for all entities that have a "phase" attribute:

myeav find {} exists phase 

To retrieve a dictionary, keyed by identifier, of all entities that have a "phase" attribute:

myeav find * exists phase 

To retrieve only the "protons" and "phase" attributes of such entities:

myeav find {protons phase} exists phase exists protons

But since any attribute mentioned in the first argument implies an "exists" requirement, the previous command is equivalent to:

myeav find {protons phase}

To find entities that have at least 3 protons:

myeav find {} > protons 3

To find the names of entities that have at least 3 protons and a phase of "solid":

myeav find name > protons 3 == phase solid

To find entities that are missing some attribute:

myeav find name > protons 3 is missing phase

To limit results to those that were inserted prior to some record, use the id operator:

myeav find {} id < $id

Finding Members of Logical Hierarchies

To find members of logical hierarchies of entities, use the descend operator, which takes the name of an entity to build the hierarchy on, and either an == or an entity operation that selects the entry points into the hierarchy, as well as provides the criteria for selecting children of the current node in the hierarchy. For example with an eav instance named organization:

organization find {} descend boss entity == $myboss 

To use a set of criteria instead of an entity to specifiy the entry point(s) into the hierarchy:

organization find {} descend boss name == Neo 

The eval operator

find features an eval operator that functions just like the one in the Tcli interface to sqlite:

organization find {} entity == $myboss descend boss eval record {
    puts [array get $record]

Ordering Results

find usually processes data in the order of insertion. To change this order, use the order operation:

myeav find {} order value


union takes a list of arguments that might be passed to find, and wraps them up into a single database query. for operators that only make sense when given once, the last occurrence is used.


myeav union {* protons > 3} {* missing phase eval record {
    puts [array get record]


Both write and unset actions can be traced. A trace can specify an attribute, an entity, or both. This results in four kinds of traces:

  • Any attribute of any entity.
  • Any attribute of a particular entity.
  • A particular attribute of any entity.
  • A particular attribute of a particular entity.

All traces that match fire, with more general matches firing first. To set a trace:

myeav trace write $id $attribute_name $cmdPrefix

The command prefix has the following signature:

operation entity attribute value

$operation is one of write or unset.