Skip to content

Commit 47938ce

Browse files
fix for bcmatch when it has problem with big fraction in scientific notation. Simplified packing structure to allow inheritance on structure classes.
1 parent 9703c91 commit 47938ce

File tree

8 files changed

+31
-35
lines changed

8 files changed

+31
-35
lines changed

src/PackStream/v1/Packer.php

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,16 @@ class Packer implements IPacker
3434
private const HUGE = 4294967295;
3535

3636
private $structuresLt = [
37-
Relationship::class => [0x52, 'packInteger', 'packInteger', 'packInteger', 'packString', 'packMap'],
38-
Date::class => [0x44, 'packInteger'],
39-
Time::class => [0x54, 'packInteger', 'packInteger'],
40-
LocalTime::class => [0x74, 'packInteger'],
41-
DateTime::class => [0x46, 'packInteger', 'packInteger', 'packInteger'],
42-
DateTimeZoneId::class => [0x66, 'packInteger', 'packInteger', 'packString'],
43-
LocalDateTime::class => [0x64, 'packInteger', 'packInteger'],
44-
Duration::class => [0x45, 'packInteger', 'packInteger', 'packInteger', 'packInteger'],
45-
Point2D::class => [0x58, 'packInteger', 'packFloat', 'packFloat'],
46-
Point3D::class => [0x59, 'packInteger', 'packFloat', 'packFloat', 'packFloat']
37+
Relationship::class => [0x52, 'id' => 'packInteger', 'startNodeId' => 'packInteger', 'endNodeId' => 'packInteger', 'type' => 'packString', 'properties' => 'packMap'],
38+
Date::class => [0x44, 'days' => 'packInteger'],
39+
Time::class => [0x54, 'nanoseconds' => 'packInteger', 'tz_offset_seconds' => 'packInteger'],
40+
LocalTime::class => [0x74, 'nanoseconds' => 'packInteger'],
41+
DateTime::class => [0x46, 'seconds' => 'packInteger', 'nanoseconds' => 'packInteger', 'tz_offset_seconds' => 'packInteger'],
42+
DateTimeZoneId::class => [0x66, 'seconds' => 'packInteger', 'nanoseconds' => 'packInteger', 'tz_id' => 'packString'],
43+
LocalDateTime::class => [0x64, 'seconds' => 'packInteger', 'nanoseconds' => 'packInteger'],
44+
Duration::class => [0x45, 'months' => 'packInteger', 'days' => 'packInteger', 'seconds' => 'packInteger', 'nanoseconds' => 'packInteger'],
45+
Point2D::class => [0x58, 'srid' => 'packInteger', 'x' => 'packFloat', 'y' => 'packFloat'],
46+
Point3D::class => [0x59, 'srid' => 'packInteger', 'x' => 'packFloat', 'y' => 'packFloat', 'z' => 'packFloat']
4747
];
4848

