Here comes a very short, cut-down version of relations.inc. It is a very basic api for use in various indexing schemes.
It can be expanded to hook into db_rewrite_sql(), but I refuse to do that for the sake of my remaining sanity.
The basic idea is that modules can/should use this or analogous api to perform all "relation" queries.
There is a HUUGE confusion going on about What is a relation?, but I won't participate in that any more - no time, sorry.
I decided to split the relations api from the more advanced issues realted to the current sqlgen implementation. The main reason for this split is due to the never ending discussions about what is a relation on drupal forums, irc, mailing lists, etc...
The relations api is going to be a simple implementation of a tree and graph indexes, with emebeded SQL. You should be able to do things like - get related nodes; get next, previous, parent, children, sibling nodes.
Long term-wise we should be able to replace the book and taxonomy implementations of the database using this api. I'm intentionally going to make it extremely minimalistic, since I'm really not a supporter of using embdedded sql statements.
minor imporvements - Rev 4 - vlado (2 file(s) modified)minor imporvements
[relations svn]
As it says on the box minor improvements. Actually the changes are a mockup of some of my ideas for better/proper database abstraction, and a variation on some of Adrian's model thoughts.
sqlgen_join(
// functional form
sqlgen_table('n'=>'node'),
//array(ish) form
array('r'=>'node_revisions'),
// the join constrains, defines the new relation
sqlgen_constraints(
array('node_revisions'=>'may be null'),
sqlgen_and(
sqlgen_eq( arg('node','nid'),arg('node_revisions','nid') ),
sqlgen_eq( arg('node'=>'vid'),arg('node_revisions','vid'))
)
),
//result filtering
sqlgen_cond( sqlgen_eq(arg('node','nid'),$nid))
);
This is the functional form. It provides a good abstraction. It is independant of the underlying structure. In my opinion it has better code readability. Can be thoroughly unit tested.
$view=array(
'*'=>'node_revisions',
'*'=>'node',
'name'=>'user',
'#cond'=>array(
'#op'=>'AND',
array(
'#op'=>'eq',
array('node','nid'),
array('node_revisions','nid')),
array('#op'=>'eq',
array('node','vid'),
array('node_revisions','vid')),
array('#op'=>'eq',
array('node','nid'),
'#param'=>'node_view_id')
)
);
The array form, can easily become a mess. It is faster using arrays, rather than using functions to generate them, but could be daunting.
Both cases provide a close native equivalent to s-forms in php. Although you have eval(), the native php syntax is not as easily manipulateable as in lisp.
Still both forms have a significant advantage over 'embeded SQL'. We can get native php expression of the concepts in the db. We can optimise the queries, based on both data knowledge and database backends. Database independence is obvious. No rewrite_sql hacks. So things like coding a new/custom permission system becomes a breeze. Content type mashups, view/form remixing becomes possible.
As I've said this is just a mockup.
updated the comments in the functional form for readability
I've been reading. Scheming. And I stumpled upon SchemeUnit and SchemeQL: Two Little Languages. I liked the paper. Especially the SchemeQL part. It does state my (intellectual) motivation behind writing relations/sqlgen.
I realised that I need to demo, coming soon in flesh, why I'm doing the relations the way I do, and why I have these strange concepts.
Let's start with an example in KIF, the example is lifted from the KIF draft proposed American National Standard (dpANS).
(defrelation number (?x) := (or (real ?x) (complex ?x)))
What does it mean? Well, is number(x) will be true if x is either a real or complex number. Number is a relation.
Generally speaking we have two ways to define a relation or function - either explictly defining all possible/known cases, or by using some procedure to produce them.
I've updated the code in my relations svn repository.
Some of the changes a very experimental - like the munit.inc - it is implementing bovine tests- simply very basic (beasty), non-complicated, dirty, grazing unit tests. When I was writing the tests I was out of net reach, so no simpletest for me. And now I just like it.
Implemented tests for the majority of sqlgen. There are the beginnings of theme widgets - using drupal forms api for theming, as Adrian suggested earlier. The widget tests need to be refactored. Don't you believe them.
What I need to do next is to figure out how to tie together the data from db and some meta-data so I can generate the different view. The main goal is minimal metadata for maximum impact. We shall see. At the moment nothing more than the table description from db is used.
The bryght repository seems to be down.
So here are the urls to the drpkg and relations svn repositories maintained at MEC by me. I will be syncing them to bryght regularly.
svn://mec0026.engi.cf.ac.uk/relations svn://mec0026.engi.cf.ac.uk/drpkg
To checkout the relations code do:
svn co svn://mec0026.engi.cf.ac.uk/relations
To checkout the drpkg code do:
svn co svn://mec0026.engi.cf.ac.uk/drpkg
Update: It is back up, but I'll keep both in sync.
Update: repair
I uploaded the first version of the relations module to the Bryght svn repository. I intend to use it for easier management and brainstorming. When the module is considered alpha quality it will get into drupal's contrib cvs, maybe earlier. I don't want to pollute it earlier than nessesary.
The bulk of the sql query generation has been done. An initial working version of the url parser, implemention a simple relation definition language parser has been done.
There are a few things, which need to be done in order for the api to be properly usable. The main show-stoppers are the relation nodeapi and themeing of the output. I haven't done anything on the nodeapi side, since I'm not sure about the UI. Needs experimenting. For the themeing, I need to think through themeing based on the field meta-data. Thes goes dangerously into the cck teritory. If anyone has any ideas, please come up and shout.
OK, I was talking, talking, writing, fuming - here is some code. Please comment. I need some feedback. I need help as well - to make this better. The file is attached to this post.
Some explanation is probably needed, or I might end up scoring even higher mad hatter points. My previous scribbles on relations give background on my thoughts on this. So I won't be repeating them. The goal is to produce an api, which can be used to form predicates, essentially queries on various related things. One and the same relation can be used in many ways. For example in a simple triple - (subject,predicate,object) or (left,relation,right), we can have four different questions - the free variables being subject and object. Things get more complicated when you consider relation tuples with a length more than two. This is the main reason to try and create a query generator.
Now some implementation details. The RFS() function. The parameter passing is a bit awkward. It is not elegant, but I had to solve a particular problem there. Consider that the arguments can be generated using a different RFS function. Consider as well that $arg1 and $arg2 can be generated separately or as part of a single expression. There is a need to pass the arguments (signatures essentially) by name, so we can identify them properly, but the order is not guaranteed or even worse, the order and the number of arguments, as well as their shape can't be known in advance. This leads to what I consider a not elegant, but workable solution. I would love to streamline that.
A collection of relations in rupal related links. Add more in comments.