Skip to content

Commit e7c3a8b

Browse files
committed
Introduce codecs to work with lazy BSON objects
1 parent 835a2b7 commit e7c3a8b

15 files changed

+1009
-26
lines changed

psalm-baseline.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@
2828
<code>($value is NativeType ? BSONType : $value)</code>
2929
</MixedInferredReturnType>
3030
</file>
31+
<file src="src/Codec/LazyBSONArrayCodec.php">
32+
<MixedAssignment>
33+
<code>$return[]</code>
34+
</MixedAssignment>
35+
</file>
36+
<file src="src/Codec/LazyBSONDocumentCodec.php">
37+
<MixedAssignment>
38+
<code>$return[$field]</code>
39+
</MixedAssignment>
40+
</file>
3141
<file src="src/Command/ListCollections.php">
3242
<MixedAssignment>
3343
<code>$cmd[$option]</code>

src/Codec/ArrayCodec.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
/*
3+
* Copyright 2023-present MongoDB, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace MongoDB\Codec;
19+
20+
use MongoDB\Exception\UnsupportedValueException;
21+
22+
use function array_map;
23+
use function is_array;
24+
25+
/**
26+
* Codec to recursively encode/decode values in arrays.
27+
*
28+
* @template-implements Codec<array, array>
29+
*/
30+
class ArrayCodec implements Codec, KnowsCodecLibrary
31+
{
32+
private ?CodecLibrary $library = null;
33+
34+
public function attachCodecLibrary(CodecLibrary $library): void
35+
{
36+
$this->library = $library;
37+
}
38+
39+
/**
40+
* @param mixed $value
41+
* @psalm-assert-if-true array $value
42+
*/
43+
public function canDecode($value): bool
44+
{
45+
return is_array($value);
46+
}
47+
48+
/**
49+
* @param mixed $value
50+
* @psalm-assert-if-true array $value
51+
*/
52+
public function canEncode($value): bool
53+
{
54+
return is_array($value);
55+
}
56+
57+
/** @param mixed $value */
58+
public function decode($value): array
59+
{
60+
if (! $this->canDecode($value)) {
61+
throw UnsupportedValueException::invalidDecodableValue($value);
62+
}
63+
64+
return array_map(
65+
/**
66+
* @param mixed $item
67+
* @return mixed
68+
*/
69+
function ($item) {
70+
return $this->getLibrary()->decodeIfSupported($item);
71+
},
72+
$value,
73+
);
74+
}
75+
76+
/**
77+
* @param mixed $value
78+
* @return mixed
79+
* @psalm-return ($value is array ? array : $value)
80+
*/
81+
public function decodeIfSupported($value)
82+
{
83+
return $this->canDecode($value) ? $this->decode($value) : $value;
84+
}
85+
86+
/** @param mixed $value */
87+
public function encode($value): array
88+
{
89+
if (! $this->canEncode($value)) {
90+
throw UnsupportedValueException::invalidEncodableValue($value);
91+
}
92+
93+
return array_map(
94+
/**
95+
* @param mixed $item
96+
* @return mixed
97+
*/
98+
function ($item) {
99+
return $this->getLibrary()->encodeIfSupported($item);
100+
},
101+
$value,
102+
);
103+
}
104+
105+
/**
106+
* @param mixed $value
107+
* @return mixed
108+
* @psalm-return ($value is array ? array : $value)
109+
*/
110+
public function encodeIfSupported($value)
111+
{
112+
return $this->canEncode($value) ? $this->encode($value) : $value;
113+
}
114+
115+
private function getLibrary(): CodecLibrary
116+
{
117+
if (! $this->library) {
118+
$this->library = new CodecLibrary();
119+
}
120+
121+
return $this->library;
122+
}
123+
}

