PageRenderTime 74ms CodeModel.GetById 15ms app.highlight 51ms RepoModel.GetById 1ms app.codeStats 1ms

/tests/Pomm/Test/Converter/ConverterTest.php

https://github.com/FabienD/Pomm
PHP | 811 lines | 753 code | 45 blank | 13 comment | 4 complexity | 8c2cb7561bb0b6abd4195874058d10ef MD5 | raw file
  1<?php
  2
  3namespace Pomm\Test\Converter;
  4
  5use Pomm\Connection\Database;
  6use Pomm\Object\BaseObject;
  7use Pomm\Object\BaseObjectMap;
  8use Pomm\Exception\Exception;
  9use Pomm\Converter;
 10use Pomm\Type;
 11
 12class ConverterTest extends \PHPUnit_Framework_TestCase
 13{
 14    protected static $cv_map;
 15    protected static $super_cv_map;
 16    protected static $logger;
 17    protected static $connection;
 18
 19    public static function setUpBeforeClass()
 20    {
 21        $database = new Database(array('dsn' => $GLOBALS['dsn'], 'name' => 'test_db'));
 22
 23        static::$connection = $database->createConnection();
 24
 25        if (isset($GLOBALS['dev']) && $GLOBALS['dev'] == 'true') 
 26        {
 27            static::$logger = new \Pomm\Tools\Logger();
 28
 29            static::$connection->registerFilter(new \Pomm\FilterChain\LoggerFilter(static::$logger));
 30        } 
 31
 32        static::$connection->begin();
 33        try
 34        {
 35            $sql = 'CREATE SCHEMA pomm_test';
 36            static::$connection->executeAnonymousQuery($sql);
 37
 38            static::$cv_map = static::$connection->getMapFor('Pomm\Test\Converter\ConverterEntity');
 39            static::$cv_map->createTable();
 40
 41            static::$super_cv_map = static::$connection->getMapFor('Pomm\Test\Converter\SuperConverterEntity');
 42            static::$super_cv_map->createTable(static::$cv_map);
 43            static::$connection->commit();
 44        }
 45        catch (Exception $e)
 46        {
 47            static::$connection->rollback();
 48
 49            throw $e;
 50        }
 51    }
 52
 53    public static function tearDownAfterClass()
 54    {
 55        $sql = 'DROP SCHEMA pomm_test CASCADE';
 56        static::$connection->executeAnonymousQuery($sql);
 57
 58        !is_null(static::$logger) && print_r(static::$logger);
 59    }
 60
 61    public function testInteger()
 62    {
 63        $entity = static::$cv_map->createObject(array('id' => 1, 'fixed' => 12.345, 'fl' => 0.000001, 'arr_fl' => array(1.0,1.1,1.2,1.3)));
 64        static::$cv_map->saveOne($entity);
 65
 66        $this->assertEquals(1, $entity['id'], "PHP int 1 <=> PG int 1");
 67        $this->assertEquals(12.345, $entity['fixed'], "PHP 12.345 <=> PG 12.345 numeric");
 68        $this->assertEquals(0.000001, $entity['fl'], "PHP 0.000001 <=> PG 1e-6");
 69        $this->assertEquals(array(1.0, 1.1, 1.2, 1.3), $entity['arr_fl'], "Float array is preserved.");
 70
 71        $entity['fixed'] = 0.0001;
 72        $entity['fl'] = 1000000.000001;
 73        $entity['arr_fl'] = array(1.0, 1.1, null, 1.3);
 74        static::$cv_map->saveOne($entity);
 75
 76        $this->assertEquals(0.000, $entity['fixed'], "PHP 0.0001 <=> PG 0.000 numeric");
 77        $this->assertEquals(1000000, $entity['fl'], "PHP 1000000.000001 <=> PG 1e+6");
 78        $this->assertEquals(array(1.0, 1.1, null, 1.3), $entity['arr_fl'], "Float array preserves null.");
 79    }
 80
 81    /**
 82     * @depends testInteger
 83     **/
 84    public function testString()
 85    {
 86        static::$cv_map->alterText();
 87        $entity = static::$cv_map->findAll()->current();
 88        $values = array('some_char' => 'abcdefghij', 'some_varchar' => '1234567890 abcdefghij', 'some_text' => 'Lorem Ipsum', 'arr_varchar' => array('pika', '{"a","b b \'c"}'));
 89
 90        $entity->hydrate($values);
 91        static::$cv_map->updateOne($entity, array_keys($values));
 92
 93        $this->assertEquals('abcdefghij', $entity['some_char'], "Chars are ok.");
 94        $this->assertEquals('1234567890 abcdefghij', $entity['some_varchar'], "Varchars are ok.");
 95        $this->assertEquals('Lorem Ipsum', $entity['some_text'], "Text is ok.");
 96        $this->assertEquals(array('pika', '{"a","b b \'c"}'), $entity['arr_varchar'], "Varchar arrays are ok.");
 97
 98        $entity['some_char'] = 'a        b';
 99        $entity['some_varchar'] = '&"\'-- =+_-;\\?,{}[]()';
100        $entity['some_text'] = '';
101        $entity['arr_varchar'] = array(null, '123', null, '', null, 'abc');
102        static::$cv_map->updateOne($entity, array_keys($values));
103
104        $this->assertEquals('a        b', $entity['some_char'], "Chars' length is kept.");
105        $this->assertEquals('&"\'-- =+_-;\?,{}[]()', $entity['some_varchar'], "Non alpha is escaped.");
106        $this->assertEquals('', $entity['some_text'], "Empty strings are ok.");
107        $this->assertEquals(array(null, '123', null, '', null, 'abc'), $entity['arr_varchar'], "Char arrays can contain nulls and emtpy strings.");
108
109        if (static::$cv_map->alterJson() !== false)
110        {
111            $entity['some_json'] = json_encode(array('plop' => array('pika' => 'chu', 'lot of' => array(1, 2, 3, 4, 5))));
112            static::$cv_map->updateOne($entity, array('some_json'));
113
114            $this->assertEquals('{"plop":{"pika":"chu","lot of":[1,2,3,4,5]}}', $entity['some_json'], "Json type is kept unchanged.");
115        }
116        else
117        {
118            $this->markTestSkipped("Json type is supported since postgresql 9.2. Test skipped.");
119        }
120
121
122        return $entity;
123    }
124
125    /**
126     * @depends testInteger
127     **/
128    public function testDate()
129    {
130        static::$cv_map->alterDate();
131        $entity = static::$cv_map->findAll()->current();
132        $values = array(
133            'some_ts' => '2012-06-20 18:34:16.640044',
134            'some_intv' => '37 years 3 months 7 days 2 hours 14 minutes 46 seconds',
135            'arr_ts' => array('2015-06-08 03:54:08.880287', '1994-12-16 21:23:50.224208', '1941-02-18 17:29:52.216309')
136        );
137
138        $entity->hydrate($values);
139        static::$cv_map->saveOne($entity);
140
141        $this->assertInstanceOf('\DateTime', $entity['some_ts'], "'some_ts' is a \DateTime instance.");
142        $this->assertEquals( '2012-06-20 18:34:16.640044', $entity['some_ts']->format('Y-m-d H:i:s.u'), "Timestamp is preserved.");
143        $this->assertInstanceOf('\DateInterval', $entity['some_intv'], "'some_intv' is a \DateInterval instance.");
144        $this->assertEquals('37 years 3 mons 7 days 02:14:46', $entity['some_intv']->format("%y years %m mons %d days %H:%i:%s"), "'some_intv' is '37 years 3 mons 7 days 02:14:46'.");
145        $this->assertEquals(3, count($entity['arr_ts']), "'arr_ts' is an array of 3 elements.");
146        $this->assertInstanceOf('\DateTime', $entity['arr_ts'][2], "Third element of 'arr_ts' is a DateTime instance.");
147        $this->assertEquals('1941-02-18 17:29:52.216309', $entity['arr_ts'][2]->format('Y-m-d H:i:s.u'), "Array timestamp is preserved.");
148
149        $entity['arr_ts'] = array('2015-06-08 03:54:08.880287', null,  '1941-02-18 17:29:52.216309');
150        static::$cv_map->updateOne($entity, array('arr_ts'));
151
152        $this->assertEquals(3, count($entity['arr_ts']), "'arr_ts' is an array of 3 elements.");
153        $this->assertTrue(is_null($entity['arr_ts'][1]), "Second element of 'arr_ts' is null.");
154
155        return $entity;
156    }
157
158    /**
159     * @depends testInteger
160     **/
161    public function testBool()
162    {
163        static::$cv_map->alterBool();
164        $entity = static::$cv_map->findAll()->current();
165        $values = array('some_bool' => true, 'arr_bool' => array(true, false, true));
166
167        $entity->hydrate($values);
168        static::$cv_map->saveOne($entity);
169
170        $this->assertTrue($entity['some_bool'], "'some_bool' is boolean and TRUE.");
171        $this->assertEquals(3, count($entity['arr_bool']), "'arr_bool' is an array of 3 elements.");
172        $this->assertFalse($entity['arr_bool'][1], "Second element of 'arr_bool' is FALSE.");
173
174        $entity['arr_bool'] = array(true, false, null, false, null, null);
175
176        static::$cv_map->updateOne($entity, array('arr_bool'));
177
178        $this->assertEquals(6, count($entity['arr_bool']), "'arr_bool' is 6 elements array.");
179        $this->assertTrue(is_null($entity['arr_bool'][2]), "3th element is NULL.");
180        $this->assertFalse($entity['arr_bool'][3], "4th element is FALSE.");
181        $this->assertTrue(is_null($entity['arr_bool'][4]), "5th element is NULL.");
182        $this->assertTrue(is_null($entity['arr_bool'][5]), "6th element is NULL.");
183
184        return $entity;
185    }
186
187    /**
188     * Tests are volontarily simplistic, read below:
189     *
190     * pg bytea escaping with PHP :
191     * https://bugs.php.net/bug.php?id=59831&thanks=6
192     *
193     * I don't know why PHP seems to strip some chars from bytea when fetching 
194     * results on some large objects wich makes fail tests (See issue #31).
195     *
196     * Arrays of bytea is not supported as PHP returns this field as string and 
197     * it (or myself) was not able to convert strings to binary (See issue #32).
198     *
199     * @depends testInteger
200     **/
201    public function testBinary()
202    {
203        static::$cv_map->alterBinary();
204        $entity = static::$cv_map->findAll()->current();
205        $binary = chr(0).chr(27).chr(92).chr(39).chr(32).chr(13);
206        $base64 = <<<_
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
208_;
209
210        $values = array('some_bin' => $binary, 'arr_bin' => array($binary, base64_decode($base64)));
211        $entity->hydrate($values);
212
213        static::$cv_map->saveOne($entity);
214
215        $this->assertEquals(strlen($binary), strlen($entity['some_bin']), "Binary strings have same length.");
216        $this->assertEquals(base64_encode($binary), base64_encode($entity['some_bin']), "Small 'some_bin' is preserved.");
217
218        $this->assertEquals(2, count($entity['arr_bin']), "The array has 2 elements.");
219        $this->assertEquals($binary, $entity['arr_bin'][0], "First value in the array is preserved.");
220        //$this->assertEquals($base64, base64_encode($entity['arr_bin'][1]), "Second value in the array is preserved.");
221
222        $entity['some_bin'] = base64_decode($base64);
223        static::$cv_map->updateOne($entity, array('some_bin'));
224
225        $this->assertEquals($base64, base64_encode($entity['some_bin']), "Image is preserved.");
226
227        return $entity;
228    }
229
230    /**
231     * @depends testInteger
232     **/
233    public function testPoint()
234    {
235        static::$cv_map->alterPoint();
236        $entity = static::$cv_map->findAll()->current();
237        $values = array(
238            'some_point' => new Type\Point(47.21262, -1.55516), 
239            'arr_point' => array(new Type\Point(6.431264, 3.424915), new Type\Point(-33.969043, 151.187225))
240        );
241
242        $entity->hydrate($values);
243        static::$cv_map->saveOne($entity);
244
245        $this->assertInstanceOf('\Pomm\Type\Point', $entity['some_point'], "'some_point' is a Point instance.");
246        $this->assertEquals(47.21262, $entity['some_point']->x, "X coordinate is preserved.");
247        $this->assertEquals(-1.55516, $entity['some_point']->y, "Y coordinate is preserved.");
248        $this->assertTrue(is_array($entity['arr_point']), "'arr_point' is an array.");
249        $this->assertEquals(2, count($entity['arr_point']), "Containing 2 elements.");
250        $this->assertEquals(-33.969043, $entity['arr_point'][1]->x, "X of the 2nd element is preserved.");
251        $this->assertEquals(151.187225, $entity['arr_point'][1]->y, "Y of the 2nd element is preserved.");
252
253        $entity['arr_point'] = array(null, $entity['arr_point'][1], null, $entity['arr_point'][0], null);
254        $entity['some_point'] = new Type\Point(0.12345E9, -9.87654E-9);
255
256        static::$cv_map->updateOne($entity, array('arr_point', 'some_point'));
257
258        $this->assertEquals(123450000, $entity['some_point']->x, "X coordinate is preserved.");
259        $this->assertEquals(-9.87654E-9, $entity['some_point']->y, "Y coordinate is preserved.");
260        $this->assertTrue(is_array($entity['arr_point']), "'arr_point' is an array.");
261        $this->assertEquals(5, count($entity['arr_point']), "Containing 5 elements.");
262        $this->assertTrue(is_null($entity['arr_point'][2]), '3rd element is null');
263        $this->assertTrue(is_null($entity['arr_point'][4]), '5th element is null');
264        $this->assertInstanceOf('\Pomm\Type\Point', $entity['arr_point'][1], "2nd element is a Point instance.");
265
266        return $entity;
267    }
268
269    /**
270     * @depends testInteger
271     **/
272    public function testCircle()
273    {
274        static::$cv_map->alterCircle();
275        $entity = static::$cv_map->findAll()->current();
276        $values = array(
277            'some_circle' => new Type\Circle(new Type\Point(0.1234E9,-2), 10),
278            'arr_circle' => array(new Type\Circle(new Type\Point(2,-2), 10), new Type\Circle(new Type\Point(0,0), 1))
279        );
280
281        $entity->hydrate($values);
282        static::$cv_map->saveOne($entity);
283
284        $this->assertInstanceOf('\Pomm\Type\Circle', $entity['some_circle'], "'some_circle' is a Circle type.");
285        $this->assertInstanceOf('\Pomm\Type\Point', $entity['some_circle']->center, "'some_circle' center is a type Point.");
286        $this->assertEquals(10, $entity['some_circle']->radius, "'some_circle' radius is preserved.");
287        $this->assertTrue(is_array($entity['arr_circle']), "'arr_circle' is an array.");
288        $this->assertEquals(2, count($entity['arr_circle']), "Containing 2 elements.");
289        $this->assertInstanceOf('\Pomm\Type\Circle', $entity['arr_circle'][1], "'arr_circle' 2nd element is a Circle type.");
290        $this->assertInstanceOf('\Pomm\Type\Point', $entity['arr_circle'][1]->center, "'arr_circle' 2nd element's center is a type Point.");
291        $this->assertEquals(1, $entity['arr_circle'][1]->radius, "'arr_circle' 2nd element's radius is preserved.");
292
293        $entity['arr_circle'] = array(null, $entity['arr_circle'][0], null,  $entity['arr_circle'][1], null);
294        static::$cv_map->updateOne($entity, array('arr_circle'));
295
296        $this->assertTrue(is_array($entity['arr_circle']), "'arr_circle' is an array.");
297        $this->assertEquals(5, count($entity['arr_circle']), "Containing 5 elements.");
298        $this->assertInstanceOf('\Pomm\Type\Circle', $entity['arr_circle'][1], "'arr_circle' 2nd element is a Circle type.");
299        $this->assertTrue(is_null($entity['arr_circle'][2]), '3rd element is null');
300        $this->assertTrue(is_null($entity['arr_circle'][4]), '5rd element is null');
301
302        return $entity;
303    }
304
305    /**
306     * @depends testInteger
307     **/
308    public function testSegment()
309    {
310        static::$cv_map->alterSegment();
311        $entity = static::$cv_map->findAll()->current();
312        $values = array(
313            'some_lseg' => new Type\Segment(new Type\Point(0.1234E9,-2), new Type\Point(10, -10)),
314            'arr_lseg' => array(new Type\Segment(new Type\Point(2,-2), new Type\Point(0,0)), new Type\Segment(new Type\Point(2,-2), new Type\Point(1000,-1000))),
315        );
316
317        $entity->hydrate($values);
318        static::$cv_map->saveOne($entity);
319
320        $this->assertInstanceOf('\Pomm\Type\Segment', $entity['some_lseg'], "'some_lseg' is a lseg type.");
321        $this->assertInstanceOf('\Pomm\Type\Point', $entity['some_lseg']->point_a, "'some_lseg' point_a is a type Point.");
322        $this->assertInstanceOf('\Pomm\Type\Point', $entity['some_lseg']->point_b, "'some_lseg' point_b is a type Point.");
323        $this->assertTrue(is_array($entity['arr_lseg']), "'arr_lseg' is an array.");
324        $this->assertEquals(2, count($entity['arr_lseg']), "Containing 2 elements.");
325        $this->assertInstanceOf('\Pomm\Type\Segment', $entity['arr_lseg'][1], "'arr_lseg' 2nd element is a lseg type.");
326        $this->assertInstanceOf('\Pomm\Type\Point', $entity['arr_lseg'][1]->point_b, "'arr_lseg' 2nd element's point_b is a type Point.");
327
328        $entity['arr_lseg'] = array(null, $entity['arr_lseg'][0], null,  $entity['arr_lseg'][1], null);
329        static::$cv_map->updateOne($entity, array('arr_lseg'));
330
331        $this->assertTrue(is_array($entity['arr_lseg']), "'arr_lseg' is an array.");
332        $this->assertEquals(5, count($entity['arr_lseg']), "Containing 5 elements.");
333        $this->assertInstanceOf('\Pomm\Type\Segment', $entity['arr_lseg'][1], "'arr_lseg' 2nd element is a lseg type.");
334        $this->assertTrue(is_null($entity['arr_lseg'][2]), '3rd element is null');
335        $this->assertTrue(is_null($entity['arr_lseg'][4]), '5rd element is null');
336    }
337
338    /**
339     * @depends testInteger
340     **/
341    function testHStore()
342    {
343        if (static::$cv_map->alterHStore() === false)
344        {
345            $this->markTestSkipped("HStore extension could not be found in Postgres, tests skipped.");
346
347            return;
348        }
349
350        $entity = static::$cv_map->findAll()->current();
351        $values = array('pika' => 'chu', 'plop' => null, 'grum' => '', 'quote' => '"', '"a"=>"b,a"' => '"c" => "d,a"' );
352        $entity['some_hstore'] = $values;
353
354        static::$cv_map->updateOne($entity, array('some_hstore'));
355        $this->assertTrue(is_array($entity['some_hstore']), "'some_hstore' is an array.");
356        $this->assertEquals($values, $entity['some_hstore'], "'some_hstore' array is preserved.");
357    }
358
359    /**
360     * @depends testInteger
361     **/
362    public function testLTree()
363    {
364        if (static::$cv_map->alterLTree() === false)
365        {
366            $this->markTestSkipped("Ltree extension could not be found in Postgres, tests skipped.");
367
368            return;
369        }
370
371        $entity = static::$cv_map->findAll()->current();
372        $values = array(
373            'some_ltree' => array('one', 'two', 'three', 'four'),
374            'arr_ltree' => array(
375                array('a', 'b', 'c', 'd'),
376                array('a', 'b', 'e', 'f')
377            ));
378
379        $entity->hydrate($values);
380        static::$cv_map->saveOne($entity);
381
382        $this->assertTrue(is_array($entity['some_ltree']), "'some_ltree' is an array.");
383        $this->assertEquals($values['some_ltree'], $entity['some_ltree'], "'some_ltree' is preserved.");
384        $this->assertEquals($values['arr_ltree'][0], $entity['arr_ltree'][0], "'arr_ltree' 1st element is preserved.");
385
386        $entity['arr_ltree'] = array(
387            array(),
388            null,
389            $entity['arr_ltree'][0],
390            array(),
391            $entity['arr_ltree'][1],
392            null);
393
394        static::$cv_map->updateOne($entity, array('arr_ltree'));
395
396        $this->assertEquals(array(), $entity['arr_ltree'][0], "Empty ltrees are preserved.");
397        $this->assertTrue(is_null($entity['arr_ltree'][1]), "Nulls are preserved.");
398        $this->assertTrue(is_array($entity['arr_ltree'][2]), "3rd element is an array.");
399        $this->assertEquals($values['arr_ltree'][0], $entity['arr_ltree'][2], "Ltree are preserved.");
400        $this->assertTrue(is_null($entity['arr_ltree'][5]), "5th element is null");
401    }
402
403    /**
404     * @depends testInteger
405     **/
406    public function testTsRange()
407    {
408        if (static::$cv_map->alterTsRange() === false)
409        {
410            $this->markTestSkipped("tsrange type could not be found, maybe Postgres version < 9.2. Tests skipped.");
411
412            return;
413        }
414
415        $entity = static::$cv_map->findAll()->current();
416        $value = new Type\TsRange(new \DateTime('2012-08-20'), new \DateTime('2012-09-01'), true);
417        $entity['some_tsrange'] = $value;
418
419        static::$cv_map->updateOne($entity, array('some_tsrange'));
420
421        $this->assertInstanceOf('\Pomm\Type\TsRange', $entity['some_tsrange'], "'some_tsrange' is a 'TsRange' type.");
422        $this->assertEquals($value->start->format('U'), $entity['some_tsrange']->start->format('U'), "Timestamps are equal.");
423
424        $entity['arr_tsrange'] = array($value, new Type\TsRange(new \DateTime('2012-12-21'), new \DateTime('2012-12-21 12:21:59')));
425
426        static::$cv_map->updateOne($entity, array('some_tsrange', 'arr_tsrange'));
427
428        $this->assertEquals(2, count($entity['arr_tsrange']), "There are 2 elements in the array.");
429        $this->assertInstanceOf('\Pomm\Type\TsRange', $entity['arr_tsrange'][1], "'arr_tsrange' element 1 is a 'TsRange' type.");
430        $this->assertEquals(44519, $entity['arr_tsrange'][1]->end->format('U') - $entity['arr_tsrange'][1]->start->format('U'), "Range is preserved.");
431
432        return $entity;
433    }
434
435    /**
436     * @depends testInteger
437     **/
438    public function testNumberRangeConverter()
439    {
440        if (static::$cv_map->alterNumberRange() === false)
441        {
442            $this->markTestSkipped("Range types could not be found, maybe Postgres version < 9.2. Tests skipped.");
443
444            return;
445        }
446
447        $entity = static::$cv_map->findAll()->current();
448
449        $entity['some_int4range'] = new Type\NumberRange(-5, 45, true, false);
450        $entity['some_int8range'] = new Type\NumberRange(4452940833, 4553946490);
451        $entity['some_numrange']  = new Type\NumberRange(29.76607095, 30.44125206, false, false);
452        $entity['arr_numrange']   = array(new Type\NumberRange(1.1, 1.2), new Type\NumberRange(2.2, 2.4, true, false), new Type\NumberRange(3.3, 3.6, false, false));
453
454        static::$cv_map->updateOne($entity, array('some_int8range', 'some_int4range', 'some_numrange', 'arr_numrange'));
455
456        $this->assertEquals(new Type\NumberRange(-5, 45, true, false), $entity['some_int4range'], "Int4range is ok.");
457        $this->assertEquals(new Type\NumberRange(4452940834, 4553946490, true), $entity->getSomeInt8range(), "Int8range is ok.");
458        $this->assertEquals(new Type\NumberRange(29.76607095, 30.44125206, false, false), $entity['some_numrange'], "Numrange is ok.");
459        $this->assertTrue(is_array($entity['arr_numrange']), "'arr_numrange' is an array.");
460
461        for($x = 1; $x <= count($entity['arr_numrange']); $x++)
462        {
463            $range = $entity['arr_numrange'][$x - 1];
464            $this->assertInstanceOf('\Pomm\Type\NumberRange', $range, "Instance 'NumberRange'.");
465            $this->assertEquals((float) $x * 1.1, $range->start, "Range start is ok.");
466            $this->assertEquals((float) $x * 1.2, $range->end, "Range en is ok.");
467        }
468    }
469
470    /**
471     * @depends testInteger
472     **/
473    public function testSuperConverter()
474    {
475        $entity = static::$cv_map->findAll()->current();
476        $super_entity = new SuperConverterEntity(array('cv_entities' => array($entity)));
477
478        static::$super_cv_map->saveOne($super_entity);
479
480        $this->assertTrue(is_int($super_entity['id']), "'id' has been generated.");
481        $this->assertTrue(is_array($super_entity['cv_entities']), "'cv_entities' is an array.");
482        $this->assertInstanceOf('Pomm\Test\Converter\ConverterEntity', $super_entity['cv_entities'][0], "'cv_entities' is a ConverterEntity instance.");
483        $this->assertEquals(1, $super_entity['cv_entities'][0]->get('id'), "'id' is 1.");
484        $this->assertEquals(array(1.0, 1.1, null, 1.3), $super_entity['cv_entities'][0]->get('arr_fl'), "'arr_fl' of 'cv_entities' is preserved.");
485
486        $new_entity = new ConverterEntity(array('some_point' => new Type\Point(12,-3)));
487        $super_entity->add('cv_entities', $new_entity);
488        static::$super_cv_map->updateOne($super_entity, array('cv_entities'));
489
490        $this->assertInstanceOf('\Pomm\Type\Point', $super_entity['cv_entities'][1]['some_point'], "'some_point' of 2nd element is a Point.");
491        $this->assertEquals(12, $super_entity['cv_entities'][1]['some_point']->x, "With x = 12");
492        $this->assertEquals(-3, $super_entity['cv_entities'][1]['some_point']->y, "With y = -3");
493        $this->assertTrue(is_null($super_entity['cv_entities'][1]['some_bin']), "'some_bin' is null.");
494    }
495
496    /**
497     * @depends testInteger
498     **/
499    public function testTsExtendedEntity()
500    {
501        $ts_entity_map = static::$connection
502            ->getMapFor('\Pomm\Test\Converter\TsEntity');
503        $ts_entity_map->createTable();
504
505        $ts_extended_entity_map = static::$connection
506            ->getMapFor('\Pomm\Test\Converter\TsExtendedEntity');
507        $ts_extended_entity_map->createTable($ts_entity_map);
508
509        $collection = $ts_extended_entity_map->findAll();
510        $ts_extended_entity = $collection->current();
511
512        $this->assertInstanceOf('\Pomm\Test\Converter\TsEntity', $ts_extended_entity['p1'], "'p1' is a \\DateTime instance.");
513        $this->assertEquals('2000-02-29', $ts_extended_entity['p1']['p1']->format('Y-m-d'), 'Timestamp is preserved.');
514
515        foreach (array('1999-12-31 23:59:59.999999', '2005-01-29 23:01:58.000000') AS $key => $ts)
516        {
517            $this->assertEquals($ts, $ts_extended_entity['p2'][$key]['p1']->format('Y-m-d H:i:s.u'), 'Timestamp array is preserved.');
518        }
519
520        $ts_over_extended_entity_map = static::$connection
521            ->getMapFor('\Pomm\Test\Converter\TsOverExtendedEntity');
522        $ts_over_extended_entity_map->createTable($ts_extended_entity_map);
523
524        $collection = $ts_over_extended_entity_map->findAll();
525        $ts_over_extended_entity = $collection->current();
526
527        $this->assertInstanceOf('\Pomm\Test\Converter\TsExtendedEntity', $ts_over_extended_entity['p1'], "'p1' is a TsExtendedEntity instance.");
528        $this->assertTrue(is_array($ts_over_extended_entity['p2']), "'p2' is an Array.");
529        $this->assertInstanceOf('\Pomm\Test\Converter\TsExtendedEntity', $ts_over_extended_entity['p2'][0], "Which contains TsExtendedEntity instances.");
530    }
531}
532
533class ConverterEntityMap extends BaseObjectMap
534{
535    protected function initialize()
536    {
537        $this->object_class = '\Pomm\Test\Converter\ConverterEntity';
538        $this->object_name  = 'pomm_test.cv_entity';
539
540        $this->addField('id', 'int4');
541        $this->addField('fixed', 'numeric');
542        $this->addField('fl', 'float4');
543        $this->addField('arr_fl', 'float4[]');
544
545        $this->pk_fields = array('id');
546    }
547
548    public function createTable()
549    {
550        $sql = sprintf("CREATE TABLE %s (id serial PRIMARY KEY, fixed numeric(5,3), fl float4, arr_fl float4[])", $this->getTableName());
551        $this->connection->executeAnonymousQuery($sql);
552    }
553
554    protected function alterTable(Array $fields)
555    {
556        $this->connection->begin();
557        try
558        {
559            foreach($fields as $field => $type)
560            {
561                $sql = sprintf("ALTER TABLE %s ADD COLUMN %s %s", $this->getTableName(), $field, $type);
562                $this->connection->executeAnonymousQuery($sql);
563                $this->addField($field, strtok($type, '('));
564            }
565
566            $this->connection->commit();
567        }
568        catch(Exception $e)
569        {
570            $this->connection->rollback();
571
572            throw $e;
573        }
574    }
575
576    public function checkType($type)
577    {
578        $sql = sprintf("SELECT pg_namespace.nspname FROM pg_type JOIN pg_namespace ON pg_type.typnamespace = pg_namespace.oid WHERE typname = '%s'", $type);
579
580        return $this->connection
581            ->executeAnonymousQuery($sql)
582            ->fetchColumn(0);
583    }
584
585    public function alterText()
586    {
587        $this->alterTable(array('some_char' => 'char(10)', 'some_varchar' => 'varchar', 'some_text' => 'text', 'arr_varchar' => 'varchar[]'));
588    }
589
590    public function alterDate()
591    {
592        $this->alterTable(array('some_ts' => 'timestamp', 'some_intv' => 'interval', 'arr_ts' => 'timestamp[]'));
593    }
594
595    public function alterBool()
596    {
597        $this->alterTable(array('some_bool' => 'bool', 'arr_bool' => 'bool[]'));
598    }
599
600    public function alterBinary()
601    {
602        $this->alterTable(array('some_bin' => 'bytea', 'arr_bin' => 'bytea[]'));
603    }
604
605    public function alterPoint()
606    {
607        $this->alterTable(array('some_point' => 'point', 'arr_point' => 'point[]'));
608
609        $this->connection->getDatabase()
610            ->registerConverter('Point', new Converter\PgPoint(), array('point'));
611    }
612
613    public function alterCircle()
614    {
615        $this->alterTable(array('some_circle' => 'circle', 'arr_circle' => 'circle[]'));
616
617        $this->connection->getDatabase()
618            ->registerConverter('Circle', new Converter\PgCircle(), array('circle'));
619    }
620
621    public function alterSegment()
622    {
623        $this->alterTable(array('some_lseg' => 'lseg', 'arr_lseg' => 'lseg[]'));
624
625        $this->connection->getDatabase()
626            ->registerConverter('Segment', new Converter\PgLseg(), array('lseg'));
627    }
628
629    public function alterHStore()
630    {
631        if ($schema = $this->checkType('hstore') === false)
632        {
633            return false;
634        }
635
636        $this->alterTable(array('some_hstore' => 'hstore'));
637
638        $this->connection->getDatabase()
639            ->registerConverter('HStore', new Converter\PgHStore(), array('hstore', 'public.hstore', $schema.'.hstore'));
640    }
641
642    public function alterLTree()
643    {
644        if ($schema = $this->checkType('ltree') === false)
645        {
646            return false;
647        }
648
649        $this->alterTable(array('some_ltree' => 'ltree', 'arr_ltree' => 'ltree[]'));
650
651        $this->connection->getDatabase()
652            ->registerConverter('LTree', new Converter\PgLTree(), array('ltree', 'public.ltree', $schema.'.ltree'));
653    }
654
655    public function alterTsRange()
656    {
657        if ($schema = $this->checkType('tsrange') === false)
658        {
659            return false;
660        }
661
662        $this->alterTable(array('some_tsrange' => 'tsrange', 'arr_tsrange' => 'tsrange[]'));
663
664        $this->connection->getDatabase()
665            ->registerConverter('tsrange', new Converter\PgTsRange(), array('tsrange', 'public.tsrange', $schema.'.tsrange'));
666    }
667
668    public function alterJson()
669    {
670        if ($schema = $this->checkType('json') === false)
671        {
672            return false;
673        }
674
675        $this->alterTable(array('some_json' => 'json'));
676    }
677
678    public function alterNumberRange()
679    {
680        if ($schema = $this->checkType('numrange') === false)
681        {
682            return false;
683        }
684
685        $this->alterTable(array('some_int4range' => 'int4range', 'some_int8range' => 'int8range', 'some_numrange' => 'numrange', 'arr_numrange' => 'numrange[]'));
686    }
687}
688
689class ConverterEntity extends BaseObject
690{
691}
692
693class SuperConverterEntityMap extends BaseObjectMap
694{
695    protected function initialize()
696    {
697        $this->object_class = '\Pomm\Test\Converter\SuperConverterEntity';
698        $this->object_name  = 'pomm_test.super_cv_entity';
699
700        $this->addField('id', 'int4');
701        $this->addField('cv_entities', 'pomm_test.cv_entity[]');
702
703        $this->pk_fields = array('id');
704    }
705
706    public function createTable(ConverterEntityMap $map)
707    {
708        $sql = sprintf('CREATE TABLE %s (id serial PRIMARY KEY, cv_entities pomm_test.cv_entity[])', $this->getTableName());
709        $this->connection
710            ->executeAnonymousQuery($sql);
711
712        $this->connection
713            ->getDatabase()
714            ->registerConverter('ConverterEntity', new Converter\PgEntity($map), array('pomm_test.cv_entity'));
715    }
716}
717
718class SuperConverterEntity extends BaseObject
719{
720}
721
722class TsEntityMap extends BaseObjectMap
723{
724    protected function initialize()
725    {
726        $this->object_class = '\Pomm\Test\Converter\TsEntity';
727        $this->object_name = "( VALUES ('1999-12-31 23:59:59.999999'::timestamp) ) AS ts_entity (p1)";
728
729        $this->addField('p1', 'timestamp');
730
731        $this->pk_fields = array();
732    }
733
734    public function createTable()
735    {
736        $sql = 'CREATE TYPE pomm_test.ts_entity AS (p1 timestamp)';
737        $this->connection
738            ->executeAnonymousQuery($sql);
739    }
740}
741
742class TsEntity extends BaseObject
743{
744}
745
746class TsExtendedEntityMap extends BaseObjectMap
747{
748    protected function initialize()
749    {
750        $this->object_class = '\Pomm\Test\Converter\TsExtendedEntity';
751        $this->object_name  = <<<SQL
752( VALUES 
753  ( ROW('2000-02-29'::timestamp)::pomm_test.ts_entity, ARRAY[ROW('1999-12-31 23:59:59.999999'::timestamp)::pomm_test.ts_entity, ROW('2005-01-29 23:01:58'::timestamp)::pomm_test.ts_entity]::pomm_test.ts_entity[] ),
754  ( ROW('2004-02-29'::timestamp)::pomm_test.ts_entity, ARRAY[ROW('1989-12-31 23:59:59.999999'::timestamp)::pomm_test.ts_entity, ROW('2005-01-29 23:01:58'::timestamp)::pomm_test.ts_entity]::pomm_test.ts_entity[] )
755) ts_extended_entity (p1, p2)
756SQL;
757
758        $this->addField('p1', 'pomm_test.ts_entity');
759        $this->addField('p2', 'pomm_test.ts_entity[]');
760
761        $this->pk_fields = array();
762    }
763
764    public function createTable(TsEntityMap $map)
765    {
766        $sql = 'CREATE TYPE pomm_test.ts_extended_entity AS (p1 pomm_test.ts_entity, p2 pomm_test.ts_entity[])';
767        $this->connection
768            ->executeAnonymousQuery($sql);
769
770        $this->connection
771            ->getDatabase()
772            ->registerConverter('TsEntityConverter', new Converter\PgEntity($map), array('pomm_test.ts_entity', 'ts_entity'));
773    }
774}
775
776class TsExtendedEntity extends BaseObject
777{
778}
779
780class TsOverExtendedEntityMap extends BaseObjectMap
781{
782    protected function initialize()
783    {
784        $this->object_class = '\Pomm\Test\Converter\TsOverExtendedEntity';
785        $this->object_name  = <<<SQL
786( VALUES 
787  ( ROW(ROW('2000-02-29'::timestamp)::pomm_test.ts_entity, ARRAY[ROW('1999-12-31 23:59:59.999999'::timestamp)::pomm_test.ts_entity, ROW('2005-01-29 23:01:58'::timestamp)::pomm_test.ts_entity]::pomm_test.ts_entity[] )::pomm_test.ts_extended_entity, ARRAY[ROW(ROW('2004-02-29'::timestamp)::pomm_test.ts_entity, ARRAY[ROW('1989-12-31 23:59:59.999999'::timestamp)::pomm_test.ts_entity, ROW('2005-01-29 23:01:58'::timestamp)::pomm_test.ts_entity]::pomm_test.ts_entity[])::pomm_test.ts_extended_entity]::pomm_test.ts_extended_entity[] )
788) ts_over_extended_entity (p1, p2)
789SQL;
790
791        $this->addField('p1', 'pomm_test.ts_extended_entity');
792        $this->addField('p2', 'pomm_test.ts_extended_entity[]');
793
794        $this->pk_fields = array();
795    }
796
797    public function createTable(TsExtendedEntityMap $map)
798    {
799        $sql = 'CREATE TYPE pomm_test.ts_over_extended_entity AS (p1 pomm_test.ts_extended_entity, p2 pomm_test.ts_extended_entity[])';
800        $this->connection
801            ->executeAnonymousQuery($sql);
802
803        $this->connection
804            ->getDatabase()
805            ->registerConverter('TsExtendedEntityConverter', new Converter\PgEntity($map), array('pomm_test.ts_extended_entity', 'pomm_test.extended_entity'));
806    }
807}
808
809class TsOverExtendedEntity extends BaseObject 
810{
811}