Index: rdbms/Criteria.class.php
===================================================================
--- rdbms/Criteria.class.php (revision 6389)
+++ rdbms/Criteria.class.php (working copy)
@@ -64,12 +64,17 @@
* @param mixed value
* @param string comparison default EQUAL
*/
- function add($key, $value, $comparison= EQUAL) {
+ function add($key, $value= NULL, $comparison= EQUAL) {
static $nullMapping= array(
EQUAL => IS,
NOT_EQUAL => IS_NOT
);
+ if (is('rdbms.criterion.Criterion', $key)) {
+ $this->conditions[]= &$key;
+ return;
+ }
+
// Automatically convert '= NULL' to 'is NULL', former is not valid ANSI-SQL
if (NULL === $value && isset($nullMapping[$comparison]))
$comparison= $nullMapping[$comparison];
@@ -145,6 +150,11 @@
if (!empty($this->conditions)) {
$sql.= ' where ';
foreach ($this->conditions as $condition) {
+ if (is('rdbms.criterion.Criterion', $condition)) {
+ $sql.= $condition->asSql($db, $types).' and ';
+ continue;
+ }
+
if (!isset($types[$condition[0]])) {
return throw(new SQLStateException('Field "'.$condition[0].'" unknown'));
}
Index: rdbms/criterion/Restrictions.class.php
===================================================================
--- rdbms/criterion/Restrictions.class.php (revision 0)
+++ rdbms/criterion/Restrictions.class.php (revision 0)
@@ -0,0 +1,205 @@
+
Index: rdbms/criterion/SimpleExpression.class.php
===================================================================
--- rdbms/criterion/SimpleExpression.class.php (revision 0)
+++ rdbms/criterion/SimpleExpression.class.php (revision 0)
@@ -0,0 +1,76 @@
+
+ *
IN
+ * NOT_IN
+ * LIKE
+ * EQUAL
+ * NOT_EQUAL
+ * LESS_THAN
+ * GREATER_THAN
+ * LESS_EQUAL
+ * GREATER_EQUAL
+ *
+ *
+ * @access public
+ * @param string field
+ * @param mixed value
+ * @param string op default EQUAL
+ */
+ function __construct($field, $value, $op= EQUAL) {
+ static $nullMapping= array(
+ EQUAL => IS,
+ NOT_EQUAL => IS_NOT
+ );
+
+ $this->field= $field;
+ $this->value= &$value;
+
+ // Automatically convert '= NULL' to 'is NULL', former is not valid ANSI-SQL
+ if (NULL === $value && isset($nullMapping[$op])) {
+ $op= $nullMapping[$op];
+ }
+ $this->op= $op;
+ }
+
+ /**
+ * Returns the fragment SQL
+ *
+ * @access public
+ * @param &rdbms.DBConnection conn
+ * @param array types
+ * @return string
+ * @throws rdbms.SQLStateException
+ */
+ function asSql(&$conn, $types) {
+ if (!isset($types[$this->field])) {
+ return throw(new SQLStateException('Field "'.$this->field.'" unknown'));
+ }
+
+ return $this->field.' '.$conn->prepare(
+ str_replace('?', $types[$this->field], $this->op),
+ $this->value
+ );
+ }
+
+ } implements(__FILE__, 'rdbms.criterion.Criterion');
+?>
Index: rdbms/criterion/BetweenExpression.class.php
===================================================================
--- rdbms/criterion/BetweenExpression.class.php (revision 0)
+++ rdbms/criterion/BetweenExpression.class.php (revision 0)
@@ -0,0 +1,54 @@
+field= $field;
+ $this->lo= &$lo;
+ $this->hi= &$hi;
+ }
+
+ /**
+ * Returns the fragment SQL
+ *
+ * @access public
+ * @param &rdbms.DBConnection conn
+ * @param array types
+ * @return string
+ * @throws rdbms.SQLStateException
+ */
+ function asSql(&$conn, $types) {
+ if (!isset($types[$this->field])) {
+ return throw(new SQLStateException('Field "'.$this->field.'" unknown'));
+ }
+
+ return $this->field.' between '.$conn->prepare(
+ $types[$this->field].' and '.$types[$this->field],
+ $this->lo,
+ $this->hi
+ );
+ }
+
+ } implements(__FILE__, 'rdbms.criterion.Criterion');
+?>
Index: rdbms/criterion/LogicalExpression.class.php
===================================================================
--- rdbms/criterion/LogicalExpression.class.php (revision 0)
+++ rdbms/criterion/LogicalExpression.class.php (revision 0)
@@ -0,0 +1,54 @@
+left= &$left;
+ $this->right= &$right;
+ $this->op= $op;
+ }
+
+ /**
+ * Returns the fragment SQL
+ *
+ * @access public
+ * @param &rdbms.DBConnection conn
+ * @param array types
+ * @return string
+ * @throws rdbms.SQLStateException
+ */
+ function asSql(&$conn, $types) {
+ return $conn->prepare(
+ '(%c %c %c)',
+ $this->left->asSql($conn, $types),
+ $this->op,
+ $this->right->asSql($conn, $types)
+ );
+ }
+
+ } implements(__FILE__, 'rdbms.criterion.Criterion');
+?>
Index: rdbms/criterion/Criterion.class.php
===================================================================
--- rdbms/criterion/Criterion.class.php (revision 0)
+++ rdbms/criterion/Criterion.class.php (revision 0)
@@ -0,0 +1,28 @@
+
Index: rdbms/criterion/NegationExpression.class.php
===================================================================
--- rdbms/criterion/NegationExpression.class.php (revision 0)
+++ rdbms/criterion/NegationExpression.class.php (revision 0)
@@ -0,0 +1,40 @@
+criterion= &$criterion;
+ }
+
+ /**
+ * Returns the fragment SQL
+ *
+ * @access public
+ * @param &rdbms.DBConnection conn
+ * @param array types
+ * @return string
+ * @throws rdbms.SQLStateException
+ */
+ function asSql(&$conn, $types) {
+ return $conn->prepare('not (%c)', $this->criterion->asSql($conn, $types));
+ }
+
+ } implements(__FILE__, 'rdbms.criterion.Criterion');
+?>
Index: rdbms/criterion/Property.class.php
===================================================================
--- rdbms/criterion/Property.class.php (revision 0)
+++ rdbms/criterion/Property.class.php (revision 0)
@@ -0,0 +1,168 @@
+name= $name;
+ }
+
+ /**
+ * Retrieve a property instance by name
+ *
+ * @model static
+ * @access public
+ * @param string name
+ * @return &rdbms.criterion.Property
+ */
+ function &forName($name) {
+ static $instances= array();
+
+ if (!isset($instances[$name])) {
+ $instances[$name]= &new Property($name);
+ }
+ return $instances[$name];
+ }
+
+ /**
+ * Apply an "in" constraint to the named property
+ *
+ * @access public
+ * @param mixed[] values
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &in($values) {
+ return Restrictions::in($this->name, $values);
+ }
+
+ /**
+ * Apply an "not in" constraint to the named property
+ *
+ * @access public
+ * @param mixed[] values
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function ¬In($values) {
+ return Restrictions::notIn($this->name, $values);
+ }
+
+ /**
+ * Apply a "like" constraint to the named property
+ *
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &like($value) {
+ return Restrictions::like($this->name, $value);
+ }
+
+ /**
+ * Apply a case-insensitive "like" constraint to the named property
+ *
+ * @see php://sql_regcase
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &ilike($value) {
+ return Restrictions::ilike($this->name, $value);
+ }
+
+ /**
+ * Apply an "equal" constraint to the named property
+ *
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &equal($value) {
+ return Restrictions::equal($this->name, $value);
+ }
+
+ /**
+ * Apply a "not equal" constraint to the named property
+ *
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function ¬Equal($value) {
+ return Restrictions::notEqual($this->name, $value);
+ }
+
+ /**
+ * Apply a "less than" constraint to the named property
+ *
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &lessThan($value) {
+ return Restrictions::lessThan($this->name, $value);
+ }
+
+ /**
+ * Apply a "greater than" constraint to the named property
+ *
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &greaterThan($value) {
+ return Restrictions::greaterThan($this->name, $value);
+ }
+
+ /**
+ * Apply a "less than or equal to" constraint to the named property
+ *
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &lessThanOrEqualTo($value) {
+ return Restrictions::lessThanOrEqualTo($this->name, $value);
+ }
+
+ /**
+ * Apply a "greater than or equal to" constraint to the named property
+ *
+ * @access public
+ * @param mixed value
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &greaterThanOrEqualTo($value) {
+ return Restrictions::greaterThanOrEqualTo($this->name, $value);
+ }
+
+ /**
+ * Apply a "between" constraint to the named property
+ *
+ * @access public
+ * @param mixed lo
+ * @param mixed hi
+ * @return &rdbms.criterion.SimpleExpression
+ */
+ function &between($lo, $hi) {
+ return Restrictions::between($this->name, $lo, $hi);
+ }
+ }
+?>
Index: net/xp_framework/unittest/rdbms/CriteriaTest.class.php
===================================================================
--- net/xp_framework/unittest/rdbms/CriteriaTest.class.php (revision 6389)
+++ net/xp_framework/unittest/rdbms/CriteriaTest.class.php (working copy)
@@ -6,6 +6,8 @@
uses(
'rdbms.Criteria',
+ 'rdbms.criterion.Restrictions',
+ 'rdbms.criterion.Property',
'rdbms.DriverManager',
'net.xp_framework.unittest.rdbms.dataset.Job',
'util.profiling.unittest.TestCase'
@@ -14,6 +16,10 @@
/**
* Test criteria class
*
+ * Note we're relying on the connection to be a sybase connection -
+ * otherwise, quoting and date representation may change and make
+ * this testcase fail.
+ *
* @see xp://rdbms.Criteria
* @purpose Unit Test
*/
@@ -94,13 +100,34 @@
$c->addOrderBy('valid_from');
}
- // Note we're relying on the connection to be a sybase connection -
- // otherwise, quoting and date representation may change and make
- // this test fail.
$this->assertSql(
'where job_id = 1 and valid_from >= "2006-01-01 12:00AM" and title like "Hello%" order by valid_from asc',
$c
);
}
+
+ /**
+ * Tests the rdbms.criterion API
+ *
+ * @see xp://rdbms.criterion.Property
+ * @see xp://rdbms.criterion.Restrictions
+ * @access public
+ */
+ #[@test]
+ function restrictionsFactory() {
+ $job_id= &Property::forName('job_id');
+ $c= &new Criteria(Restrictions::eitherOf(
+ Restrictions::not($job_id->in(array(1, 2, 3))),
+ Restrictions::bothOf(
+ Restrictions::like('title', 'Hello%'),
+ Restrictions::greaterThan('valid_from', new Date('2006-01-01'))
+ )
+ ));
+
+ $this->assertSql(
+ 'where (not (job_id in (1, 2, 3)) or (title like "Hello%" and valid_from > "2006-01-01 12:00AM"))',
+ $c
+ );
+ }
}
?>