4949
/**
@@ -257,24 +257,15 @@ private function packList(array $arr): string
257257
*/
258258
private function packStructure(IStructure $structure): string
259259
{
260-
$reflection = new \ReflectionClass($structure);
261-
$properties = $reflection->getProperties();
262-
$cnt = count($properties);
263-
264260
if (!array_key_exists(get_class($structure), $this->structuresLt)) {
265261
throw new PackException('Provided structure as parameter is not supported');
266262
}
267263

268264
$arr = $this->structuresLt[get_class($structure)];
269-
if (count($arr) != $cnt + 1) {
270-
throw new PackException('Invalid amount of structure properties');
271-
}
272-
273-
$output = pack('C', 0b10110000 | $cnt);
274-
$output .= chr(array_shift($arr));
275-
foreach ($arr as $i => $method) {
276-
$properties[$i]->setAccessible(true);
277-
$output .= $this->{$method}($properties[$i]->getValue($structure));
265+
$signature = chr(array_shift($arr));
266+
$output = pack('C', 0b10110000 | count($arr)) . $signature;
267+
foreach ($arr as $structureMethod => $packerMethod) {
268+
$output .= $this->{$packerMethod}($structure->{$structureMethod}());
278269
}
279270

280271
return $output;

src/structures/DateTime.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function tz_offset_seconds(): int
7676

7777
public function __toString(): string
7878
{
79-
$ts = bcadd($this->seconds - $this->tz_offset_seconds, bcdiv($this->nanoseconds, 10e8, 6), 6);
79+
$ts = bcadd($this->seconds - $this->tz_offset_seconds, bcdiv($this->nanoseconds, 1e9, 6), 6);
8080
return \DateTime::createFromFormat('U.u', $ts, new \DateTimeZone('UTC'))
8181
->setTimezone(new \DateTimeZone(sprintf("%+'05d", $this->tz_offset_seconds / 3600 * 100)))
8282
->format('Y-m-d\TH:i:s.uP');

src/structures/DateTimeZoneId.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function tz_id(): string
7676

7777
public function __toString(): string
7878
{
79-
$timestamp = bcadd($this->seconds(), bcdiv($this->nanoseconds, 10e8, 6), 6);
79+
$timestamp = bcadd($this->seconds, bcdiv($this->nanoseconds, 1e9, 6), 6);
8080
return \DateTime::createFromFormat('U.u', $timestamp, new \DateTimeZone($this->tz_id))
8181
->format('Y-m-d\TH:i:s.u') . '[' . $this->tz_id . ']';
8282
}

src/structures/Duration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function __toString(): string
102102
if (!empty($minutes))
103103
$time .= $minutes . 'M';
104104

105-
$seconds = rtrim(bcadd($this->seconds % 3600 % 60, bcdiv($this->nanoseconds, 10e8, 6), 6), '0.');
105+
$seconds = rtrim(bcadd($this->seconds % 3600 % 60, bcdiv($this->nanoseconds, 1e9, 6), 6), '0.');
106106
if (!empty($seconds))
107107
$time .= $seconds . 'S';
108108

src/structures/LocalDateTime.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function nanoseconds(): int
5656

5757
public function __toString(): string
5858
{
59-
return \DateTime::createFromFormat('U.u', bcadd($this->seconds, bcdiv($this->nanoseconds, 10e8, 6), 6))
59+
return \DateTime::createFromFormat('U.u', bcadd($this->seconds, bcdiv($this->nanoseconds, 1e9, 6), 6))
6060
->format('Y-m-d\TH:i:s.u');
6161
}
6262

src/structures/LocalTime.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function nanoseconds(): int
4040

4141
public function __toString(): string
4242
{
43-
return \DateTime::createFromFormat('U.u', bcdiv($this->nanoseconds, 10e8, 6))
43+
return \DateTime::createFromFormat('U.u', bcdiv($this->nanoseconds, 1e9, 6))
4444
->format('H:i:s.u');
4545
}
4646
}

src/structures/Time.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function tz_offset_seconds(): int
5959

6060
public function __toString(): string
6161
{
62-
$ts = bcsub(bcdiv($this->nanoseconds, 10e8, 6), $this->tz_offset_seconds, 6);
62+
$ts = bcsub(bcdiv($this->nanoseconds, 1e9, 6), $this->tz_offset_seconds, 6);
6363
return \DateTime::createFromFormat('U.u', $ts, new \DateTimeZone('UTC'))
6464
->setTimezone(new \DateTimeZone(sprintf("%+'05d", $this->tz_offset_seconds / 3600 * 100)))
6565
->format('H:i:s.uP');

tests/StructuresTest.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function testDate(int $timestamp, AProtocol $protocol)
111111
public function testDateTime(int $timestamp, string $timezone, AProtocol $protocol)
112112
{
113113
try {
114-
$timestamp = bcadd($timestamp, fmod(microtime(true), 1), 6);
114+
$timestamp = bcadd($timestamp, sprintf('%.6f', fmod(microtime(true), 1)), 6);
115115
$datetime = \DateTime::createFromFormat('U.u', $timestamp, new \DateTimeZone($timezone))
116116
->format('Y-m-d\TH:i:s.uP');
117117

@@ -143,7 +143,7 @@ public function testDateTime(int $timestamp, string $timezone, AProtocol $protoc
143143
public function testDateTimeZoneId(int $timestamp, string $timezone, AProtocol $protocol)
144144
{
145145
try {
146-
$timestamp = bcadd($timestamp, fmod(microtime(true), 1), 6);
146+
$timestamp = bcadd($timestamp, sprintf('%.6f', fmod(microtime(true), 1)), 6);
147147
$datetime = \DateTime::createFromFormat('U.u', $timestamp, new \DateTimeZone($timezone))
148148
->format('Y-m-d\TH:i:s.u') . '[' . $timezone . ']';
149149

@@ -165,7 +165,12 @@ public function testDateTimeZoneId(int $timestamp, string $timezone, AProtocol $
165165
$rows[0][0] = preg_replace("/([+\-]\d{2}:\d{2}|Z)\[/", '[', $rows[0][0]);
166166
$this->assertEquals($datetime, $rows[0][0], 'pack ' . $datetime . ' != ' . $rows[0][0]);
167167
} catch (Exception $e) {
168-
$this->markTestIncomplete($e->getMessage());
168+
if (strpos($e->getMessage(), 'Invalid value for TimeZone: Text \'' . $timezone . '\'') === 0) {
169+
$protocol->reset();
170+
$this->markTestSkipped('Test skipped because Neo4j missing timezone ID ' . $timezone);
171+
} else {
172+
$this->markTestIncomplete($e->getMessage());
173+
}
169174
}
170175
}
171176

@@ -209,7 +214,7 @@ public function testDuration(AProtocol $protocol)
209214
public function testLocalDateTime(int $timestamp, AProtocol $protocol)
210215
{
211216
try {
212-
$timestamp = bcadd($timestamp, fmod(microtime(true), 1), 6);
217+
$timestamp = bcadd($timestamp, sprintf('%.6f', fmod(microtime(true), 1)), 6);
213218
$datetime = \DateTime::createFromFormat('U.u', $timestamp)
214219
->format('Y-m-d\TH:i:s.u');
215220

@@ -240,7 +245,7 @@ public function testLocalDateTime(int $timestamp, AProtocol $protocol)
240245
public function testLocalTime(int $timestamp, AProtocol $protocol)
241246
{
242247
try {
243-
$timestamp = bcadd($timestamp, fmod(microtime(true), 1), 6);
248+
$timestamp = bcadd($timestamp, sprintf('%.6f', fmod(microtime(true), 1)), 6);
244249
$time = \DateTime::createFromFormat('U.u', $timestamp)
245250
->format('H:i:s.u');
246251

@@ -381,7 +386,7 @@ public function testRelationship(AProtocol $protocol)
381386
public function testTime(int $timestamp, string $timezone, AProtocol $protocol)
382387
{
383388
try {
384-
$timestamp = bcadd($timestamp, fmod(microtime(true), 1), 6);
389+
$timestamp = bcadd($timestamp, sprintf('%.6f', fmod(microtime(true), 1)), 6);
385390
$time = \DateTime::createFromFormat('U.u', $timestamp, new \DateTimeZone($timezone))
386391
->format('H:i:s.uP');
387392

0 commit comments

Comments
 (0)