Skip to content

Commit e7c2b6f

Browse files
committed
Add Postgres document store
0 parents  commit e7c2b6f

15 files changed

+1281
-0
lines changed

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
nbproject
2+
._*
3+
.~lock.*
4+
.buildpath
5+
.DS_Store
6+
.idea
7+
.php_cs.cache
8+
.project
9+
.settings
10+
vendor
11+
composer.lock
12+
.phpunit.result.cache

LICENSE

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2019, prooph software GmbH
4+
All rights reserved.
5+
6+
Redistribution and use in source and binary forms, with or without
7+
modification, are permitted provided that the following conditions are met:
8+
9+
* Redistributions of source code must retain the above copyright notice, this
10+
list of conditions and the following disclaimer.
11+
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
16+
* Neither the name of the copyright holder nor the names of its
17+
contributors may be used to endorse or promote products derived from
18+
this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# postgres-document-store
2+
PostgreSQL [Document Store for Event Engine](https://github.com/event-engine/php-engine/blob/master/document-store/src/DocumentStore.php)
3+
4+

bin/test_store.php

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
<?php
2+
/**
3+
* This file is part of the event-engine/php-postgres-document-store.
4+
* (c) 2019 prooph software GmbH <contact@prooph.de>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
use EventEngine\DocumentStore\Filter;
13+
use EventEngine\DocumentStore\OrderBy;
14+
use EventEngine\DocumentStore;
15+
16+
require_once __DIR__ .'/../vendor/autoload.php';
17+
18+
$dsn = getenv('PDO_DSN');
19+
$usr = getenv('PDO_USER');
20+
$pwd = getenv('PDO_PWD');
21+
22+
$pdo = new \PDO($dsn, $usr, $pwd);
23+
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
24+
25+
$pdo->prepare("DROP TABLE IF EXISTS em_ds_docs")->execute();
26+
$pdo->prepare("DROP TABLE IF EXISTS em_ds_animals")->execute();
27+
$pdo->prepare("DROP TABLE IF EXISTS em_ds_test")->execute();
28+
29+
$documentStore = new \EventEngine\DocumentStore\Postgres\PostgresDocumentStore($pdo);
30+
31+
$documentStore->addCollection('test');
32+
$documentStore->addCollection('animals',
33+
DocumentStore\FieldIndex::forField('name', DocumentStore\FieldIndex::SORT_DESC, true),
34+
DocumentStore\MultiFieldIndex::forFields([
35+
DocumentStore\FieldIndex::forField('character.friendly'),
36+
DocumentStore\FieldIndex::forField('pet')
37+
])
38+
);
39+
40+
$collections = $documentStore->listCollections();
41+
42+
foreach ($collections as $col) {
43+
echo "Collection: $col\n";
44+
}
45+
46+
$collections = $documentStore->filterCollectionsByPrefix('do');
47+
48+
foreach ($collections as $col) {
49+
echo "Filtered Collection: $col\n";
50+
}
51+
52+
echo "Has test: " . ($documentStore->hasCollection('test')? 'YES' : 'NO') . "\n";
53+
echo "Has dogs: " . ($documentStore->hasCollection('dogs')? 'YES' : 'NO') . "\n";
54+
55+
$documentStore->dropCollection('test');
56+
echo "Table test dropped\n";
57+
echo "Has test: " . ($documentStore->hasCollection('test')? 'YES' : 'NO') . "\n";
58+
59+
$docId1 = '0e2c39b1-0778-4e92-a06b-0fa1c6ae9c5d';
60+
$docId2 = '0e2ec294-df90-4bd7-a934-74747752f0bb';
61+
$docId3 = '5bd4fdee-bfe2-4e1d-a4bf-b27e57fa1686';
62+
63+
$documentStore->addDoc('animals', $docId1, [
64+
'animal' => 'dog',
65+
'name' => 'Jack',
66+
'age' => 5,
67+
'character' => [
68+
'friendly' => 10,
69+
'wild' => 6,
70+
'docile' => 8
71+
]
72+
]);
73+
74+
$jack = $documentStore->getDoc('animals', $docId1);
75+
76+
echo "Jack: " . json_encode($jack) . "\n";
77+
78+
try {
79+
$documentStore->upsertDoc('animals', $docId2, [
80+
'animal' => 'cat',
81+
'name' => 'Jack',
82+
'age' => 5,
83+
'character' => [
84+
'friendly' => 3,
85+
'wild' => 7,
86+
'docile' => 2
87+
]
88+
]);
89+
} catch (PDOException $exception) {
90+
if($exception->errorInfo[0] === "23505") {
91+
echo "Cannot add Jack twice due to unqiue index on name.\n";
92+
} else {
93+
throw $exception;
94+
}
95+
}
96+
97+
$documentStore->upsertDoc('animals', $docId2, [
98+
'animal' => 'cat',
99+
'name' => 'Tiger',
100+
'age' => 5,
101+
'character' => [
102+
'friendly' => 3,
103+
'wild' => 7,
104+
'docile' => 2
105+
]
106+
]);
107+
108+
$documentStore->upsertDoc('animals', $docId2, [
109+
'age' => 3
110+
]);
111+
112+
$tiger = $documentStore->getDoc('animals', $docId2);
113+
114+
echo "Tiger: " . json_encode($tiger) . "\n";
115+
116+
$documentStore->addDoc('animals', $docId3, [
117+
'animal' => 'cat',
118+
'name' => 'Gini',
119+
'age' => 5,
120+
'character' => [
121+
'friendly' => 8,
122+
'wild' => 3,
123+
'docile' => 4
124+
]
125+
]);
126+
127+
$cats = $documentStore->filterDocs('animals', new Filter\EqFilter('animal', 'cat'));
128+
129+
foreach ($cats as $cat) {
130+
echo "Cat: " . json_encode($cat) . "\n";
131+
}
132+
133+
$tiNames = $documentStore->filterDocs(
134+
'animals',
135+
new Filter\LikeFilter('name', 'Ti%')
136+
);
137+
138+
foreach ($tiNames as $tiName) {
139+
echo "Animal name starting with Ti: " . json_encode($tiName) . "\n";
140+
}
141+
142+
$documentStore->updateMany('animals', new Filter\GteFilter('character.friendly', 5), ['pet' => true]);
143+
144+
$pets = $documentStore->filterDocs('animals', new Filter\EqFilter('pet', true));
145+
146+
foreach ($pets as $pet) {
147+
echo "Pet: " . json_encode($pet) . "\n";
148+
}
149+
150+
$superFriendlyPets = $documentStore->filterDocs(
151+
'animals',
152+
new Filter\AndFilter(
153+
new Filter\EqFilter('pet', true),
154+
new Filter\EqFilter('character.friendly', 10)
155+
)
156+
);
157+
158+
foreach ($superFriendlyPets as $pet) {
159+
echo "Super friendly pet: " . json_encode($pet) . "\n";
160+
}
161+
162+
$documentStore->updateDoc('animals', $docId1, ['color' => ['black', 'white']]);
163+
$documentStore->updateDoc('animals', $docId2, ['color' => ['grey', 'black', 'white']]);
164+
$documentStore->updateDoc('animals', $docId3, ['color' => ['brown', 'red', 'white']]);
165+
166+
$petsWithBlack = $documentStore->filterDocs(
167+
'animals',
168+
new Filter\AndFilter(
169+
new Filter\EqFilter('pet', true),
170+
new Filter\InArrayFilter('color', 'black')
171+
)
172+
);
173+
174+
foreach ($petsWithBlack as $pet) {
175+
echo "Pet with black: " . json_encode($pet) . "\n";
176+
}
177+
178+
$noPets = $documentStore->filterDocs(
179+
'animals',
180+
new Filter\NotFilter(new Filter\ExistsFilter('pet'))
181+
);
182+
183+
foreach ($noPets as $pet) {
184+
echo "Not a pet: " . json_encode($pet) . "\n";
185+
}
186+
187+
$oldestAnimals = $documentStore->filterDocs(
188+
'animals',
189+
new Filter\AnyFilter(),
190+
null,
191+
2,
192+
OrderBy\AndOrder::by(
193+
OrderBy\Desc::byProp('age'),
194+
OrderBy\Asc::byProp('name')
195+
)
196+
);
197+
198+
foreach ($oldestAnimals as $animal) {
199+
echo "Old animal: " . json_encode($animal) . "\n";
200+
}
201+
202+
$sortedAnimals = $documentStore->filterDocs(
203+
'animals',
204+
new Filter\AnyFilter(),
205+
1,
206+
2,
207+
OrderBy\Asc::byProp('name')
208+
);
209+
210+
foreach ($sortedAnimals as $animal) {
211+
echo "Sorted animal: " . json_encode($animal) . "\n";
212+
}
213+
214+
215+
$documentStore->deleteDoc('animals', $docId2);
216+
echo "Deleted doc with id $docId2\n";
217+
218+
$animalsWithWhite = $documentStore->filterDocs(
219+
'animals',
220+
New Filter\InArrayFilter('color', 'white')
221+
);
222+
223+
foreach ($animalsWithWhite as $animal) {
224+
echo "Animal with color white: " . json_encode($animal) . "\n";
225+
}
226+
227+
$documentStore->deleteMany('animals', new Filter\InArrayFilter('color', 'white'));
228+
229+
echo "Deleted animals with color white\n";
230+
231+
$animalsWithWhite = $documentStore->filterDocs(
232+
'animals',
233+
New Filter\InArrayFilter('color', 'white')
234+
);
235+
236+
foreach ($animalsWithWhite as $animal) {
237+
echo "Animal with color white: " . json_encode($animal) . "\n";
238+
}

composer.json

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"name": "event-engine/php-postgres-document-store",
3+
"description": "PostgreSQL Document Store for Event Engine",
4+
"homepage": "http://prooph.de/",
5+
"license": "BSD-3-Clause",
6+
"authors": [
7+
{
8+
"name": "Alexander Miertsch",
9+
"email": "contact@prooph.de",
10+
"homepage": "http://www.prooph.de"
11+
},
12+
{
13+
"name": "Sandro Keil",
14+
"email": "contact@prooph.de",
15+
"homepage": "http://prooph-software.com/"
16+
}
17+
],
18+
"require": {
19+
"php": "^7.1",
20+
"ext-pdo": "*"
21+
},
22+
"require-dev": {
23+
"event-engine/php-engine": "dev-master",
24+
"infection/infection": "^0.11.0",
25+
"malukenho/docheader": "^0.1.4",
26+
"phpspec/prophecy": "^1.7",
27+
"phpstan/phpstan": "^0.10.5",
28+
"phpstan/phpstan-strict-rules": "^0.10.1",
29+
"phpunit/phpunit": "^8.0",
30+
"prooph/bookdown-template": "^0.2.3",
31+
"prooph/php-cs-fixer-config": "^0.3",
32+
"roave/security-advisories": "dev-master",
33+
"satooshi/php-coveralls": "^1.0"
34+
},
35+
"autoload": {
36+
"psr-4": {
37+
"EventEngine\\DocumentStore\\Postgres\\": "src/"
38+
}
39+
},
40+
"autoload-dev": {
41+
"psr-4": {
42+
"EventEngine\\DocumentStoreTest\\Postgres\\": "tests/"
43+
}
44+
},
45+
"config": {
46+
"sort-packages": true,
47+
"platform": {
48+
}
49+
},
50+
"minimum-stability": "dev",
51+
"prefer-stable": true,
52+
"repositories": [
53+
{
54+
"type": "composer",
55+
"url": "https://packagist.org"
56+
},
57+
{
58+
"packagist": false
59+
},
60+
{
61+
"type": "vcs",
62+
"url": "https://github.com/event-engine/php-engine"
63+
}
64+
],
65+
"scripts": {
66+
"test": "vendor/bin/phpunit",
67+
"test-coverage": "phpunit --colors=always --coverage-clover clover.xml",
68+
"cs": "php-cs-fixer fix -v --diff --dry-run",
69+
"cs-fix": "php-cs-fixer fix -v --diff",
70+
"analyze": "phpstan analyze -l max -c ./phpstan.installer.neon ./src",
71+
"infection": "infection"
72+
}
73+
}

docker-compose.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
version: '2'
2+
3+
services:
4+
php:
5+
image: prooph/php:7.2-cli
6+
volumes:
7+
- .:/app
8+
environment:
9+
- PROOPH_ENV=dev
10+
- PDO_DSN=pgsql:host=postgres port=5432 dbname=event_engine
11+
- PDO_USER=postgres
12+
- PDO_PWD=
13+
14+
postgres:
15+
image: postgres:alpine
16+
ports:
17+
- 5432:5432
18+
environment:
19+
- POSTGRES_DB=event_engine

infection.json.dist

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"source": {
3+
"directories": [
4+
"src"
5+
]
6+
},
7+
"timeout": 15,
8+
"logs": {
9+
"text": "infectionlog.txt"
10+
},
11+
"testFramework":"phpunit",
12+
"bootstrap":"./vendor/autoload.php"
13+
}

0 commit comments

Comments
 (0)