Saturday, April 23, 2011

a look at the chet "appositive expression" orm dsl

Chet is a lightweight, minimal, php framework intended to make writing php not feel like a giant pile of array('a' => array('b' => array('c', 'd')). This is accomplished mainly by declaring appropriate constants and using what I am calling "appositive expressions". e.g. Person(name, 'shaun', age, 28);

While this started out as a joke it has actually begun to have merit and today I am going to demonstrate the latest portion of the project which is the sql dsl which in a nut shell looks like:

TodoItem::with(
creationDate, between($start, $end),
either(
owner, eq(25),
status, in('active', 'pending')));

SCS: 26
When I am messing with snytax ideas I have come up with a system for scoring their visual complexity which comes down to counting any piece of non-word character i.e. parens, colons, commas, quotes etc. For the above example the SCS (syntactic-complexity-score) is 26.

The above in a raw php + sql approach would be:

safe_mysql_query("select *
from TodoItem
where creationDate between(?, ?)
and (owner = ?
or status in(?, ?))", array($start, $end, 25, 'active', 'pending'));

SCS: 33

The equivalent in something like cake php would be (from with in a controller abusing the concept of $this to access a model... ugh)

$this->TodoItem->find('all', array('conditions' => array(
'creationDate between ? and ?' => array($start, $end),
'OR' => array(
'owner' => 25,
'status in(?, ?)' => array('active', 'pending')))));

SCS: 58

I am pretty sure that the above describes what I am trying to get at: if your "abstraction" is messier/harder to read than that which you are meant to be abstracting yourself "from" it is time to go back to the drawing board. While Chet started out as a joke (a reference to Sinatra for ruby but more fitting as Chet Baker was a horrible drug addict yet an incredible musician - thus php is a terrible language yet still capable of doing marvelous things in a non-classy manner even), I am slowly actually wanting to use it for real projects.

One of the design choices was to either bit the bullet and have methods called _and, _or etc. or find alternatives for them. For "and" I have chosen "with". For "or" I have chosen "either". For all of the other sql operators I have chosen the perl approach: "=" is "eq", ">" is "gt", ">=" is "gte" etc. between and in are now both just methods. The beauty is that because all of this is just sugar you can just as easily express the above as:

TodoItem::with(array(
'creationDate' => array('between' => array($start, $end)),
'or' => array(
'owner' => array('=', 25),
'status' => array('in', array('active', 'pending')))));

SCS: 56

Still not as gnarly as the cake php but clearly noisier than the "real chet" approach. My point is that you can drop the sugar in favor of the array noise if one is so inclined.

I am using this same approach for the html/css which yields some very similar gains in readability and "self-similarity" across the entire application.

All of the above being said this is purely an exercise in "how far" I can push php to gain something that resembles a non-array/class-abusing DSL with a small amount of code generation and utilization of everything php 5.3 has to offer.