Last active
August 29, 2015 13:56
-
-
Save mattparker/9177369 to your computer and use it in GitHub Desktop.
Including SQL in Specifications
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// This is another response to Mattias Verraes talk on unbreakable domain | |
// models (slides at http://verraes.net/2013/06/unbreakable-domain-models/) | |
// Near the end there's a bit where he suggests you implement business logic | |
// rules initially as code (i.e. an array filter) and secondly as sql. | |
// You can then test that these are consistent (though the tests in the talk | |
// don't show correctness, there needs to be a test against a known good result | |
// too). But with that, it seems like a nice way to have testable SQL. | |
// A problem for me with the example (which is obviously shortened for the slide example) | |
// is that it shows hard-coded SQL strings. SQL ought to be in one place. But also, | |
// I want these things to be chainable (see https://gist.github.com/mattparker/9177040). | |
// So whatever's returned from asSql wants to be not a string of SQL. | |
// There's some ideas here, but not quite sure about them... | |
final class CustomerWith3OrdersIsPremium implements CustomerSpecification { | |
/** | |
* @return Select | |
*/ | |
public function asSql (Select $select) { | |
// I still don't think this is quite right. | |
// I don't really like that SQL string here. | |
$select->join(new CustomerTable) | |
->where('summary_order_count >= 3'); | |
return $select; | |
} | |
} | |
// or perhaps | |
final class CustomerWith3OrdersIsPremium implements CustomerSpecification { | |
/** | |
* @return Select | |
*/ | |
public function asSql (Select $select) { | |
// This still isn't quite right. | |
// It's better in that the SQL being written is now in | |
// some kind of Select object that belongs to the table. | |
// But instantiating the table here doesn't feel quite right. | |
$customers = new CustomerTable; | |
$customers->select()->orderCount(Select::GREATER_OR_EQUAL, 3); | |
$select->where($customers); | |
return $select; | |
} | |
} | |
// or perhaps | |
final class CustomerWith3OrdersIsPremium implements CustomerSpecification { | |
/** | |
* @return QueryBuilder | |
*/ | |
public function asSql (QueryBuilder $builder) { | |
// The Select object returned from this first line | |
// knows about how to write SQL queries, join tables, etc. | |
$customerSelect = $builder->getSelect(QueryBuilder::CUSTOMER); | |
$customerSelect->hasOrderCount(Select::GREATER_OR_EQUAL, 3); | |
// The QueryBuilder provides access to these Select objects, | |
// and aggregates them and sends them off for execution | |
$builder->where($customerSelect); | |
return $builder; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment