PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

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