src/Codec/LazyBSONArrayCodec.php

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
/*
3+
* Copyright 2023-present MongoDB, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace MongoDB\Codec;
19+
20+
use MongoDB\BSON\PackedArray;
21+
use MongoDB\Exception\UnsupportedValueException;
22+
use MongoDB\Model\LazyBSONArray;
23+
24+
/**
25+
* Codec for lazy decoding of BSON PackedArray instances
26+
*
27+
* @template-implements Codec<PackedArray, LazyBSONArray>
28+
*/
29+
class LazyBSONArrayCodec implements Codec, KnowsCodecLibrary
30+
{
31+
private ?CodecLibrary $library = null;
32+
33+
public function attachCodecLibrary(CodecLibrary $library): void
34+
{
35+
$this->library = $library;
36+
}
37+
38+
/**
39+
* @param mixed $value
40+
* @psalm-assert-if-true PackedArray $value
41+
*/
42+
public function canDecode($value): bool
43+
{
44+
return $value instanceof PackedArray;
45+
}
46+
47+
/**
48+
* @param mixed $value
49+
* @psalm-assert-if-true LazyBSONArray $value
50+
*/
51+
public function canEncode($value): bool
52+
{
53+
return $value instanceof LazyBSONArray;
54+
}
55+
56+
/** @param mixed $value */
57+
public function decode($value): LazyBSONArray
58+
{
59+
if (! $value instanceof PackedArray) {
60+
throw UnsupportedValueException::invalidDecodableValue($value);
61+
}
62+
63+
return new LazyBSONArray($value, $this->getLibrary());
64+
}
65+
66+
/**
67+
* @param mixed $value
68+
* @return mixed
69+
* @psalm-return ($value is PackedArray ? LazyBSONArray : $value)
70+
*/
71+
public function decodeIfSupported($value)
72+
{
73+
return $this->canDecode($value) ? $this->decode($value) : $value;
74+
}
75+
76+
/** @param mixed $value */
77+
public function encode($value): PackedArray
78+
{
79+
if (! $value instanceof LazyBSONArray) {
80+
throw UnsupportedValueException::invalidEncodableValue($value);
81+
}
82+
83+
$return = [];
84+
/** @var mixed $offsetValue */
85+
foreach ($value as $offsetValue) {
86+
$return[] = $this->getLibrary()->encodeIfSupported($offsetValue);
87+
}
88+
89+
return PackedArray::fromPHP($return);
90+
}
91+
92+
/**
93+
* @param mixed $value
94+
* @return mixed
95+
* @psalm-return ($value is LazyBSONArray ? PackedArray : $value)
96+
*/
97+
public function encodeIfSupported($value)
98+
{
99+
return $this->canEncode($value) ? $this->encode($value) : $value;
100+
}
101+
102+
private function getLibrary(): CodecLibrary
103+
{
104+
if (! $this->library) {
105+
$this->library = new LazyBSONCodecLibrary();
106+
}
107+
108+
return $this->library;
109+
}
110+
}

src/Codec/LazyBSONCodecLibrary.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
/*
3+
* Copyright 2023-present MongoDB, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace MongoDB\Codec;
19+
20+
class LazyBSONCodecLibrary extends CodecLibrary
21+
{
22+
public function __construct()
23+
{
24+
parent::__construct(
25+
new LazyBSONDocumentCodec(),
26+
new LazyBSONArrayCodec(),
27+
new ArrayCodec(),
28+
new ObjectCodec(),
29+
);
30+
}
31+
}

src/Codec/LazyBSONDocumentCodec.php

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
<?php
2+
/*
3+
* Copyright 2023-present MongoDB, Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
namespace MongoDB\Codec;
19+
20+
use MongoDB\BSON\Document;
21+
use MongoDB\Exception\UnsupportedValueException;
22+
use MongoDB\Model\LazyBSONDocument;
23+
24+
/**
25+
* Codec for lazy decoding of BSON Document instances
26+
*
27+
* @template-implements DocumentCodec<LazyBSONDocument>
28+
*/
29+
class LazyBSONDocumentCodec implements DocumentCodec, KnowsCodecLibrary
30+
{
31+
private ?CodecLibrary $library = null;
32+
33+
public function attachCodecLibrary(CodecLibrary $library): void
34+
{
35+
$this->library = $library;
36+
}
37+
38+
/**
39+
* @param mixed $value
40+
* @psalm-assert-if-true Document $value
41+
*/
42+
public function canDecode($value): bool
43+
{
44+
return $value instanceof Document;
45+
}
46+
47+
/**
48+
* @param mixed $value
49+
* @psalm-assert-if-true LazyBSONDocument $value
50+
*/
51+
public function canEncode($value): bool
52+
{
53+
return $value instanceof LazyBSONDocument;
54+
}
55+
56+
/** @param mixed $value */
57+
public function decode($value): LazyBSONDocument
58+
{
59+
if (! $value instanceof Document) {
60+
throw UnsupportedValueException::invalidDecodableValue($value);
61+
}
62+
63+
return new LazyBSONDocument($value, $this->getLibrary());
64+
}
65+
66+
/**
67+
* @param mixed $value
68+
* @return mixed
69+
* @psalm-return ($value is Document ? LazyBSONDocument : $value)
70+
*/
71+
public function decodeIfSupported($value)
72+
{
73+
return $this->canDecode($value) ? $this->decode($value) : $value;
74+
}
75+
76+
/** @param mixed $value */
77+
public function encode($value): Document
78+
{
79+
if (! $value instanceof LazyBSONDocument) {
80+
throw UnsupportedValueException::invalidEncodableValue($value);
81+
}
82+
83+
$return = [];
84+
/** @var mixed $fieldValue */
85+
foreach ($value as $field => $fieldValue) {
86+
$return[$field] = $this->getLibrary()->encodeIfSupported($fieldValue);
87+
}
88+
89+
return Document::fromPHP($return);
90+
}
91+
92+
/**
93+
* @param mixed $value
94+
* @return mixed
95+
* @psalm-return ($value is LazyBSONDocument ? Document : $value)
96+
*/
97+
public function encodeIfSupported($value)
98+
{
99+
return $this->canEncode($value) ? $this->encode($value) : $value;
100+
}
101+
102+
private function getLibrary(): CodecLibrary
103+
{
104+
if (! $this->library) {
105+
$this->library = new LazyBSONCodecLibrary();
106+
}
107+
108+
return $this->library;
109+
}
110+
}

0 commit comments

Comments
 (0)