├── .editorconfig
├── .gitignore
├── .scrutinizer.yml
├── _config.yml
├── composer.json
├── docs
├── code_conventions.md
├── code_of_conduct.md
├── contributing.md
├── examples
│ └── operations.md
├── getting-started.md
├── issue_template.md
├── pull-request-template.md
├── query-tree.md
├── roadmap.md
└── tests.md
├── license.md
├── phpcs.xml
├── phpunit.xml
├── readme.md
├── src
├── Connection
│ ├── Connection.php
│ ├── ConnectionCursorInterface.php
│ ├── ConnectionException.php
│ ├── ConnectionInterface.php
│ ├── ConnectionQueryInterface.php
│ ├── Options.php
│ ├── OptionsInterface.php
│ ├── Registry.php
│ ├── RegistryInterface.php
│ └── Socket
│ │ ├── Exception.php
│ │ ├── Handshake.php
│ │ ├── HandshakeInterface.php
│ │ └── Socket.php
├── Message
│ ├── ExprMessage.php
│ ├── Message.php
│ └── MessageInterface.php
├── Query
│ ├── AbstractQuery.php
│ ├── Aggregation
│ │ ├── AggregationTrait.php
│ │ ├── Avg.php
│ │ ├── Count.php
│ │ ├── Group.php
│ │ ├── Max.php
│ │ ├── Min.php
│ │ ├── Sum.php
│ │ └── Ungroup.php
│ ├── Builder.php
│ ├── Database.php
│ ├── Exception
│ │ └── QueryException.php
│ ├── Logic
│ │ ├── AndLogic.php
│ │ ├── EqualLogic.php
│ │ ├── FuncLogic.php
│ │ ├── GreaterThanLogic.php
│ │ ├── GreaterThanOrEqualToLogic.php
│ │ ├── LowerThanLogic.php
│ │ ├── LowerThanOrEqualToLogic.php
│ │ ├── NotEqualLogic.php
│ │ ├── NotLogic.php
│ │ └── OrLogic.php
│ ├── Manipulation
│ │ ├── GetField.php
│ │ ├── HasFields.php
│ │ ├── Keys.php
│ │ ├── LogicTrait.php
│ │ ├── ManipulationTrait.php
│ │ ├── Pluck.php
│ │ ├── RowHasFields.php
│ │ ├── Values.php
│ │ └── Without.php
│ ├── Operation
│ │ ├── Between.php
│ │ ├── Changes.php
│ │ ├── DbCreate.php
│ │ ├── DbDrop.php
│ │ ├── DbList.php
│ │ ├── Delete.php
│ │ ├── Filter.php
│ │ ├── FilterByRow.php
│ │ ├── Get.php
│ │ ├── GetAll.php
│ │ ├── IndexCreate.php
│ │ ├── IndexDrop.php
│ │ ├── IndexList.php
│ │ ├── IndexRename.php
│ │ ├── Insert.php
│ │ ├── OperationTrait.php
│ │ ├── Sync.php
│ │ ├── TableCreate.php
│ │ ├── TableDrop.php
│ │ ├── TableList.php
│ │ └── Update.php
│ ├── Options.php
│ ├── OptionsInterface.php
│ ├── Ordening.php
│ ├── QueryInterface.php
│ ├── Row.php
│ ├── Table.php
│ └── Transformation
│ │ ├── IsEmpty.php
│ │ ├── Limit.php
│ │ ├── OrderBy.php
│ │ ├── Skip.php
│ │ └── TransformationTrait.php
├── Response
│ ├── Cursor.php
│ ├── Response.php
│ └── ResponseInterface.php
├── Rethink.php
├── RethinkInterface.php
├── Serializer
│ └── QueryNormalizer.php
└── Types
│ ├── Frame
│ └── FrameType.php
│ ├── Query
│ └── QueryType.php
│ ├── Response
│ ├── ErrorType.php
│ ├── ResponseNote.php
│ └── ResponseType.php
│ ├── Term
│ └── TermType.php
│ └── VersionDummy
│ ├── Protocol.php
│ └── Version.php
└── test
├── Bootstrap.php
├── config.php.dist
├── config_scrutinizer.php
├── integration
├── AbstractTestCase.php
├── Aggregation
│ ├── AvgTest.php
│ ├── CountTest.php
│ ├── GroupTest.php
│ ├── MaxTest.php
│ ├── MinTest.php
│ └── SumTest.php
├── Connection
│ └── ConnectionTest.php
├── Manipulation
│ ├── HasFieldsTest.php
│ ├── KeysTest.php
│ ├── PluckTest.php
│ ├── ValuesTest.php
│ └── WithoutTest.php
├── Operation
│ ├── AbstractTableTest.php
│ ├── BetweenTest.php
│ ├── ChangesTest.php
│ ├── CursorTest.php
│ ├── DatabaseTest.php
│ ├── DeleteTest.php
│ ├── EmptyTableTest.php
│ ├── FilterTest.php
│ ├── GetAllTest.php
│ ├── GetTest.php
│ ├── IndexTest.php
│ ├── InsertTest.php
│ ├── RowTest.php
│ ├── SyncTest.php
│ └── UpdateTest.php
└── Transformation
│ ├── IsEmptyTest.php
│ ├── LimitTest.php
│ ├── OrderByTest.php
│ └── SkipTest.php
└── unit
├── BaseUnitTestCase.php
├── Connection
├── ConnectionCursorTest.php
├── ConnectionQueryTest.php
├── ConnectionTest.php
├── ConnectionTestCase.php
├── OptionsTest.php
├── RegistryTest.php
└── Socket
│ └── HandshakeTest.php
├── Query
└── MessageTest.php
├── Response
└── ResponseTest.php
└── Serializer
└── QueryNormalizerTest.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | # top-most EditorConfig file
2 | root = true
3 |
4 | # Unix-style newlines with a newline ending every file
5 | [*]
6 | end_of_line = lf
7 | insert_final_newline = true
8 | charset = utf-8
9 |
10 | # 4 space indentation
11 | [*.php]
12 | indent_style = space
13 | indent_size = 4
14 |
15 | # Matches the exact files
16 | [{composer.json,*.js}]
17 | indent_style = space
18 | indent_size = 4
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | vendor/
3 | rethinkdb_data
4 | test/config.php
5 | composer.lock
6 |
7 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | before_commands:
2 | - "composer install"
3 |
4 | checks:
5 | php: true
6 |
7 | build:
8 | environment:
9 | timezone: 'Europe/Amsterdam'
10 | variables:
11 | integration_test_file: 'config_scrutinizer.php'
12 | php:
13 | version: '7.1'
14 | ini:
15 | 'date.timezone': 'Europe/Amsterdam'
16 | dependencies:
17 | # Runs before inferred commands
18 | before:
19 | - 'source /etc/lsb-release && echo "deb http://download.rethinkdb.com/apt $DISTRIB_CODENAME main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list'
20 | - 'wget -qO- https://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add -'
21 | - 'sudo apt-get update -y'
22 | - 'sudo apt-get install rethinkdb -y'
23 | - 'sudo cp /etc/rethinkdb/default.conf.sample /etc/rethinkdb/instances.d/instance1.conf'
24 | - 'sudo /etc/init.d/rethinkdb start'
25 | # Overwrites inferred commands
26 | override: []
27 | # Runs after inferred commands
28 | after: []
29 | # Run after dependencies
30 | project_setup:
31 | before: []
32 | override: []
33 | after: []
34 | nodes:
35 | tests: true
36 | analysis:
37 | tests:
38 | override:
39 | -
40 | command: phpcs-run --standard=phpcs.xml
41 | use_website_config: false
42 | - php-scrutinizer-run
43 |
44 | build_failure_conditions:
45 | # No critical issue is introduced (existing ones are tolerated)
46 | - 'issues.label("coding-style").exists'
47 |
48 | # No new critical issue is introduced (existing ones are tolerated)
49 | - 'issues.label("coding-style").new.exists'
50 |
51 | # No critical issue is present
52 | - 'issues.severity(= MINOR).exists'
53 |
54 | # No new critical issue is introduced (existing ones are tolerated)
55 | - 'issues.severity(= MINOR).new.exists'
56 |
57 | # Class has no tests
58 | - 'classes.metric("php_code_coverage.coverage", = 0).exists'
59 |
60 | # Rating is C or worse for existing classes
61 | - 'elements.rating(<= D).exists'
62 |
63 | # Rating is C or worse is introduced
64 | - 'elements.rating(<= D).new.exists'
65 |
66 | - 'project.metric("scrutinizer.quality", < 9)' # Code Quality Rating drops below 9
67 | - 'project.metric("scrutinizer.test_coverage", < 0.85)' # Code Coverage drops below 90%
68 |
69 | # Code Coverage decreased from previous inspection by more than 5%
70 | - 'project.metric_change("scrutinizer.test_coverage", < -0.05)'
71 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tbolier/php-rethink-ql",
3 | "description": "A clean and solid RethinkDB driver for PHP.",
4 | "type": "library",
5 | "license": "Apache-2.0",
6 | "homepage": "https://github.com/tbolier/php-rethink-ql/",
7 | "authors": [
8 | {
9 | "name": "Timon Bolier",
10 | "email": "timonb@gmail.com"
11 | }
12 | ],
13 | "keywords": [
14 | "adapter",
15 | "database",
16 | "driver",
17 | "rethinkdb",
18 | "nosql",
19 | "nosql-database",
20 | "php",
21 | "php-rethinkdb",
22 | "php-rethinkdb-driver",
23 | "rethinkdb-adapter",
24 | "reql",
25 | "rethinkdb-ql"
26 | ],
27 | "minimum-stability": "stable",
28 | "require": {
29 | "php": "^7.1",
30 | "psr/http-message": "^1.0",
31 | "symfony/serializer": "^4.1",
32 | "symfony/property-access": "^4.1"
33 | },
34 | "require-dev": {
35 | "mockery/mockery": "^1.0",
36 | "phpunit/phpunit": "^7.0 || ^8.0"
37 | },
38 | "autoload": {
39 | "psr-4": {
40 | "TBolier\\RethinkQL\\": "src/",
41 | "TBolier\\RethinkQL\\UnitTest\\": "test/unit/",
42 | "TBolier\\RethinkQL\\IntegrationTest\\": "test/integration/"
43 | }
44 | },
45 | "support": {
46 | "docs": "https://github.com/tbolier/php-rethink-ql/tree/master/docs/",
47 | "issues": "https://github.com/tbolier/php-rethink-ql/issues/",
48 | "source": "https://github.com/tbolier/php-rethink-ql/"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/docs/code_conventions.md:
--------------------------------------------------------------------------------
1 | # Code conventions
2 |
3 | We value quality. Because everyone can contribute we have created some guidelines.
4 |
5 | # Naming conventions
6 |
7 | 1. Interfaces MUST be suffixed by Interface: e.g. `TBolier\Foo\QueryInterface`.
8 | 2. Abstract classes MUST be prefixed by Abstract: e.g. `TBolier\Foo\AbstractQuery`.
9 | 3. Traits MUST be suffixed by Trait: e.g. `TBolier\Foo\QueryTrait`.
10 | 4. PSR-1, 2 and 4 MUST be followed.
11 | 5. The vendor namespace MUST be `TBolier`.
12 |
13 | # Code standards and principles
14 |
15 | 1. The [PHP-FIG PHP Standards Recommendations](https://www.php-fig.org/psr/) (PSR-1, 2 and 4) MUST be followed.
16 | 2. Create understandable, flexible and maintainable code by using the [Solid Principles](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) as a set of guidelines.
17 | 3. Use [Composite over inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance) as a guideline.
18 | 4. Create integration and unit tests for your fixes and code contributions.
19 |
20 | Thank you!
21 |
--------------------------------------------------------------------------------
/docs/code_of_conduct.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | Our focus is to create an open-source RethinkDB driver for PHP where everyone is welcome to contribute and discuss. We hope by community input and improvements, we deliver a community-driven driver that is well supported for both RethinkDB versions and API, and PHP. Please feel free to participate in this project and keep in mind the guidelines below.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/docs/contributing.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | Please read the following guidelines if you would like to contribute to this project.
4 |
5 | 1. Agree with our [code of conduct](code_of_conduct.md)
6 | 2. Follow the [code conventions](code_conventions.md) guidelines
7 | 3. Check the [roadmap](roadmap.md) to see what's planned for the next version
8 | 4. Go to [open issues](https://github.com/tbolier/php-rethink-ql/issues) and pick a _good first issue_ or _help wanted_ issue
9 | 5. Run the tests. See [here for the configuration](tests.md)
10 |
11 | ## Discussions and chat
12 |
13 | You can find us at Gitter.im in the `rethinkdb-php` room at https://gitter.im/rethinkdb-php/Lobby
14 |
--------------------------------------------------------------------------------
/docs/examples/operations.md:
--------------------------------------------------------------------------------
1 | # ReQL operation examples
2 |
3 | ## between
4 |
5 | Insert three documents, select `between` 1 and 2, assert the result.
6 |
7 | ```php
8 | // We can do our operations meanwhile.
9 | $res = $r
10 | ->table('tabletest')
11 | ->insert([
12 | [
13 | 'id' => 1,
14 | 'title' => 'Test document 1',
15 | 'description' => 'A document description.',
16 | ],
17 | [
18 | 'id' => 2,
19 | 'title' => 'Test document 2',
20 | 'description' => 'A document description.',
21 | ],
22 | [
23 | 'id' => 3,
24 | 'title' => 'Test document 3',
25 | 'description' => 'A document description.',
26 | ],
27 | ])
28 | ->run();
29 |
30 | /** @var Cursor $cursor */
31 | $cursor = $r
32 | ->table('tabletest')
33 | ->between(1, 2)
34 | ->run();
35 |
36 | echo $cursor->count() === 2 ? 'equals' : 'different';
37 | foreach ($cursor as $document) {
38 | print_r($document);
39 | }
40 | ```
41 |
42 | ## changes
43 | Insert five documents and consume the `changes` afterwards.
44 | ```php
45 | // In this example we set the time limit to 5 seconds before the process is terminated.
46 | set_time_limit(5);
47 |
48 | // The feed is an iterable cursor.
49 | $feed = $r
50 | ->table('tabletest')
51 | ->changes()
52 | ->run();
53 |
54 | // We can do our operations meanwhile.
55 | $res = $r
56 | ->table('tabletest')
57 | ->insert([
58 | [
59 | 'id' => 2,
60 | 'title' => 'Test document 2',
61 | 'description' => 'A document description.',
62 | ],
63 | [
64 | 'id' => 1,
65 | 'title' => 'Test document 1',
66 | 'description' => 'A document description.',
67 | ],
68 | ])
69 | ->run();
70 |
71 | // When we iterate over the feed, it will print out the changes.
72 | foreach ($feed as $change) {
73 | extract($change);
74 | print_r($old_val, $new_val);
75 | }
76 | ```
77 |
78 | #### changes with options
79 | Insert one document, update it, and consume the change feed with a squashed cursor.
80 | For all possible options, please visit the Java documentation [here](https://rethinkdb.com/api/java/changes/).
81 | ```php
82 | $feed = $r
83 | ->table('tabletest')
84 | ->changes(['squash' => true])
85 | ->run();
86 |
87 | $res = $r
88 | ->table('tabletest')
89 | ->insert([
90 | [
91 | 'id' => 1,
92 | 'title' => 'Test document 1',
93 | 'description' => 'A document description.',
94 | ]
95 | ])
96 | ->run();
97 |
98 | $r
99 | ->table('tabletest')
100 | ->filter(['id' => 1])
101 | ->update(['description' => 'cool!'])
102 | ->run();
103 |
104 | $change = $feed->current();
105 | print_r($change);
106 | ```
107 |
108 | ## tableCreate
109 | ```php
110 | $r->db()
111 | ->tableCreate('Table')
112 | ->run();
113 | ```
114 |
115 | ## insert
116 | Insert one or more documents.
117 | ```php
118 | $r->table('tableName')
119 | ->insert([
120 | 'documentId' => 1,
121 | 'title' => 'Test document 1',
122 | 'description' => 'A document description.'
123 | ])
124 | ->run();
125 |
126 | $r->table('tableName')
127 | ->insert([
128 | [
129 | 'documentId' => 2,
130 | 'title' => 'Test document 2',
131 | 'description' => 'A document description.'
132 | ],
133 | [
134 | 'documentId' => 3,
135 | 'title' => 'Test document 3',
136 | 'description' => 'A document description.'
137 | ],
138 | ])
139 | ->run();
140 | ```
141 |
142 | ## update
143 | Update one or more documents.
144 | ```php
145 | $r->table('tableName')
146 | ->filter([
147 | [
148 | 'title' => 'A document description.',
149 | ],
150 | ])
151 | ->update([
152 | [
153 | 'title' => 'Updated document description.',
154 | ],
155 | ])
156 | ->run();
157 | ```
158 |
159 | ## filter
160 | Filter and count the results.
161 | ```php
162 | $r->table('tableName')
163 | ->filter([
164 | [
165 | 'title' => 'Test document',
166 | ],
167 | ])
168 | ->count()
169 | ->run();
170 | ```
171 |
172 | ## sync
173 | Save writes to permanent storage.
174 |
175 | ```php
176 | $r->table('tableName')
177 | ->sync()
178 | ->run();
179 | ```
--------------------------------------------------------------------------------
/docs/getting-started.md:
--------------------------------------------------------------------------------
1 | # Getting started
2 |
3 | *Work in progress document.*
4 |
5 | Multiple connections can be injected into the connection `Registry`.
6 | Create the Rethink driver object by injecting a `Connection` object into it.
7 |
8 | ```php
9 | [
15 | 'host' => 'localhost',
16 | 'port' => 28015,
17 | 'default_db' => 'demoDB',
18 | 'user' => 'demo',
19 | 'password' => 'demo',
20 | 'timeout' => 5,
21 | 'timeout_stream' => 10,
22 | ],
23 | ];
24 |
25 | $registry = new Registry($connections);
26 |
27 | $r = new Rethink($registry->getConnection('default_connection'));
28 |
29 | // Now you can connect to RethinkDB.
30 | $r->connection()->connect();
31 | ```
32 |
33 | The driver class `Rethink` has an API Interface that supports the ReQL domain-specific language (DSL).
34 |
35 | ## Examples
36 |
37 | ### Operations
38 |
39 | Examples on ReQL operations can be [found here](examples/operations.md).
--------------------------------------------------------------------------------
/docs/issue_template.md:
--------------------------------------------------------------------------------
1 | ## Issue summary
2 |
3 | Please describe your issue.
4 |
5 | ## Issue checklist
6 | A checklist overview of items to do before the issue can be marked as done.
7 | - [ ] Item one
8 | - [ ] Item two
9 |
10 | The following sections can be removed only, whenever they are not applicable or you have a simple question.
11 |
12 | ## Actual Behavior
13 |
14 | What is it doing now?
15 |
16 | ## Expected Behavior
17 |
18 | What do you expect it to do?
19 |
20 | ## Steps to Reproduce the Problem
21 |
22 | 1.
23 | 1.
24 | 1.
25 |
26 | ## Specifications
27 |
28 | - PHP Version:
29 | - RethinkDB Version:
30 | - Platform: Mac OS / Linux (Distro?) / Windows
31 |
--------------------------------------------------------------------------------
/docs/pull-request-template.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 | _Describe the problem or feature in addition to a link to the issues._
3 |
4 | ## Approach
5 | _How does this change address the problem?_
6 |
7 | #### Open Questions and Pre-Merge TODOs
8 | - [ ] Use github checklists. When solved, check the box and explain the answer.
9 |
10 | ## Research
11 | _Describe the research stage_
12 |
13 | _Links to blog posts, patterns, libraries or addons used to solve this problem_
14 |
15 | ## Solution
16 |
17 | _How did you solve the issue?_
18 |
19 |
--------------------------------------------------------------------------------
/docs/query-tree.md:
--------------------------------------------------------------------------------
1 | # Query tree guide
2 |
3 | A simple RethinkDB query like:
4 |
5 | ```php
6 | $r->db('test')->table('tabletest')->filter('{"title":"Test document"}')->count();
7 | ```
8 |
9 | ## Under the hood
10 |
11 | First we nest all query operation objects. This is a too long dump for the example. So afterwards the `toArray` method is called to normalize the query.
12 | This is how the message object looks like with the normalized query before we serialize it.
13 |
14 | ```php
15 | TBolier\RethinkQL\Message\Message Object
16 | (
17 | [queryType:TBolier\RethinkQL\Message\Message:private] => 1
18 | [query:TBolier\RethinkQL\Message\Message:private] => Array
19 | (
20 | [0] => 43
21 | [1] => Array
22 | (
23 | [0] => Array
24 | (
25 | [0] => 39
26 | [1] => Array
27 | (
28 | [0] => Array
29 | (
30 | [0] => 15
31 | [1] => Array
32 | (
33 | [0] => tabletest
34 | )
35 |
36 | )
37 |
38 | [1] => Array
39 | (
40 | [0] => 98
41 | [1] => Array
42 | (
43 | [0] => {"title":"Test document"}
44 | )
45 |
46 | )
47 |
48 | )
49 |
50 | )
51 |
52 | )
53 |
54 | )
55 |
56 | [options:TBolier\RethinkQL\Message\Message:private] => TBolier\RethinkQL\Query\Options Object
57 | (
58 | [db:TBolier\RethinkQL\Query\Options:private] => Array
59 | (
60 | [0] => 14
61 | [1] => Array
62 | (
63 | [0] => test
64 | )
65 |
66 | )
67 |
68 | )
69 |
70 | )
71 | ```
72 |
73 | Now we JSON serialize the Message object and we end up with a raw query that we send to the RethinkDB (server):
74 |
75 | ```php
76 | [
77 | 1,
78 | [
79 | 43,
80 | [
81 | [
82 | 39,
83 | [
84 | [
85 | 15,
86 | [
87 | "tabletest"
88 | ]
89 | ],
90 | [
91 | 98,
92 | [
93 | "{\"title\":\"Test document\"}"
94 | ]
95 | ]
96 | ]
97 | ]
98 | ]
99 | ],
100 | {
101 | "db": [
102 | 14,
103 | [
104 | "test"
105 | ]
106 | ]
107 | }
108 | ]
109 | ```
110 |
--------------------------------------------------------------------------------
/docs/tests.md:
--------------------------------------------------------------------------------
1 | # Tests
2 |
3 | We value quality. Because everyone can contribute we have created some guidelines.
4 |
5 | ## Configuration
6 |
7 | First you need to install RethinkDB.
8 |
9 | Then it's necessary to duplicate the standard configuration, and replace default values in `test/config.php`.
10 |
11 | ```sh
12 | cp test/config.php.dist test/config.php
13 | ```
14 |
15 | ## Run
16 |
17 | ```sh
18 | composer update
19 |
20 | vendor/bin/phpunit
21 | ```
22 |
23 | Thank you!
24 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | The coding standard for PHP_CodeSniffer itself.
4 |
5 |
6 |
7 |
8 |
9 |
10 | src
11 | test
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | test/integration/*
8 |
9 |
10 | test/unit/*
11 |
12 |
13 |
14 |
15 | src/*
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | PHP-RETHINK-QL
2 | A PHP RethinkDB driver for the RethinkDB query language (ReQL).
3 | License: Apache License 2.0
4 |
5 | PHP-RETHINK-QL [](https://github.com/tbolier) [](https://scrutinizer-ci.com/g/tbolier/php-rethink-ql/?branch=master) [](https://scrutinizer-ci.com/g/tbolier/php-rethink-ql/?branch=master) [](https://scrutinizer-ci.com/g/tbolier/php-rethink-ql/build-status/master)
6 | ========================
7 |
8 | # License
9 | PHP-RETHINK-QL is licensed under the terms of the [Apache License 2.0](LICENSE.md)
10 |
11 | # Description
12 |
13 | A new clean and solid RethinkDB driver for PHP, focused on clean code with SOLID principles in mind.
14 |
15 | Unfortunately the original PHP-RQL driver is no longer is no longer actively maintained and patched. That's why we have started this new PHP RethinkDB driver with the goal to create an easy to understand driver that can be improved and maintained by the community.
16 |
17 | # Requirements
18 |
19 | ## RethinkDB version
20 |
21 | This library supports the RethinkDB release `>=2.3.0` and protocol version `V1_0`.
22 | Earliers version of RethinkDB are not supported at this moment.
23 |
24 | ## PHP
25 |
26 | PHP version `>=7.1`
27 |
28 | ## Supported ReQL Command API overview.
29 |
30 | In the release [roadmap](docs/roadmap.md) you will find a table with the currently and future supported ReQL command methods.
31 |
32 | # Getting started
33 |
34 | Multiple connections can be injected into the connection `Registry`.
35 | Create the Rethink driver object by injecting a `Connection` object into it.
36 |
37 | ```php
38 | [
44 | 'host' => 'localhost',
45 | 'port' => 28015,
46 | 'default_db' => 'demoDB',
47 | 'user' => 'demo',
48 | 'password' => 'demo',
49 | 'timeout' => 5,
50 | 'timeout_stream' => 10,
51 | ],
52 | ];
53 |
54 | $registry = new Registry($connections);
55 |
56 | $r = new Rethink($registry->getConnection('default_connection'));
57 |
58 | // Now you can connect to RethinkDB.
59 | $r->connection()->connect();
60 | ```
61 |
62 | The driver class `Rethink` has a default database defined in the connection options. However you can always switch database if needed.
63 | ```php
64 | $r->use('demoDB-2');
65 | ```
66 |
67 | The driver class `Rethink` has an API Interface that supports the ReQL domain-specific language (DSL).
68 |
69 | A create table example:
70 | ```php
71 | $r->db()
72 | ->tableCreate('Table')
73 | ->run();
74 | ```
75 |
76 | For more examples about executing queries go to our docs section: [Getting started](docs/getting-started.md)
77 |
78 | ## Contributing
79 |
80 | Please read the [contributing guidelines](docs/contributing.md) if you would like to contribute to this project.
81 |
82 | ## Discussions and chat
83 |
84 | You can find us at Gitter.im in the `rethinkdb-php` room at https://gitter.im/rethinkdb-php/Lobby
85 |
86 | ## Author and collaborators
87 |
88 | * **Timon Bolier** - *Author and collaborator* - [tbolier](https://github.com/tbolier)
89 | * **Michel Maas** - *Collaborator* - [AxaliaN](https://github.com/AxaliaN)
90 | * **Jérémy** - *Collaborator* - [Th3Mouk](https://github.com/Th3Mouk)
91 |
92 | See also the list of [contributors](https://github.com/tbolier/php-rethink-ql/contributors) who participated in this project.
93 |
--------------------------------------------------------------------------------
/src/Connection/ConnectionCursorInterface.php:
--------------------------------------------------------------------------------
1 | hostname = $options['hostname'] ?? 'localhost';
51 | $this->port = $options['port'] ?? 28015;
52 | $this->dbname = $options['dbname'] ?? '';
53 | $this->user = $options['user'] ?? '';
54 | $this->password = $options['password'] ?? '';
55 | $this->timeout = $options['timeout'] ?? 1.0;
56 | $this->timeoutStream = $options['timeout_stream'] ?? 3;
57 | $this->ssl = $options['ssl'] ?? false;
58 | }
59 |
60 | public function getHostname(): string
61 | {
62 | return $this->hostname;
63 | }
64 |
65 | public function getPort(): int
66 | {
67 | return $this->port;
68 | }
69 |
70 | public function getDbName(): string
71 | {
72 | return $this->dbname;
73 | }
74 |
75 | public function getUser(): string
76 | {
77 | return $this->user;
78 | }
79 |
80 | public function getPassword(): string
81 | {
82 | return $this->password;
83 | }
84 |
85 | public function getTimeout(): float
86 | {
87 | return $this->timeout;
88 | }
89 |
90 | public function getTimeoutStream(): int
91 | {
92 | return $this->timeoutStream;
93 | }
94 |
95 | public function isSsl(): bool
96 | {
97 | return $this->ssl;
98 | }
99 |
100 | public function hasDefaultDatabase(): bool
101 | {
102 | return !empty($this->dbname);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Connection/OptionsInterface.php:
--------------------------------------------------------------------------------
1 | $options) {
28 | if (!$options instanceof OptionsInterface) {
29 | continue;
30 | }
31 |
32 | $this->addConnection($name, $options);
33 | }
34 | }
35 | }
36 |
37 | /**
38 | * @throws ConnectionException
39 | */
40 | public function addConnection(string $name, OptionsInterface $options): bool
41 | {
42 | if ($this->hasConnection($name)) {
43 | throw new ConnectionException("The connection {$name} has already been added.", 400);
44 | }
45 |
46 | // TODO: Create factory for instantiation Connection.
47 | $this->connections[$name] = new Connection(
48 | function () use ($options) {
49 | return new Socket(
50 | $options
51 | );
52 | },
53 | new Handshake($options->getUser(), $options->getPassword(), Version::V1_0),
54 | $options->getDbName(),
55 | new Serializer(
56 | [new QueryNormalizer()],
57 | [new JsonEncoder()]
58 | ),
59 | new Serializer(
60 | [new ObjectNormalizer()],
61 | [new JsonEncoder()]
62 | )
63 | );
64 |
65 | return true;
66 | }
67 |
68 | public function hasConnection(string $name): bool
69 | {
70 | return isset($this->connections[$name]);
71 | }
72 |
73 | /**
74 | * @throws ConnectionException
75 | */
76 | public function getConnection(string $name): ConnectionInterface
77 | {
78 | if (!$this->connections[$name]) {
79 | throw new ConnectionException("The connection {$name} does not exist.", 400);
80 | }
81 |
82 | return $this->connections[$name];
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Connection/RegistryInterface.php:
--------------------------------------------------------------------------------
1 | queryType = $queryType ?? QueryType::START;
29 | $this->query = $query ?? '';
30 | $this->options = $options ?? new Options();
31 | }
32 |
33 | public function getQueryType(): int
34 | {
35 | return $this->queryType;
36 | }
37 |
38 | public function setCommand(int $queryType): MessageInterface
39 | {
40 | $this->queryType = $queryType;
41 |
42 | return $this;
43 | }
44 |
45 | public function setQuery($query): MessageInterface
46 | {
47 | $this->query = (string) $query;
48 |
49 | return $this;
50 | }
51 |
52 | public function getOptions(): OptionsInterface
53 | {
54 | return $this->options;
55 | }
56 |
57 | public function setOptions(OptionsInterface $options): MessageInterface
58 | {
59 | $this->options = $options;
60 |
61 | return $this;
62 | }
63 |
64 | public function toArray(): array
65 | {
66 | return [
67 | $this->queryType,
68 | $this->query,
69 | (object) $this->getOptions(),
70 | ];
71 | }
72 |
73 | public function jsonSerialize(): array
74 | {
75 | return $this->toArray();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Message/Message.php:
--------------------------------------------------------------------------------
1 | queryType = $queryType ?? QueryType::START;
30 | $this->query = $query ?? [];
31 | $this->options = $options ?? new Options();
32 | }
33 |
34 | public function getQueryType(): int
35 | {
36 | return $this->queryType;
37 | }
38 |
39 | public function setCommand(int $queryType): MessageInterface
40 | {
41 | $this->queryType = $queryType;
42 |
43 | return $this;
44 | }
45 |
46 | public function setQuery($query): MessageInterface
47 | {
48 | $this->query = (array) $query;
49 |
50 | return $this;
51 | }
52 |
53 | public function getOptions(): OptionsInterface
54 | {
55 | return $this->options;
56 | }
57 |
58 | public function setOptions(OptionsInterface $options): MessageInterface
59 | {
60 | $this->options = $options;
61 |
62 | return $this;
63 | }
64 |
65 | public function toArray(): array
66 | {
67 | return [
68 | $this->queryType,
69 | $this->query,
70 | (object) $this->getOptions()
71 | ];
72 | }
73 |
74 | public function jsonSerialize(): array
75 | {
76 | return $this->toArray();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Message/MessageInterface.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
25 | }
26 |
27 | public function run()
28 | {
29 | $message = new Message();
30 | $message->setQuery($this->toArray());
31 |
32 | return $this->rethink->connection()->run($message);
33 | }
34 |
35 | abstract public function toArray(): array;
36 | }
37 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/AggregationTrait.php:
--------------------------------------------------------------------------------
1 | rethink, /** @scrutinizer ignore-type */ $this);
13 | }
14 |
15 | public function group(string $key)
16 | {
17 | return new Group($this->rethink, /** @scrutinizer ignore-type */ $this, $key);
18 | }
19 |
20 | public function ungroup()
21 | {
22 | return new Ungroup($this->rethink, /** @scrutinizer ignore-type */ $this);
23 | }
24 |
25 | public function sum(string $key): QueryInterface
26 | {
27 | return new Sum($this->rethink, /** @scrutinizer ignore-type */ $this, $key);
28 | }
29 |
30 | public function avg(string $key): QueryInterface
31 | {
32 | return new Avg($this->rethink, /** @scrutinizer ignore-type */ $this, $key);
33 | }
34 |
35 | public function min(string $key)
36 | {
37 | return new Min($this->rethink, /** @scrutinizer ignore-type */ $this, $key);
38 | }
39 |
40 | public function max(string $key)
41 | {
42 | return new Max($this->rethink, /** @scrutinizer ignore-type */ $this, $key);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/Avg.php:
--------------------------------------------------------------------------------
1 | query = $query;
33 | $this->key = $key;
34 | $this->rethink = $rethink;
35 | }
36 |
37 | public function toArray(): array
38 | {
39 | return [
40 | TermType::AVG,
41 | [
42 | $this->query->toArray(),
43 | $this->key,
44 | ],
45 | ];
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/Count.php:
--------------------------------------------------------------------------------
1 | query = $query;
23 | $this->rethink = $rethink;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::COUNT,
30 | [
31 | $this->query->toArray(),
32 | ],
33 | ];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/Group.php:
--------------------------------------------------------------------------------
1 | query = $query;
37 | $this->key = $key;
38 | $this->rethink = $rethink;
39 | }
40 |
41 | public function toArray(): array
42 | {
43 | return [
44 | TermType::GROUP,
45 | [
46 | $this->query->toArray(),
47 | $this->key,
48 | ],
49 | ];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/Max.php:
--------------------------------------------------------------------------------
1 | query = $query;
38 | $this->key = $key;
39 | $this->rethink = $rethink;
40 | }
41 |
42 | public function toArray(): array
43 | {
44 | return [
45 | TermType::MAX,
46 | [
47 | $this->query->toArray(),
48 | $this->key,
49 | ],
50 | ];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/Min.php:
--------------------------------------------------------------------------------
1 | query = $query;
33 | $this->key = $key;
34 | $this->rethink = $rethink;
35 | }
36 |
37 | public function toArray(): array
38 | {
39 | return [
40 | TermType::MIN,
41 | [
42 | $this->query->toArray(),
43 | $this->key,
44 | ],
45 | ];
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/Sum.php:
--------------------------------------------------------------------------------
1 | query = $query;
33 | $this->key = $key;
34 | $this->rethink = $rethink;
35 | }
36 |
37 | public function toArray(): array
38 | {
39 | return [
40 | TermType::SUM,
41 | [
42 | $this->query->toArray(),
43 | $this->key,
44 | ],
45 | ];
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Query/Aggregation/Ungroup.php:
--------------------------------------------------------------------------------
1 | query = $query;
30 | $this->rethink = $rethink;
31 | }
32 |
33 | public function toArray(): array
34 | {
35 | return [
36 | TermType::UNGROUP,
37 | [
38 | $this->query->toArray(),
39 | ],
40 | ];
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Query/Builder.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
38 | }
39 |
40 | public function table(string $name): Table
41 | {
42 | if ($this->table) {
43 | unset($this->table);
44 | }
45 |
46 | $this->table = new Table($name, $this->rethink);
47 |
48 | return $this->table;
49 | }
50 |
51 | public function database(): Database
52 | {
53 | if ($this->database) {
54 | unset($this->database);
55 | }
56 |
57 | $this->database = new Database($this->rethink);
58 |
59 | return $this->database;
60 | }
61 |
62 | public function ordening(string $key): Ordening
63 | {
64 | if ($this->ordering) {
65 | unset($this->ordering);
66 | }
67 |
68 | $this->ordering = new Ordening($key, $this->rethink);
69 |
70 | return $this->ordering;
71 | }
72 |
73 | public function row(string $value = null): Row
74 | {
75 | $this->row = new Row($this->rethink, $value);
76 |
77 | return $this->row;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Query/Database.php:
--------------------------------------------------------------------------------
1 | dbList();
26 | }
27 |
28 | public function dbCreate(string $name): Database
29 | {
30 | $this->query = new DbCreate($this->rethink, $name);
31 |
32 | return $this;
33 | }
34 |
35 | public function dbDrop(string $name): Database
36 | {
37 | $this->query = new DbDrop($this->rethink, $name);
38 |
39 | return $this;
40 | }
41 |
42 | public function dbList(): Database
43 | {
44 | $this->query = new DbList($this->rethink);
45 |
46 | return $this;
47 | }
48 |
49 | public function tableList(): Database
50 | {
51 | $this->query = new TableList($this->rethink);
52 |
53 | return $this;
54 | }
55 |
56 | public function tableCreate(string $name): Database
57 | {
58 | $this->query = new TableCreate($this->rethink, $name);
59 |
60 | return $this;
61 | }
62 |
63 | public function tableDrop(string $name): Database
64 | {
65 | $this->query = new TableDrop($this->rethink, $name);
66 |
67 | return $this;
68 | }
69 |
70 | public function toArray(): array
71 | {
72 | return $this->query->toArray();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Query/Exception/QueryException.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
33 |
34 | $this->functionOne = $functionOne;
35 | $this->functionTwo = $functionTwo;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return
41 | [
42 | TermType::AND,
43 | [
44 | $this->functionOne->toArray(),
45 | $this->functionTwo->toArray(),
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Logic/EqualLogic.php:
--------------------------------------------------------------------------------
1 | value = $value;
33 | $this->rethink = $rethink;
34 |
35 | $this->query = $query;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return
41 | [
42 | TermType::EQ,
43 | [
44 | $this->query->toArray(),
45 | $this->value,
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Logic/FuncLogic.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
27 |
28 | $this->query = $query;
29 | }
30 |
31 | public function toArray(): array
32 | {
33 | return
34 | [
35 | TermType::FUNC,
36 | [
37 | [
38 | TermType::MAKE_ARRAY,
39 | [
40 | TermType::DATUM,
41 | ],
42 | ],
43 | $this->query->toArray(),
44 | ],
45 | ];
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Query/Logic/GreaterThanLogic.php:
--------------------------------------------------------------------------------
1 | value = $value;
33 | $this->rethink = $rethink;
34 |
35 | $this->query = $query;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return
41 | [
42 | TermType::GT,
43 | [
44 | $this->query->toArray(),
45 | $this->value,
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Logic/GreaterThanOrEqualToLogic.php:
--------------------------------------------------------------------------------
1 | value = $value;
33 | $this->rethink = $rethink;
34 |
35 | $this->query = $query;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return
41 | [
42 | TermType::GE,
43 | [
44 | $this->query->toArray(),
45 | $this->value,
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Logic/LowerThanLogic.php:
--------------------------------------------------------------------------------
1 | value = $value;
33 | $this->rethink = $rethink;
34 |
35 | $this->query = $query;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return
41 | [
42 | TermType::LT,
43 | [
44 | $this->query->toArray(),
45 | $this->value,
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Logic/LowerThanOrEqualToLogic.php:
--------------------------------------------------------------------------------
1 | value = $value;
33 | $this->rethink = $rethink;
34 |
35 | $this->query = $query;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return
41 | [
42 | TermType::LE,
43 | [
44 | $this->query->toArray(),
45 | $this->value,
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Logic/NotEqualLogic.php:
--------------------------------------------------------------------------------
1 | value = $value;
33 | $this->rethink = $rethink;
34 |
35 | $this->query = $query;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return
41 | [
42 | TermType::NE,
43 | [
44 | $this->query->toArray(),
45 | $this->value,
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Logic/NotLogic.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
28 | $this->query = $query;
29 | }
30 |
31 | public function toArray(): array
32 | {
33 | return
34 | [
35 | TermType::NOT,
36 | [
37 | $this->query->toArray(),
38 | ],
39 | ];
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Query/Logic/OrLogic.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
34 |
35 | $this->functionOne = $functionOne;
36 | $this->functionTwo = $functionTwo;
37 | }
38 |
39 | public function toArray(): array
40 | {
41 | return
42 | [
43 | TermType::OR,
44 | [
45 | $this->functionOne->toArray(),
46 | $this->functionTwo->toArray(),
47 | ],
48 | ];
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/GetField.php:
--------------------------------------------------------------------------------
1 | field = $field;
37 | $this->rethink = $rethink;
38 |
39 | $this->query = $query;
40 | }
41 |
42 | public function toArray(): array
43 | {
44 | if ($this->query !== null) {
45 | return [
46 | TermType::GET_FIELD,
47 | [
48 | $this->query->toArray(),
49 | $this->field,
50 | ],
51 | ];
52 | }
53 |
54 | return [
55 | TermType::GET_FIELD,
56 | [
57 | [
58 | TermType::IMPLICIT_VAR,
59 | [],
60 | ],
61 | $this->field,
62 | ],
63 | ];
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/HasFields.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
38 | $this->query = $query;
39 | $this->keys = $keys;
40 | }
41 |
42 | public function toArray(): array
43 | {
44 | if (\count($this->keys) === 1) {
45 | $keysQuery = implode($this->keys);
46 | } else {
47 | $keysQuery = [
48 | TermType::MAKE_ARRAY,
49 | array_values($this->keys)
50 | ];
51 | }
52 |
53 | return [
54 | TermType::HAS_FIELDS,
55 | [
56 | $this->query->toArray(),
57 | $keysQuery
58 | ]
59 | ];
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/Keys.php:
--------------------------------------------------------------------------------
1 | query = $query;
31 | $this->rethink = $rethink;
32 | }
33 |
34 | public function toArray(): array
35 | {
36 | return [
37 | TermType::KEYS,
38 | [
39 | $this->query->toArray()
40 | ]
41 | ];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/LogicTrait.php:
--------------------------------------------------------------------------------
1 | rethink, $field, $this->query);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/ManipulationTrait.php:
--------------------------------------------------------------------------------
1 | rethink, /** @scrutinizer ignore-type */ $this, $keys);
13 | }
14 |
15 | public function without(...$keys): Without
16 | {
17 | return new Without($this->rethink, /** @scrutinizer ignore-type */ $this, $keys);
18 | }
19 |
20 | public function keys(): Keys
21 | {
22 | return new Keys($this->rethink, /** @scrutinizer ignore-type */ $this);
23 | }
24 |
25 | public function values(): Values
26 | {
27 | return new Values($this->rethink, /** @scrutinizer ignore-type */ $this);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/Pluck.php:
--------------------------------------------------------------------------------
1 | query = $query;
38 | $this->rethink = $rethink;
39 | $this->keys = $keys;
40 | }
41 |
42 | public function toArray(): array
43 | {
44 | if (\count($this->keys) === 1) {
45 | $keysQuery = implode($this->keys);
46 | } else {
47 | $keysQuery = [
48 | TermType::MAKE_ARRAY,
49 | array_values($this->keys)
50 | ];
51 | }
52 |
53 | return [
54 | TermType::PLUCK,
55 | [
56 | $this->query->toArray(),
57 | $keysQuery
58 | ]
59 | ];
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/RowHasFields.php:
--------------------------------------------------------------------------------
1 | keys = $keys;
28 | $this->rethink = $rethink;
29 | }
30 |
31 | public function toArray(): array
32 | {
33 | if (\count($this->keys) === 1) {
34 | $keysQuery = implode($this->keys);
35 | } else {
36 | $keysQuery = [
37 | TermType::MAKE_ARRAY,
38 | array_values($this->keys)
39 | ];
40 | }
41 |
42 | return [
43 | TermType::HAS_FIELDS,
44 | [
45 | [
46 | TermType::IMPLICIT_VAR
47 | ],
48 | $keysQuery
49 | ]
50 | ];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/Values.php:
--------------------------------------------------------------------------------
1 | query = $query;
37 | $this->rethink = $rethink;
38 | }
39 |
40 | public function toArray(): array
41 | {
42 | return [
43 | TermType::VALUES,
44 | [
45 | $this->query->toArray()
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Manipulation/Without.php:
--------------------------------------------------------------------------------
1 | query = $query;
38 | $this->rethink = $rethink;
39 | $this->keys = $keys;
40 | }
41 |
42 | public function toArray(): array
43 | {
44 | if (\count($this->keys) === 1) {
45 | $keysQuery = implode($this->keys);
46 | } else {
47 | $keysQuery = [
48 | TermType::MAKE_ARRAY,
49 | array_values($this->keys)
50 | ];
51 | }
52 |
53 | return [
54 | TermType::WITHOUT,
55 | [
56 | $this->query->toArray(),
57 | $keysQuery
58 | ]
59 | ];
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Query/Operation/Between.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
49 | $this->query = $query;
50 | $this->min = $min;
51 | $this->max = $max;
52 | $this->options = $options;
53 | }
54 |
55 | public function toArray(): array
56 | {
57 | $args = [
58 | $this->query->toArray(),
59 | $this->min,
60 | $this->max,
61 | ];
62 |
63 | if ($this->options !== null) {
64 | $args = array_merge($args, [$this->options]);
65 | }
66 |
67 | return [
68 | TermType::BETWEEN,
69 | $args,
70 | ];
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Query/Operation/Changes.php:
--------------------------------------------------------------------------------
1 | query = $query;
31 | $this->rethink = $rethink;
32 | $this->options = $options;
33 | }
34 |
35 | public function toArray(): array
36 | {
37 | $query = [
38 | TermType::CHANGES,
39 | [
40 | $this->query->toArray(),
41 | ],
42 | ];
43 |
44 | if (!empty($this->options)) {
45 | $query[] = $this->options;
46 | }
47 |
48 | return $query;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Query/Operation/DbCreate.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
22 |
23 | $this->name = $name;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::DB_CREATE,
30 | [
31 | [
32 | TermType::DATUM,
33 | $this->name,
34 | ],
35 | ],
36 | ];
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Query/Operation/DbDrop.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
22 |
23 | $this->name = $name;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::DB_DROP,
30 | [
31 | [
32 | TermType::DATUM,
33 | $this->name,
34 | ],
35 | ],
36 | ];
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Query/Operation/DbList.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
17 | }
18 |
19 | public function toArray(): array
20 | {
21 | return [
22 | TermType::DB_LIST,
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Query/Operation/Delete.php:
--------------------------------------------------------------------------------
1 | query = $query;
23 | $this->rethink = $rethink;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::DELETE,
30 | [
31 | $this->query->toArray(),
32 | ],
33 | ];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Query/Operation/Filter.php:
--------------------------------------------------------------------------------
1 | query = $query;
39 | $this->predicate = [$predicate];
40 | $this->rethink = $rethink;
41 | }
42 |
43 | public function toArray(): array
44 | {
45 | $jsonDocuments = [];
46 | foreach ($this->predicate as $key => $document) {
47 | $jsonDocuments[] = json_encode($document);
48 | }
49 |
50 | return [
51 | TermType::FILTER,
52 | [
53 | $this->query->toArray(),
54 | [
55 | TermType::JSON,
56 | $jsonDocuments,
57 | ],
58 | ],
59 | ];
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Query/Operation/FilterByRow.php:
--------------------------------------------------------------------------------
1 | query = $query;
37 | $this->functionQuery = $manipulation;
38 | $this->rethink = $rethink;
39 | }
40 |
41 | public function toArray(): array
42 | {
43 | return [
44 | TermType::FILTER,
45 | [
46 | $this->query->toArray(),
47 | $this->functionQuery->toArray(),
48 | ],
49 | ];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Query/Operation/Get.php:
--------------------------------------------------------------------------------
1 | query = $query;
34 | $this->key = $key;
35 | $this->rethink = $rethink;
36 | }
37 |
38 | public function toArray(): array
39 | {
40 | return [
41 | TermType::GET,
42 | [
43 | $this->query->toArray(),
44 | [
45 | TermType::DATUM,
46 | $this->key,
47 | ],
48 | ],
49 | ];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Query/Operation/GetAll.php:
--------------------------------------------------------------------------------
1 | query = $query;
39 | $this->keys = $keys;
40 | $this->rethink = $rethink;
41 | }
42 |
43 | public function toArray(): array
44 | {
45 | return [
46 | TermType::GET_ALL,
47 | array_merge(
48 | [$this->query->toArray()],
49 | array_values($this->keys)
50 | ),
51 | ];
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Query/Operation/IndexCreate.php:
--------------------------------------------------------------------------------
1 | query = $query;
31 | $this->rethink = $rethink;
32 |
33 | $this->name = $name;
34 | }
35 |
36 | public function toArray(): array
37 | {
38 | return [
39 | TermType::INDEX_CREATE,
40 | [
41 | $this->query->toArray(),
42 | [
43 | TermType::DATUM,
44 | $this->name,
45 | ],
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Operation/IndexDrop.php:
--------------------------------------------------------------------------------
1 | query = $query;
31 | $this->rethink = $rethink;
32 |
33 | $this->name = $name;
34 | }
35 |
36 | public function toArray(): array
37 | {
38 | return [
39 | TermType::INDEX_DROP,
40 | [
41 | $this->query->toArray(),
42 | [
43 | TermType::DATUM,
44 | $this->name,
45 | ],
46 | ],
47 | ];
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Query/Operation/IndexList.php:
--------------------------------------------------------------------------------
1 | query = $query;
23 | $this->rethink = $rethink;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::INDEX_LIST,
30 | [
31 | $this->query->toArray(),
32 | ],
33 | ];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Query/Operation/IndexRename.php:
--------------------------------------------------------------------------------
1 | query = $query;
37 | $this->rethink = $rethink;
38 |
39 | $this->oldValue = $oldValue;
40 | $this->newValue = $newValue;
41 | }
42 |
43 | public function toArray(): array
44 | {
45 | return [
46 | TermType::INDEX_RENAME,
47 | [
48 | $this->query->toArray(),
49 | [
50 | TermType::DATUM,
51 | $this->oldValue,
52 | ],
53 | [
54 | TermType::DATUM,
55 | $this->newValue,
56 | ],
57 | ],
58 | ];
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Query/Operation/Insert.php:
--------------------------------------------------------------------------------
1 | query = $query;
30 | $this->documents = [$documents];
31 | $this->rethink = $rethink;
32 | }
33 |
34 | public function toArray(): array
35 | {
36 | $jsonDocuments = [];
37 | foreach ($this->documents as $key => $document) {
38 | $jsonDocuments[] = json_encode($document);
39 | }
40 |
41 | return [
42 | TermType::INSERT,
43 | [
44 | $this->query->toArray(),
45 | [
46 | TermType::JSON,
47 | $jsonDocuments,
48 | ],
49 | ],
50 | ];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Query/Operation/OperationTrait.php:
--------------------------------------------------------------------------------
1 | rethink, /** @scrutinizer ignore-type */ $this, $options);
14 | }
15 |
16 | public function delete(): QueryInterface
17 | {
18 | return new Delete($this->rethink, /** @scrutinizer ignore-type */ $this);
19 | }
20 |
21 | public function filter($value)
22 | {
23 | if (\is_object($value)) {
24 | return new FilterByRow($this->rethink, /** @scrutinizer ignore-type */ $this, $value);
25 | }
26 |
27 | return new Filter($this->rethink, /** @scrutinizer ignore-type */ $this, $value);
28 | }
29 |
30 | public function getAll(...$keys): GetAll
31 | {
32 | return new GetAll($this->rethink, /** @scrutinizer ignore-type */ $this, $keys);
33 | }
34 |
35 | public function update(array $elements): QueryInterface
36 | {
37 | return new Update($this->rethink, /** @scrutinizer ignore-type */ $this, $elements);
38 | }
39 |
40 | public function insert(array $document): QueryInterface
41 | {
42 | return new Insert($this->rethink, /** @scrutinizer ignore-type */ $this, $document);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Query/Operation/Sync.php:
--------------------------------------------------------------------------------
1 | query = $query;
25 | $this->rethink = $rethink;
26 | }
27 |
28 | public function toArray(): array
29 | {
30 | return [
31 | TermType::SYNC,
32 | [
33 | $this->query->toArray(),
34 | ],
35 | ];
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Query/Operation/TableCreate.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
22 |
23 | $this->name = $name;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::TABLE_CREATE,
30 | [
31 | [
32 | TermType::DATUM,
33 | $this->name,
34 | ],
35 | ],
36 | ];
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Query/Operation/TableDrop.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
22 |
23 | $this->name = $name;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::TABLE_DROP,
30 | [
31 | [
32 | TermType::DATUM,
33 | $this->name,
34 | ],
35 | ],
36 | ];
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Query/Operation/TableList.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
17 | }
18 |
19 | public function toArray(): array
20 | {
21 | return [
22 | TermType::TABLE_LIST,
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Query/Operation/Update.php:
--------------------------------------------------------------------------------
1 | query = $query;
31 | $this->elements = $elements;
32 | $this->rethink = $rethink;
33 | }
34 |
35 | public function toArray(): array
36 | {
37 | $jsonElements = json_encode($this->elements);
38 |
39 | return [
40 | TermType::UPDATE,
41 | [
42 | $this->query->toArray(),
43 | [
44 | TermType::JSON,
45 | [
46 | $jsonElements
47 | ],
48 | ],
49 | ],
50 | ];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Query/Options.php:
--------------------------------------------------------------------------------
1 | db = [
18 | TermType::DB,
19 | [$name],
20 | ];
21 |
22 | return $this;
23 | }
24 |
25 | public function jsonSerialize()
26 | {
27 | if (empty($this->db)) {
28 | return [];
29 | }
30 |
31 | return [
32 | 'db' => $this->db
33 | ];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Query/OptionsInterface.php:
--------------------------------------------------------------------------------
1 | asc($key);
21 | }
22 |
23 | public function asc(string $key): Ordening
24 | {
25 | $this->query = [
26 | TermType::ASC,
27 | [
28 | $key,
29 | ],
30 | ];
31 |
32 | return $this;
33 | }
34 |
35 | public function desc(string $key): Ordening
36 | {
37 | $this->query = [
38 | TermType::DESC,
39 | [
40 | $key,
41 | ],
42 | ];
43 |
44 | return $this;
45 | }
46 |
47 | public function toArray(): array
48 | {
49 | return $this->query;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Query/QueryInterface.php:
--------------------------------------------------------------------------------
1 | rethink = $rethink;
38 |
39 |
40 | $this->query = [
41 | TermType::TABLE,
42 | [
43 | $name,
44 | ],
45 | ];
46 | }
47 |
48 | public function changes(array $options = null): Changes
49 | {
50 | return new Changes($this->rethink, $this, $options);
51 | }
52 |
53 | public function get($key): Get
54 | {
55 | return new Get($this->rethink, $this, $key);
56 | }
57 |
58 | public function indexCreate(string $name): AbstractQuery
59 | {
60 | return new IndexCreate($this->rethink, $this, $name);
61 | }
62 |
63 | public function indexDrop(string $name): AbstractQuery
64 | {
65 | return new IndexDrop($this->rethink, $this, $name);
66 | }
67 |
68 | public function indexList(): AbstractQuery
69 | {
70 | return new IndexList($this->rethink, $this);
71 | }
72 |
73 | public function indexRename(string $oldValue, string $newValue): AbstractQuery
74 | {
75 | return new IndexRename($this->rethink, $this, $oldValue, $newValue);
76 | }
77 |
78 | public function between($min, $max, array $options = null): Between
79 | {
80 | return new Between($this->rethink, $this, $min, $max, $options);
81 | }
82 |
83 | public function hasFields(...$keys)
84 | {
85 | return new HasFields($this->rethink, $this, $keys);
86 | }
87 |
88 | public function sync()
89 | {
90 | return new Sync($this->rethink, $this);
91 | }
92 |
93 | public function toArray(): array
94 | {
95 | return $this->query;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/Query/Transformation/IsEmpty.php:
--------------------------------------------------------------------------------
1 | query = $query;
23 | $this->rethink = $rethink;
24 | }
25 |
26 | public function toArray(): array
27 | {
28 | return [
29 | TermType::IS_EMPTY,
30 | [
31 | $this->query->toArray(),
32 | ],
33 | ];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Query/Transformation/Limit.php:
--------------------------------------------------------------------------------
1 | query = $query;
37 | $this->n = $n;
38 | $this->rethink = $rethink;
39 | }
40 |
41 | public function toArray(): array
42 | {
43 | return [
44 | TermType::LIMIT,
45 | [
46 | $this->query->toArray(),
47 | [
48 | TermType::DATUM,
49 | $this->n,
50 | ],
51 | ],
52 | ];
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Query/Transformation/OrderBy.php:
--------------------------------------------------------------------------------
1 | query = $query;
35 | $this->key = $key;
36 | $this->rethink = $rethink;
37 | }
38 |
39 | public function toArray(): array
40 | {
41 | $ordering = $this->key instanceof QueryInterface ? $this->key->toArray() : $this->key;
42 |
43 | return [
44 | TermType::ORDER_BY,
45 | [
46 | $this->query->toArray(),
47 | $ordering,
48 | ],
49 | ];
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Query/Transformation/Skip.php:
--------------------------------------------------------------------------------
1 | query = $query;
35 | $this->n = $n;
36 | $this->rethink = $rethink;
37 | }
38 |
39 | public function toArray(): array
40 | {
41 | return [
42 | TermType::SKIP,
43 | [
44 | $this->query->toArray(),
45 | [
46 | TermType::DATUM,
47 | $this->n,
48 | ],
49 | ],
50 | ];
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Query/Transformation/TransformationTrait.php:
--------------------------------------------------------------------------------
1 | rethink, /** @scrutinizer ignore-type */ $this);
13 | }
14 |
15 | public function limit($value): Limit
16 | {
17 | return new Limit($this->rethink, /** @scrutinizer ignore-type */ $this, $value);
18 | }
19 |
20 | public function skip($value): Skip
21 | {
22 | return new Skip($this->rethink, /** @scrutinizer ignore-type */ $this, $value);
23 | }
24 |
25 | public function orderBy($key): OrderBy
26 | {
27 | return new OrderBy($this->rethink, /** @scrutinizer ignore-type */ $this, $key);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Response/Cursor.php:
--------------------------------------------------------------------------------
1 | connection = $connection;
49 | $this->token = $token;
50 | $this->addResponse($response);
51 | $this->message = $message;
52 | }
53 |
54 | /**
55 | * @throws \Exception
56 | */
57 | public function current()
58 | {
59 | $this->seek();
60 |
61 | if (!$this->valid()) {
62 | return;
63 | }
64 |
65 | if ($this->response->isAtomic()) {
66 | return $this->response->getData();
67 | }
68 |
69 | return $this->response->getData()[$this->index];
70 | }
71 |
72 | /**
73 | * @throws \Exception
74 | */
75 | public function next(): void
76 | {
77 | $this->index++;
78 |
79 | $this->seek();
80 | }
81 |
82 | public function key(): int
83 | {
84 | return $this->index;
85 | }
86 |
87 | public function valid(): bool
88 | {
89 | return (!$this->isComplete || ($this->index < $this->size));
90 | }
91 |
92 | /**
93 | * @throws ConnectionException
94 | */
95 | public function rewind(): void
96 | {
97 | if ($this->index === 0) {
98 | return;
99 | }
100 |
101 | $this->close();
102 | $this->addResponse($this->connection->rewindFromCursor($this->message));
103 | }
104 |
105 | public function count()
106 | {
107 | return $this->size;
108 | }
109 |
110 | private function addResponse(ResponseInterface $response)
111 | {
112 | $this->index = 0;
113 | $this->isComplete = $response->getType() === ResponseType::SUCCESS_SEQUENCE;
114 |
115 | if (\is_null($response->getData())) {
116 | $this->size = 0;
117 | } else {
118 | $this->size = $response->isAtomic() ? 1 : \count($response->getData());
119 | }
120 |
121 | $this->response = $response;
122 | }
123 |
124 | /**
125 | * @throws \Exception
126 | */
127 | private function seek(): void
128 | {
129 | if ($this->index >= $this->size && !$this->isComplete) {
130 | $this->request();
131 | }
132 | }
133 |
134 | /**
135 | * @throws \Exception
136 | */
137 | private function request(): void
138 | {
139 | try {
140 | $response = $this->connection->continueQuery($this->token);
141 | $this->addResponse($response);
142 | } catch (\Exception $e) {
143 | $this->isComplete = true;
144 | $this->close();
145 |
146 | throw $e;
147 | }
148 | }
149 |
150 | private function close(): void
151 | {
152 | if (!$this->isComplete) {
153 | $this->connection->stopQuery($this->token);
154 | $this->isComplete = true;
155 | }
156 |
157 | $this->index = 0;
158 | $this->size = 0;
159 | $this->response = null;
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/src/Response/Response.php:
--------------------------------------------------------------------------------
1 | type = $t;
35 | !$r ?: $this->data = $r;
36 | !$b ?: $this->backtrace = $b;
37 | !$p ?: $this->profile = $p;
38 | !$n ?: $this->note = $n;
39 | }
40 |
41 | public function getType(): ?int
42 | {
43 | return $this->type;
44 | }
45 |
46 | public function getData()
47 | {
48 | if (!\is_array($this->data)) {
49 | return null;
50 | }
51 |
52 | if (isset($this->data[0]['$reql_type$']) && $this->data[0]['$reql_type$'] === 'GROUPED_DATA') {
53 | $groups = [];
54 | foreach ($this->data[0]['data'] as $group) {
55 | $groups[] = [
56 | 'group' => $group[0],
57 | 'reduction' => $group[1],
58 | ];
59 | }
60 |
61 | return $groups;
62 | }
63 |
64 | return \count($this->data) === 1 && array_key_exists(0, $this->data) ? $this->data[0] : $this->data;
65 | }
66 |
67 | public function isAtomic(): bool
68 | {
69 | return \is_string($this->data) || (!\is_null($this->data) && \count($this->data) === 1);
70 | }
71 |
72 | public function getBacktrace(): ?array
73 | {
74 | return $this->backtrace;
75 | }
76 |
77 | public function getProfile(): ?array
78 | {
79 | return $this->profile;
80 | }
81 |
82 | public function getNote(): ?array
83 | {
84 | return $this->note;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/Response/ResponseInterface.php:
--------------------------------------------------------------------------------
1 | connection = $connection;
27 | $this->builder = new Builder($this);
28 | }
29 |
30 | public function db(): Database
31 | {
32 | return $this->builder->database();
33 | }
34 |
35 | public function dbCreate(string $name): Database
36 | {
37 | return $this->builder->database()->dbCreate($name);
38 | }
39 |
40 | public function dbDrop(string $name): Database
41 | {
42 | return $this->builder->database()->dbDrop($name);
43 | }
44 |
45 | public function dbList(): Database
46 | {
47 | return $this->builder->database()->dbList();
48 | }
49 |
50 | public function connection(): ConnectionInterface
51 | {
52 | return $this->connection;
53 | }
54 |
55 | public function table(string $name): Table
56 | {
57 | return $this->builder->table($name);
58 | }
59 |
60 | public function desc($key): Ordening
61 | {
62 | return $this->builder->ordening($key)->desc($key);
63 | }
64 |
65 | public function asc($key): Ordening
66 | {
67 | return $this->builder->ordening($key)->asc($key);
68 | }
69 |
70 | public function row(?string $value = null): Row
71 | {
72 | return $this->builder->row($value);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/RethinkInterface.php:
--------------------------------------------------------------------------------
1 | isCircularReference($object, $context)) {
17 | return $this->handleCircularReference($object);
18 | }
19 |
20 | if (!$object instanceof \JsonSerializable && !$object instanceof \stdClass) {
21 | throw new InvalidArgumentException(
22 | sprintf('The '.get_class($object).' must implement "%s".', \JsonSerializable::class)
23 | );
24 | }
25 |
26 | if (!$this->serializer instanceof NormalizerInterface) {
27 | throw new LogicException('Cannot normalize object because injected serializer is not a normalizer');
28 | }
29 |
30 | if ($object instanceof \stdClass) {
31 | return (array) $object;
32 | }
33 |
34 | if ($object instanceof OptionsInterface) {
35 | return (object) $object->jsonSerialize();
36 | }
37 |
38 | return $this->serializer->normalize($object->jsonSerialize(), $format, $context);
39 | }
40 |
41 | public function supportsNormalization($data, $format = null)
42 | {
43 | return \is_object($data) && $format === 'json';
44 | }
45 |
46 | public function supportsDenormalization($data, $type, $format = null)
47 | {
48 | return false;
49 | }
50 |
51 | public function denormalize($data, $class, $format = null, array $context = [])
52 | {
53 | throw new LogicException(sprintf('Cannot denormalize with "%s".', __CLASS__));
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Types/Frame/FrameType.php:
--------------------------------------------------------------------------------
1 | [
10 | 'hostname' => 'localhost',
11 | 'port' => 28015,
12 | 'dbname' => 'test',
13 | 'user' => 'admin',
14 | 'password' => '',
15 | 'timeout' => 5,
16 | 'timeout_stream' => 10,
17 | ],
18 | ]
19 | );
20 |
--------------------------------------------------------------------------------
/test/config_scrutinizer.php:
--------------------------------------------------------------------------------
1 | [
7 | 'hostname' => 'localhost',
8 | 'port' => 28015,
9 | 'dbname' => 'test',
10 | 'user' => 'admin',
11 | 'password' => '',
12 | 'timeout' => 5,
13 | 'timeout_stream' => 10,
14 | ],
15 | ]
16 | );
17 |
--------------------------------------------------------------------------------
/test/integration/AbstractTestCase.php:
--------------------------------------------------------------------------------
1 | allowMockingNonExistentMethods(false);
39 |
40 | // Make sure we destroy a failed previous unit test database schema
41 | $this->tearDown();
42 |
43 | parent::setUp();
44 | }
45 |
46 | protected function r()
47 | {
48 | if ($this->r !== null) {
49 | return $this->r;
50 | }
51 |
52 | $name = 'phpunit_default';
53 | $options = new Options(PHPUNIT_CONNECTIONS[$name]);
54 |
55 | /** @var ConnectionInterface $connection */
56 | $connection = $this->createConnection($name)->connect();
57 | $connection->connect()->use($options->getDbName());
58 |
59 | $this->r = new Rethink($connection);
60 |
61 | /** @var ResponseInterface $res */
62 | $res = $this->r->dbList()->run();
63 | if (\is_array($res->getData()) && !\in_array($options->getDbName(), $res->getData(), true)) {
64 | $this->r->dbCreate($options->getDbName())->run();
65 | }
66 |
67 | return $this->r;
68 | }
69 |
70 | protected function tearDown()
71 | {
72 | if ($this->r === null) {
73 | return;
74 | }
75 |
76 | $name = 'phpunit_default';
77 | $options = new Options(PHPUNIT_CONNECTIONS[$name]);
78 |
79 | /** @var ResponseInterface $res */
80 | $res = $this->r->dbList()->run();
81 | if (\is_array($res->getData()) && \in_array($options->getDbName(), $res->getData(), true)) {
82 | $this->r->dbDrop($options->getDbName())->run();
83 | }
84 | }
85 |
86 | /**
87 | * @param string $name
88 | * @return ConnectionInterface
89 | * @throws Exception
90 | */
91 | protected function createConnection(string $name): ConnectionInterface
92 | {
93 | $options = new Options(PHPUNIT_CONNECTIONS[$name]);
94 |
95 | $connection = new Connection(
96 | function () use ($options) {
97 | return new Socket(
98 | $options
99 | );
100 | },
101 | new Handshake($options->getUser(), $options->getPassword(), Version::V1_0),
102 | $options->getDbName(),
103 | new Serializer(
104 | [new QueryNormalizer()],
105 | [new JsonEncoder()]
106 | ),
107 | new Serializer(
108 | [new ObjectNormalizer()],
109 | [new JsonEncoder()]
110 | )
111 | );
112 |
113 | $this->connections[] = $connection;
114 |
115 | return $connection;
116 | }
117 |
118 | public function __destruct()
119 | {
120 | foreach ($this->connections as $connection) {
121 | $connection->close();
122 | }
123 |
124 | Mockery::close();
125 | }
126 |
127 | /**
128 | * @param $status
129 | * @param $data
130 | * @throws \Exception
131 | */
132 | protected function assertObStatus($status, $data)
133 | {
134 | $res = [];
135 | $statuses = [
136 | 'tables_created',
137 | 'tables_dropped',
138 | 'created',
139 | 'dropped',
140 | 'renamed',
141 | 'unchanged',
142 | 'skipped',
143 | 'replaced',
144 | 'inserted',
145 | 'errors',
146 | 'deleted',
147 | ];
148 | $data = new ArrayObject($data);
149 |
150 | foreach ($statuses as $s) {
151 | $status[$s] = $status[$s] ?? 0;
152 | }
153 |
154 | $data->setFlags($data::ARRAY_AS_PROPS);
155 |
156 | foreach ($statuses as $s) {
157 | $res[$s] = $data[$s] ?? 0;
158 | }
159 |
160 | $this->assertEquals($status, $res);
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/test/integration/Aggregation/AvgTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(5, 5);
18 | $this->insertDocumentWithNumber(4, 10);
19 | $this->insertDocumentWithNumber(3, 15);
20 | $this->insertDocumentWithNumber(2, 20);
21 | $this->insertDocumentWithNumber(1, 25);
22 |
23 | /** @var ResponseInterface $res */
24 | $res = $this->r()
25 | ->table('tabletest')
26 | ->avg('number')
27 | ->run();
28 |
29 | $this->assertEquals(15, $res->getData());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/integration/Aggregation/CountTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(5, 5);
17 | $this->insertDocumentWithNumber(4, 10);
18 | $this->insertDocumentWithNumber(3, 15);
19 | $this->insertDocumentWithNumber(2, 20);
20 | $this->insertDocumentWithNumber(1, 25);
21 |
22 | $res = $this->r()
23 | ->table('tabletest')
24 | ->count()
25 | ->run();
26 |
27 | $this->assertEquals(5, $res->getData());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/integration/Aggregation/GroupTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(5, 10);
18 | $this->insertDocumentWithNumber(4, 10);
19 | $this->insertDocumentWithNumber(3, 20);
20 | $this->insertDocumentWithNumber(2, 20);
21 | $this->insertDocumentWithNumber(1, 30);
22 |
23 | /** @var ResponseInterface $res */
24 | $res = $this->r()
25 | ->table('tabletest')
26 | ->group('description')
27 | ->run();
28 |
29 | $this->assertCount(1, $res->getData());
30 |
31 | $this->assertEquals('A document description.', $res->getData()[0]['group']);
32 | $this->assertCount(1, $res->getData());
33 | }
34 |
35 | /**
36 | * @return void
37 | * @throws \Exception
38 | */
39 | public function testGroupByNumber(): void
40 | {
41 | $this->insertDocumentWithNumber(5, 10);
42 | $this->insertDocumentWithNumber(4, 10);
43 | $this->insertDocumentWithNumber(3, 20);
44 | $this->insertDocumentWithNumber(2, 20);
45 | $this->insertDocumentWithNumber(1, 30);
46 |
47 | /** @var ResponseInterface $res */
48 | $res = $this->r()
49 | ->table('tabletest')
50 | ->group('number')
51 | ->run();
52 |
53 | $this->assertCount(3, $res->getData());
54 |
55 | $this->assertEquals(10, $res->getData()[0]['group']);
56 | $this->assertCount(2, $res->getData()[0]['reduction']);
57 |
58 | $this->assertEquals(20, $res->getData()[1]['group']);
59 | $this->assertCount(2, $res->getData()[1]['reduction']);
60 |
61 | $this->assertEquals(30, $res->getData()[2]['group']);
62 | $this->assertCount(1, $res->getData()[2]['reduction']);
63 | }
64 |
65 | /**
66 | * @return void
67 | * @throws \Exception
68 | */
69 | public function testGroupAndMaxByNumberReductionByNumberAndUngroupOrderByNumber(): void
70 | {
71 | $this->insertDocumentWithNumber('Bob', 10);
72 | $this->insertDocumentWithNumber('Alice', 20);
73 | $this->insertDocumentWithNumber('Bob', 30);
74 | $this->insertDocumentWithNumber('Alice', 40);
75 | $this->insertDocumentWithNumber('Harry', 50);
76 | $this->insertDocumentWithNumber('Harry', 45);
77 |
78 | /** @var ResponseInterface $res */
79 | $res = $this->r()
80 | ->table('tabletest')
81 | ->group('id')->max('number')->getField('number')
82 | ->ungroup()
83 | ->orderBy($this->r()->desc('number'))
84 | ->run();
85 |
86 | $this->assertCount(3, $res->getData());
87 |
88 | $this->assertEquals('Alice', $res->getData()[0]['group']);
89 | $this->assertEquals(20, $res->getData()[0]['reduction'][0]);
90 |
91 | $this->assertEquals('Bob', $res->getData()[1]['group']);
92 | $this->assertEquals(10, $res->getData()[1]['reduction'][0]);
93 |
94 | $this->assertEquals('Harry', $res->getData()[2]['group']);
95 | $this->assertEquals(50, $res->getData()[2]['reduction'][0]);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/test/integration/Aggregation/MaxTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(5, 99);
18 | $this->insertDocumentWithNumber(4, 77);
19 | $this->insertDocumentWithNumber(3, 1045);
20 | $this->insertDocumentWithNumber(2, 4);
21 | $this->insertDocumentWithNumber(1, 43534);
22 |
23 | /** @var ResponseInterface $res */
24 | $res = $this->r()
25 | ->table('tabletest')
26 | ->max('number')
27 | ->run();
28 |
29 | /** @var array $array */
30 | $array = $res->getData();
31 |
32 | $this->assertArraySubset(['number' => 43534], $array);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/integration/Aggregation/MinTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(5, 99);
18 | $this->insertDocumentWithNumber(4, 77);
19 | $this->insertDocumentWithNumber(3, 1045);
20 | $this->insertDocumentWithNumber(2, 4);
21 | $this->insertDocumentWithNumber(1, 43534);
22 |
23 | /** @var ResponseInterface $res */
24 | $res = $this->r()
25 | ->table('tabletest')
26 | ->min('number')
27 | ->run();
28 |
29 | /** @var array $array */
30 | $array = $res->getData();
31 |
32 | $this->assertArraySubset(['number' => 4], $array);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test/integration/Aggregation/SumTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(5, 5);
18 | $this->insertDocumentWithNumber(4, 10);
19 | $this->insertDocumentWithNumber(3, 15);
20 | $this->insertDocumentWithNumber(2, 20);
21 | $this->insertDocumentWithNumber(1, 25);
22 |
23 | /** @var ResponseInterface $res */
24 | $res = $this->r()
25 | ->table('tabletest')
26 | ->sum('number')
27 | ->run();
28 |
29 | $this->assertEquals(75, $res->getData());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/integration/Connection/ConnectionTest.php:
--------------------------------------------------------------------------------
1 | optionsMock = Mockery::mock(OptionsInterface::class);
26 | }
27 |
28 | /**
29 | * @throws \Exception
30 | */
31 | public function testConnect()
32 | {
33 | /** @var ConnectionInterface $connection */
34 | $connection = $this->createConnection('phpunit_default')->connect();
35 | $result = $connection->expr('foo');
36 |
37 | $this->assertInstanceOf(ResponseInterface::class, $result);
38 | $this->assertEquals('foo', $result->getData());
39 | }
40 |
41 | /**
42 | * @throws \Exception
43 | */
44 | public function testServer()
45 | {
46 | /** @var ConnectionInterface $connection */
47 | $res = $this->createConnection('phpunit_default')->connect()->server();
48 |
49 | $this->assertEquals(QueryType::SERVER_INFO, $res->getType());
50 | $this->assertInternalType('string', $res->getData()['name']);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/integration/Manipulation/HasFieldsTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
17 | $this->insertDocument(2);
18 | $this->insertDocumentWithNumber(3, 1);
19 |
20 | /** @var Cursor $cursor */
21 | $cursor = $this->r()
22 | ->table('tabletest')
23 | ->hasFields('number')
24 | ->run();
25 |
26 | $this->assertInstanceOf(\Iterator::class, $cursor);
27 | $this->assertEquals(1, $cursor->count());
28 | }
29 |
30 | /**
31 | * @throws \Exception
32 | */
33 | public function testHasField()
34 | {
35 | $this->insertDocument(1);
36 | $this->insertDocument(2);
37 | $this->insertDocumentWithNumber(3, 1);
38 |
39 | /** @var Cursor $cursor */
40 | $cursor = $this->r()
41 | ->table('tabletest')
42 | ->filter($this->r()->row()->hasFields('number'))
43 | ->run();
44 |
45 | $this->assertInstanceOf(\Iterator::class, $cursor);
46 | $this->assertEquals(1, $cursor->count());
47 | }
48 |
49 | /**
50 | * @throws \Exception
51 | */
52 | public function testHasFields()
53 | {
54 | $this->insertDocument(1);
55 | $this->insertDocument(2);
56 | $this->insertDocumentWithNumber(3, 1);
57 |
58 | /** @var Cursor $cursor */
59 | $cursor = $this->r()
60 | ->table('tabletest')
61 | ->filter($this->r()->row()->hasFields('id', 'number'))
62 | ->run();
63 |
64 | $this->assertInstanceOf(\Iterator::class, $cursor);
65 | $this->assertEquals(1, $cursor->count());
66 | }
67 |
68 | /**
69 | * @throws \Exception
70 | */
71 | public function testHasFieldsNot()
72 | {
73 | $this->insertDocument(1);
74 | $this->insertDocument(2);
75 | $this->insertDocumentWithNumber(3, 1);
76 |
77 | /** @var Cursor $cursor */
78 | $cursor = $this->r()
79 | ->table('tabletest')
80 | ->filter($this->r()->row()->hasFields('id', 'number')->not())
81 | ->run();
82 |
83 | $this->assertInstanceOf(\Iterator::class, $cursor);
84 | $this->assertEquals(2, $cursor->count());
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/test/integration/Manipulation/KeysTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(1, 1);
17 |
18 | /** @var ResponseInterface $response */
19 | $response = $this->r()
20 | ->table('tabletest')
21 | ->get(1)
22 | ->keys()
23 | ->run();
24 |
25 | $this->assertInstanceOf(ResponseInterface::class, $response);
26 | $this->assertCount(4, $response->getData());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test/integration/Manipulation/PluckTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(1, 1);
17 |
18 | /** @var ResponseInterface $response */
19 | $response = $this->r()
20 | ->table('tabletest')
21 | ->get(1)
22 | ->pluck('id', 'description')
23 | ->run();
24 |
25 | $this->assertInstanceOf(ResponseInterface::class, $response);
26 | $this->assertCount(2, $response->getData());
27 | $this->assertArrayHasKey('id', $response->getData());
28 | $this->assertArrayHasKey('description', $response->getData());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test/integration/Manipulation/ValuesTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(1, 777);
17 |
18 | /** @var ResponseInterface $cursor */
19 | $response = $this->r()
20 | ->table('tabletest')
21 | ->get(1)
22 | ->values()
23 | ->run();
24 |
25 | $this->assertInstanceOf(ResponseInterface::class, $response);
26 | $this->assertCount(4, $response->getData());
27 | $this->assertArraySubset([2 => 777], $response->getData());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/integration/Manipulation/WithoutTest.php:
--------------------------------------------------------------------------------
1 | insertDocumentWithNumber(1, 1);
17 |
18 | /** @var ResponseInterface $cursor */
19 | $response = $this->r()
20 | ->table('tabletest')
21 | ->get(1)
22 | ->without('title', 'number')
23 | ->run();
24 |
25 | $this->assertInstanceOf(ResponseInterface::class, $response);
26 | $this->assertCount(2, $response->getData());
27 | $this->assertArrayNotHasKey('title', $response->getData());
28 | $this->assertArrayNotHasKey('number', $response->getData());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test/integration/Operation/AbstractTableTest.php:
--------------------------------------------------------------------------------
1 | r()->db()->tableList()->run();
16 | if (\is_array($res->getData()) && !\in_array('tabletest', $res->getData(), true)) {
17 | $this->r()->db()->tableCreate('tabletest')->run();
18 | }
19 | }
20 |
21 | public function tearDown()
22 | {
23 | $res = $this->r()->db()->tableList()->run();
24 | if (\is_array($res->getData()) && \in_array('tabletest', $res->getData(), true)) {
25 | $this->r()->db()->tableDrop('tabletest')->run();
26 | }
27 | }
28 |
29 | /**
30 | * @param int|string $id
31 | * @return ResponseInterface
32 | */
33 | protected function insertDocument($id): ResponseInterface
34 | {
35 | $res = $this->r()
36 | ->table('tabletest')
37 | ->insert([
38 | 'id' => $id,
39 | 'title' => 'Test document '.$id,
40 | 'description' => 'A document description.',
41 | ])
42 | ->run();
43 |
44 | return $res;
45 | }
46 |
47 | /**
48 | * @param int|string $id
49 | * @param int $number
50 | * @return ResponseInterface
51 | */
52 | protected function insertDocumentWithNumber($id, int $number): ResponseInterface
53 | {
54 | $res = $this->r()
55 | ->table('tabletest')
56 | ->insert([
57 | 'id' => $id,
58 | 'title' => 'Test document '.$id,
59 | 'number' => $number,
60 | 'description' => 'A document description.',
61 | ])
62 | ->run();
63 |
64 | return $res;
65 | }
66 |
67 | /**
68 | * @param int|string $id
69 | * @param \DateTimeInterface $dateTime
70 | * @return ResponseInterface
71 | */
72 | protected function insertDocumentWithDate($id, \DateTimeInterface $dateTime): ResponseInterface
73 | {
74 | $res = $this->r()
75 | ->table('tabletest')
76 | ->insert([
77 | 'id' => $id,
78 | 'title' => 'Test document '.$id,
79 | 'date' => $dateTime->format(\Datetime::ATOM),
80 | 'description' => 'A document description.',
81 | ])
82 | ->run();
83 |
84 | return $res;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/test/integration/Operation/BetweenTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
18 | $this->insertDocument(3);
19 |
20 | /** @var Cursor $cursor */
21 | $cursor = $this->r()
22 | ->table('tabletest')
23 | ->between(1, 2)
24 | ->run();
25 |
26 | /** @var array $array */
27 | $array = $cursor->current();
28 |
29 | $this->assertInstanceOf(\Iterator::class, $cursor);
30 | $this->assertEquals(1, $cursor->count());
31 | $this->assertArraySubset(['title' => 'Test document 1'], $array);
32 | }
33 |
34 | /**
35 | * @throws \Exception
36 | */
37 | public function testBetweenMax()
38 | {
39 | $this->insertDocument(1);
40 | $this->insertDocument(3);
41 |
42 | /** @var Cursor $cursor */
43 | $cursor = $this->r()
44 | ->table('tabletest')
45 | ->between(2, 3)
46 | ->run();
47 |
48 | $this->assertInstanceOf(\Iterator::class, $cursor);
49 | $this->assertCount(0, $cursor);
50 | }
51 |
52 | /**
53 | * @throws \Exception
54 | */
55 | public function testBetweenMultiple()
56 | {
57 | $this->insertDocument(1);
58 | $this->insertDocument(2);
59 | $this->insertDocument(3);
60 | $this->insertDocument(4);
61 | $this->insertDocument(5);
62 |
63 | /** @var Cursor $cursor */
64 | $cursor = $this->r()
65 | ->table('tabletest')
66 | ->between(2, 4)
67 | ->run();
68 |
69 | $this->assertInstanceOf(\Iterator::class, $cursor);
70 | $this->assertCount(2, $cursor);
71 | }
72 |
73 | /**
74 | * @return void
75 | * @throws \Exception
76 | */
77 | public function testBetweenNoResult(): void
78 | {
79 | $this->insertDocument('stringId');
80 |
81 | /** @var Cursor $cursor */
82 | $cursor = $this->r()
83 | ->table('tabletest')
84 | ->between(2, 4)
85 | ->run();
86 |
87 | $this->assertInstanceOf(\Iterator::class, $cursor);
88 | $this->assertCount(0, $cursor);
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/test/integration/Operation/ChangesTest.php:
--------------------------------------------------------------------------------
1 | r()
18 | ->table('tabletest')
19 | ->changes()
20 | ->run();
21 |
22 | $this->insertDocument(1);
23 | $this->insertDocument(2);
24 | $this->insertDocument(3);
25 | $this->insertDocument(4);
26 | $this->insertDocument(5);
27 |
28 | /** @var ResponseInterface $res */
29 | $i = 1;
30 | foreach ($feed as $change) {
31 | $old_val = $change['old_val'];
32 | $new_val = $change['new_val'];
33 |
34 | $this->assertEmpty($old_val);
35 | $this->assertEquals($i, $new_val['id']);
36 |
37 | if ($i === 5) {
38 | break;
39 | }
40 |
41 | $i++;
42 | }
43 | }
44 |
45 | /**
46 | * @throws \Exception
47 | */
48 | public function testChangesUpdates(): void
49 | {
50 | /** @var Cursor $feed */
51 | $feed = $this->r()
52 | ->table('tabletest')
53 | ->changes()
54 | ->run();
55 |
56 | $this->insertDocument(777);
57 |
58 | $this->r()->table('tabletest')->filter(['id' => 777])->update(['description' => 'cool!'])->run();
59 |
60 | $i = 777;
61 | foreach ($feed as $change) {
62 | $old_val = $change['old_val'];
63 | $new_val = $change['new_val'];
64 |
65 | if ($old_val !== null) {
66 | $this->assertEquals('A document description.', $old_val['description']);
67 | $this->assertEquals('cool!', $new_val['description']);
68 |
69 | break;
70 | }
71 |
72 | $this->assertEmpty($old_val);
73 | $this->assertEquals($i, $new_val['id']);
74 | }
75 | }
76 |
77 | /**
78 | * @throws \Exception
79 | */
80 | public function testChangesWithOptions(): void
81 | {
82 | /** @var Cursor $feed */
83 | $feed = $this->r()
84 | ->table('tabletest')
85 | ->changes(['squash' => true])
86 | ->run();
87 |
88 | $this->insertDocument(1);
89 | $this->r()->table('tabletest')->filter(['id' => 1])->update(['description' => 'cool!'])->run();
90 |
91 | $change = $feed->current();
92 | $old_val = $change['old_val'];
93 | $new_val = $change['new_val'];
94 |
95 | $this->assertEmpty($old_val);
96 | $this->assertEquals(1, $new_val['id']);
97 | $this->assertEquals('cool!', $new_val['description']);
98 | }
99 |
100 | /**
101 | * @throws \Exception
102 | */
103 | public function testChangesCreateWithFilter(): void
104 | {
105 | /** @var Cursor $feed */
106 | $feed = $this->r()
107 | ->table('tabletest')
108 | ->filter(['id' => 4])
109 | ->changes()
110 | ->run();
111 |
112 | $this->insertDocument(1);
113 | $this->insertDocument(2);
114 | $this->insertDocument(3);
115 | $this->insertDocument(4);
116 | $this->insertDocument(5);
117 |
118 | $change = $feed->current();
119 | $old_val = $change['old_val'];
120 | $new_val = $change['new_val'];
121 |
122 | $this->assertEmpty($old_val);
123 | $this->assertEquals(4, $new_val['id']);
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/test/integration/Operation/CursorTest.php:
--------------------------------------------------------------------------------
1 | r()->db()->tableList()->run();
16 | if (\is_array($res->getData()) && !\in_array('tabletest_big', $res->getData(), true)) {
17 | $this->r()->db()->tableCreate('tabletest_big')->run();
18 | }
19 | }
20 |
21 | public function tearDown()
22 | {
23 | parent::tearDown();
24 |
25 | $res = $this->r()->db()->tableList()->run();
26 | if (\is_array($res->getData()) && \in_array('tabletest_big', $res->getData(), true)) {
27 | $this->r()->db()->tableDrop('tabletest_big')->run();
28 | }
29 | }
30 |
31 | /**
32 | * @throws \Exception
33 | */
34 | public function testCursor()
35 | {
36 | $this->insertDocuments();
37 |
38 | $response = $this->r()
39 | ->table('tabletest')
40 | ->count()
41 | ->run();
42 |
43 | $this->assertEquals(1000, $response->getData());
44 | }
45 |
46 | /**
47 | * @throws \Exception
48 | */
49 | public function testCursorBigDocuments()
50 | {
51 | $data = [
52 | 'Professor X' => 'Charles Francis Xavier',
53 | 'Cyclops' => 'Scott Summers',
54 | 'Iceman' => 'Robert Louis "Bobby" Drake',
55 | 'Angel' => 'Warren Kenneth Worthington III',
56 | 'Beast' => 'Henry Philip "Hank" McCoy',
57 | 'Marvel Girl/Phoenix' => 'Jean Elaine Grey/Jean Elaine Grey-Summers',
58 | 'Magnetrix/Polaris' => 'Lorna Sally Dane',
59 | 'Nightcrawler' => 'Kurt Wagner',
60 | 'Wolverine' => 'James "Logan" Howlett',
61 | 'Storm' => 'Ororo Monroe',
62 | 'Colossus' => 'Piotr Nikolaievitch "Peter" Rasputin',
63 | 'Sprite/Ariel/Shadowcat' => 'Katherine Anne "Kitty" Pryde',
64 | 'Rogue' => 'Anna Marie',
65 | 'Phoenix/Marvel Girl/Prestige' => 'Rachel Anne Grey-Summers',
66 | 'Psylocke' => 'Elizabeth "Betsy" Braddock',
67 | 'Gambit' => 'Rémy Etienne LeBeau',
68 | 'Jubilee' => 'Jubilation Lee',
69 | 'Bishop' => 'Lucas Bishop',
70 | ];
71 |
72 | $this->insertBigDocuments($data);
73 |
74 | $cursor = $this->r()->table('tabletest_big')->run();
75 |
76 | $i = 0;
77 | foreach ($cursor as $document) {
78 | // Assert the document every 1000s documents.
79 | if ($i % 1000 === 0) {
80 | $this->assertArraySubset($data, $document);
81 | }
82 | $i++;
83 | }
84 |
85 | $this->assertEquals($i, $this->r()->table('tabletest_big')->count()->run()->getData());
86 |
87 | $this->assertInstanceOf(Cursor::class, $cursor);
88 |
89 | $this->r()->table('tabletest_big')->delete()->run();
90 | }
91 |
92 | /**
93 | * @return ResponseInterface
94 | * @throws \Exception
95 | */
96 | private function insertDocuments(): ResponseInterface
97 | {
98 | $documents = [];
99 | for ($i = 1; $i <= 1000; $i++) {
100 | $documents[] = [
101 | 'id' => $i,
102 | 'title' => 'Test document',
103 | 'description' => 'My first document.',
104 | ];
105 | }
106 |
107 | /** @var ResponseInterface $res */
108 | $res = $this->r()
109 | ->table('tabletest')
110 | ->insert($documents)
111 | ->run();
112 |
113 | $this->assertEquals(1000, $res->getData()['inserted']);
114 |
115 | return $res;
116 | }
117 |
118 | /**
119 | * @param array $data
120 | * @return ResponseInterface
121 | * @throws \Exception
122 | */
123 | private function insertBigDocuments(array $data): ResponseInterface
124 | {
125 | $documents = [];
126 | for ($i = 1; $i <= 100; $i++) {
127 | $documents = [];
128 |
129 | for ($x = 1; $x <= 100; $x++) {
130 | $documents[] = $data;
131 | }
132 | }
133 |
134 | /** @var ResponseInterface $res */
135 | $res = $this->r()
136 | ->table('tabletest_big')
137 | ->insert($documents)
138 | ->run();
139 |
140 | $this->assertEquals(100, $res->getData()['inserted']);
141 |
142 | return $res;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/test/integration/Operation/DatabaseTest.php:
--------------------------------------------------------------------------------
1 | r()
14 | ->db()
15 | ->tableList()
16 | ->run();
17 |
18 | $this->assertInternalType('array', $res->getData());
19 | }
20 |
21 | /**
22 | * @throws \Exception
23 | */
24 | public function testTableCreate()
25 | {
26 | $res = $this->r()
27 | ->db()
28 | ->tableCreate('createtable')
29 | ->run();
30 |
31 | $this->assertObStatus(['tables_created' => 1], $res->getData());
32 |
33 | $this->r()
34 | ->db()
35 | ->tableDrop('createtable')
36 | ->run();
37 | }
38 |
39 | /**
40 | * @throws \Exception
41 | */
42 | public function testTableDrop()
43 | {
44 | $this->r()
45 | ->db()
46 | ->tableCreate('createtable')
47 | ->run();
48 |
49 | $res = $this->r()
50 | ->db()
51 | ->tableDrop('createtable')
52 | ->run();
53 |
54 | $this->assertObStatus(['tables_dropped' => 1], $res->getData());
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/test/integration/Operation/DeleteTest.php:
--------------------------------------------------------------------------------
1 | r()
16 | ->table('tabletest')
17 | ->insert([
18 | 'title' => 'Delete document',
19 | ])
20 | ->run();
21 |
22 | /** @var ResponseInterface $count */
23 | $count = $this->r()
24 | ->table('tabletest')
25 | ->filter(['title' => 'Delete document'])
26 | ->count()
27 | ->run();
28 |
29 | $this->assertInternalType('int', $count->getData());
30 |
31 | /** @var ResponseInterface $res */
32 | $res = $this->r()
33 | ->table('tabletest')
34 | ->filter(['title' => 'Delete document'])
35 | ->delete()
36 | ->run();
37 |
38 | $this->assertObStatus(['deleted' => $count->getData()], $res->getData());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/test/integration/Operation/EmptyTableTest.php:
--------------------------------------------------------------------------------
1 | r()
17 | ->table('tabletest')
18 | ->filter(['title' => 'Test document'])
19 | ->count()
20 | ->run();
21 |
22 | $this->assertInternalType('int', $count->getData());
23 |
24 | $res = $this->r()
25 | ->table('tabletest')
26 | ->delete()
27 | ->run();
28 |
29 | $this->assertObStatus(['deleted' => $count->getData()], $res->getData());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/integration/Operation/GetAllTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
18 | $this->insertDocument('stringId');
19 |
20 | /** @var Cursor $cursor */
21 | $cursor = $this->r()
22 | ->table('tabletest')
23 | ->getAll(1, 'stringId')
24 | ->run();
25 |
26 | /** @var array $array */
27 | $array = $cursor->current();
28 |
29 | $this->assertArraySubset(['description' => 'A document description.'], $array);
30 | }
31 |
32 | /**
33 | * @return void
34 | * @throws \Exception
35 | */
36 | public function testGetAllAndIsEmpty(): void
37 | {
38 | $this->insertDocument(1);
39 | $this->insertDocument('stringId');
40 |
41 | /** @var ResponseInterface $res */
42 | $res = $this->r()
43 | ->table('tabletest')
44 | ->getAll(1, 'stringId')
45 | ->isEmpty()
46 | ->run();
47 |
48 | $this->assertFalse($res->getData());
49 | }
50 |
51 | /**
52 | * @return void
53 | * @throws \Exception
54 | */
55 | public function testGetAllAndCount(): void
56 | {
57 | $this->insertDocument(1);
58 | $this->insertDocument('stringId');
59 |
60 | /** @var ResponseInterface $res */
61 | $res = $this->r()
62 | ->table('tabletest')
63 | ->getAll(1, 'stringId')
64 | ->count()
65 | ->run();
66 |
67 | $this->assertEquals(2, $res->getData());
68 | }
69 |
70 | /**
71 | * @return void
72 | * @throws \Exception
73 | */
74 | public function testGetAllAndAvg(): void
75 | {
76 | $this->insertDocumentWithNumber(1, 50);
77 | $this->insertDocumentWithNumber(2, 100);
78 |
79 | /** @var ResponseInterface $res */
80 | $res = $this->r()
81 | ->table('tabletest')
82 | ->getAll(1, 2)
83 | ->avg('number')
84 | ->run();
85 |
86 | $this->assertEquals(75, $res->getData());
87 | }
88 |
89 | /**
90 | * @return void
91 | * @throws \Exception
92 | */
93 | public function testGetAllAndSum(): void
94 | {
95 | $this->insertDocumentWithNumber(1, 50);
96 | $this->insertDocumentWithNumber(2, 100);
97 |
98 | /** @var ResponseInterface $res */
99 | $res = $this->r()
100 | ->table('tabletest')
101 | ->getAll(1, 2)
102 | ->sum('number')
103 | ->run();
104 |
105 | $this->assertEquals(150, $res->getData());
106 | }
107 |
108 | /**
109 | * @return void
110 | * @throws \Exception
111 | */
112 | public function testGetAllAndLimit(): void
113 | {
114 | $this->insertDocument(1);
115 | $this->insertDocument('stringId');
116 |
117 | /** @var ResponseInterface $res */
118 | $cursor = $this->r()
119 | ->table('tabletest')
120 | ->getAll(1, 'stringId')
121 | ->limit(1)
122 | ->run();
123 |
124 | $this->assertCount(1, $cursor);
125 | }
126 |
127 | /**
128 | * @return void
129 | * @throws \Exception
130 | */
131 | public function testGetAllAndSkip(): void
132 | {
133 | $this->insertDocument(1);
134 | $this->insertDocument('stringId');
135 |
136 | /** @var ResponseInterface $res */
137 | $cursor = $this->r()
138 | ->table('tabletest')
139 | ->getAll(1, 'stringId')
140 | ->skip(1)
141 | ->run();
142 |
143 | $this->assertCount(1, $cursor);
144 | }
145 |
146 | /**
147 | * @return void
148 | * @throws \Exception
149 | */
150 | public function testGetAllAndOrderBy(): void
151 | {
152 | $this->insertDocument(1);
153 | $this->insertDocument('stringId');
154 |
155 | /** @var ResponseInterface $res */
156 | $res = $this->r()
157 | ->table('tabletest')
158 | ->getAll(1, 'stringId')
159 | ->orderBy($this->r()->desc('id'))
160 | ->run();
161 |
162 | $this->assertArraySubset(['id' => 'stringId'], $res->getData()[0]);
163 | }
164 |
165 | /**
166 | * @return void
167 | * @throws \Exception
168 | */
169 | public function testGetAllAndMin(): void
170 | {
171 | $this->insertDocumentWithNumber(1, 77);
172 | $this->insertDocumentWithNumber(2, 99);
173 |
174 | /** @var ResponseInterface $res */
175 | $res = $this->r()
176 | ->table('tabletest')
177 | ->getAll(1, 2)
178 | ->min('number')
179 | ->run();
180 |
181 | $this->assertArraySubset(['number' => 77], $res->getData());
182 | }
183 |
184 | /**
185 | * @return void
186 | * @throws \Exception
187 | */
188 | public function testGetAllAndMax(): void
189 | {
190 | $this->insertDocumentWithNumber(1, 77);
191 | $this->insertDocumentWithNumber(2, 99);
192 |
193 | /** @var ResponseInterface $res */
194 | $res = $this->r()
195 | ->table('tabletest')
196 | ->getAll(1, 2)
197 | ->max('number')
198 | ->run();
199 |
200 | $this->assertArraySubset(['number' => 99], $res->getData());
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/test/integration/Operation/GetTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
17 |
18 | /** @var ResponseInterface $res */
19 | $res = $this->r()
20 | ->table('tabletest')
21 | ->get(1)
22 | ->run();
23 |
24 | /** @var array $array */
25 | $array = $res->getData();
26 |
27 | $this->assertArraySubset(['id' => 1], $array);
28 | }
29 |
30 | /**
31 | * @return void
32 | * @throws \Exception
33 | */
34 | public function testGetNonExistingDocument(): void
35 | {
36 | /** @var ResponseInterface $res */
37 | $res = $this->r()
38 | ->table('tabletest')
39 | ->get('bar')
40 | ->run();
41 |
42 | $this->assertEquals(null, $res->getData());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/test/integration/Operation/IndexTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
16 |
17 | $res = $this->r()
18 | ->table('tabletest')
19 | ->indexCreate('title')
20 | ->run();
21 |
22 | $this->assertObStatus(['created' => 1], $res->getData());
23 | }
24 |
25 | /**
26 | * @throws \Exception
27 | */
28 | public function testIndexDrop()
29 | {
30 | $this->insertDocument(1);
31 |
32 | $this->r()
33 | ->table('tabletest')
34 | ->indexCreate('title')
35 | ->run();
36 |
37 | $res = $this->r()
38 | ->table('tabletest')
39 | ->indexDrop('title')
40 | ->run();
41 |
42 | $this->assertObStatus(['dropped' => 1], $res->getData());
43 | }
44 |
45 | /**
46 | * @throws \Exception
47 | */
48 | public function testIndexList()
49 | {
50 | $this->insertDocument(1);
51 |
52 | $this->r()
53 | ->table('tabletest')
54 | ->indexCreate('title')
55 | ->run();
56 |
57 | /** @var ResponseInterface $res */
58 | $res = $this->r()
59 | ->table('tabletest')
60 | ->indexList()
61 | ->run();
62 |
63 | $this->assertEquals('title', $res->getData()[0]);
64 | }
65 |
66 | /**
67 | * @throws \Exception
68 | */
69 | public function testIndexRename()
70 | {
71 | $this->insertDocument(1);
72 |
73 | $this->r()
74 | ->table('tabletest')
75 | ->indexCreate('title')
76 | ->run();
77 |
78 | $res = $this->r()
79 | ->table('tabletest')
80 | ->indexRename('title', 'description')
81 | ->run();
82 |
83 | $this->assertObStatus(['renamed' => 1], $res->getData());
84 |
85 | $res = $this->r()
86 | ->table('tabletest')
87 | ->indexList()
88 | ->run();
89 |
90 | $this->assertEquals('description', $res->getData()[0]);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/test/integration/Operation/InsertTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
19 |
20 | $this->assertObStatus(['inserted' => 1], $res->getData());
21 | }
22 |
23 | /**
24 | * @throws \Exception
25 | */
26 | public function testMultipleInserts()
27 | {
28 | $res = $this->r()
29 | ->table('tabletest')
30 | ->insert([
31 | [
32 | 'id' => 1,
33 | 'title' => 'Test document',
34 | 'description' => 'My first document.',
35 | ],
36 | [
37 | 'id' => 2,
38 | 'title' => 'Test document',
39 | 'description' => 'My first document.',
40 | ],
41 | [
42 | 'id' => 3,
43 | 'title' => 'Test document',
44 | 'description' => 'My first document.',
45 | ]
46 | ])
47 | ->run();
48 |
49 | $this->assertObStatus(['inserted' => 3], $res->getData());
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/test/integration/Operation/SyncTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
16 | $this->insertDocument(2);
17 | $this->insertDocument(3);
18 | $this->insertDocument(4);
19 | $this->insertDocument(5);
20 |
21 | /** @var ResponseInterface $result */
22 | $result = $this->r()
23 | ->table('tabletest')
24 | ->sync()
25 | ->run();
26 |
27 | $this->assertEquals(['synced' => true], $result->getData());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/integration/Operation/UpdateTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
16 |
17 | $this->r()
18 | ->table('tabletest')
19 | ->insert(['title' => 'Update document'])
20 | ->run();
21 |
22 | /** @var ResponseInterface $count */
23 | $count = $this->r()
24 | ->table('tabletest')
25 | ->filter(['title' => 'Update document'])
26 | ->count()
27 | ->run();
28 |
29 | /** @var ResponseInterface $res */
30 | $res = $this->r()
31 | ->table('tabletest')
32 | ->filter(['title' => 'Update document'])
33 | ->update(['title' => 'Updated document'])
34 | ->run();
35 |
36 | $this->assertObStatus(['replaced' => $count->getData()], $res->getData());
37 | }
38 |
39 | /**
40 | * @throws \Exception
41 | */
42 | public function testFilterUpdate()
43 | {
44 | $this->insertDocument(1);
45 | $this->insertDocument(2);
46 | $this->insertDocument(3);
47 | $this->insertDocument(4);
48 | $this->insertDocument(5);
49 |
50 | /** @var ResponseInterface $res */
51 | $res = $this->r()
52 | ->table('tabletest')
53 | ->filter(['id' => 5])
54 | ->update(['title' => 'Updated document'])
55 | ->run();
56 |
57 | $this->assertObStatus(['replaced' => 1], $res->getData());
58 | }
59 |
60 | /**
61 | * @throws \Exception
62 | */
63 | public function testFilterUpdateWithMultipleDocuments()
64 | {
65 | $this->insertDocument(1);
66 | $this->insertDocument(2);
67 | $this->insertDocument(3);
68 | $this->insertDocument(4);
69 | $this->insertDocument(5);
70 |
71 | /** @var ResponseInterface $res */
72 | $res = $this->r()
73 | ->table('tabletest')
74 | ->filter(['description' => 'A document description.'])
75 | ->update(['title' => 'Updated document'])
76 | ->run();
77 |
78 | $this->assertObStatus(['replaced' => 5], $res->getData());
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/test/integration/Transformation/IsEmptyTest.php:
--------------------------------------------------------------------------------
1 | r()
16 | ->table('tabletest')
17 | ->isEmpty()
18 | ->run();
19 |
20 | $this->assertTrue($res->getData());
21 | }
22 |
23 | /**
24 | * @throws \Exception
25 | */
26 | public function testIsNotEmpty()
27 | {
28 | $this->insertDocument(1);
29 |
30 | $res = $this->r()
31 | ->table('tabletest')
32 | ->isEmpty()
33 | ->run();
34 |
35 | $this->assertFalse($res->getData());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/test/integration/Transformation/LimitTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
19 | $this->insertDocument(2);
20 | $this->insertDocument(3);
21 | $this->insertDocument(4);
22 | $this->insertDocument(5);
23 |
24 | /** @var Cursor $cursor */
25 | $cursor = $this->r()
26 | ->table('tabletest')
27 | ->limit(2)
28 | ->run();
29 |
30 | $this->assertCount(2, $cursor);
31 | }
32 |
33 | public function testLimitWithMultipleTransformations(): void
34 | {
35 | $this->insertDocument(1);
36 | $this->insertDocument(2);
37 | $this->insertDocument(3);
38 | $this->insertDocument(4);
39 | $this->insertDocument(5);
40 |
41 | /** @var ResponseInterface $cursor */
42 | $response = $this->r()
43 | ->table('tabletest')
44 | ->filter(['description' => 'A document description.'])
45 | ->orderBy($this->r()->desc('id'))
46 | ->skip(1)
47 | ->limit(2)
48 | ->run();
49 |
50 | $this->assertCount(2, $response->getData());
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/integration/Transformation/OrderByTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(5);
18 | $this->insertDocument(4);
19 | $this->insertDocument(3);
20 | $this->insertDocument(2);
21 | $this->insertDocument(1);
22 |
23 | /** @var ResponseInterface $res */
24 | $res = $this->r()
25 | ->table('tabletest')
26 | ->orderBy($this->r()->desc('id'))
27 | ->run();
28 |
29 | $this->assertArraySubset(['id' => 5], $res->getData()[0]);
30 | }
31 |
32 | /**
33 | * @return void
34 | * @throws \Exception
35 | */
36 | public function testOrderByAsc(): void
37 | {
38 | $this->insertDocument(5);
39 | $this->insertDocument(4);
40 | $this->insertDocument(3);
41 | $this->insertDocument(2);
42 | $this->insertDocument(1);
43 |
44 | /** @var ResponseInterface $res */
45 | $res = $this->r()
46 | ->table('tabletest')
47 | ->orderBy($this->r()->asc('id'))
48 | ->run();
49 |
50 | $this->assertArraySubset(['id' => 1], $res->getData()[0]);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/integration/Transformation/SkipTest.php:
--------------------------------------------------------------------------------
1 | insertDocument(1);
19 | $this->insertDocument(2);
20 | $this->insertDocument(3);
21 | $this->insertDocument(4);
22 | $this->insertDocument(5);
23 |
24 | /** @var Cursor $cursor */
25 | $cursor = $this->r()
26 | ->table('tabletest')
27 | ->skip(2)
28 | ->run();
29 |
30 | $this->assertCount(3, $cursor);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test/unit/BaseUnitTestCase.php:
--------------------------------------------------------------------------------
1 | allowMockingNonExistentMethods(false);
19 |
20 | parent::setUp();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/test/unit/Connection/ConnectionCursorTest.php:
--------------------------------------------------------------------------------
1 | connect();
15 |
16 | $message = \Mockery::mock(MessageInterface::class);
17 | $message->shouldReceive('setOptions')->once();
18 |
19 | $response = \Mockery::mock(ResponseInterface::class);
20 | $response->shouldReceive('getType')->atLeast()->andReturn(ResponseType::SUCCESS_ATOM);
21 |
22 | $this->setExpectations($response);
23 |
24 | try {
25 | $this->connection->rewindFromCursor($message);
26 | } catch (\Exception $e) {
27 | $this->fail($e->getMessage());
28 | }
29 |
30 | $this->assertTrue(true);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test/unit/Connection/ConnectionQueryTest.php:
--------------------------------------------------------------------------------
1 | connect();
16 |
17 | $token = 1;
18 | $message = \Mockery::mock(MessageInterface::class);
19 | $message->shouldReceive('setOptions')->once();
20 |
21 | $this->stream->shouldReceive('write')->once()->andReturn(20);
22 |
23 | $this->querySerializer->shouldReceive('serialize')->atLeast()->andReturn("['serialized': true]");
24 |
25 | try {
26 | $this->connection->writeQuery($token, $message);
27 | } catch (\Exception $e) {
28 | $this->fail($e->getMessage());
29 | }
30 |
31 | $this->assertTrue(true);
32 | }
33 |
34 | public function testStopQuery()
35 | {
36 | $this->connect();
37 |
38 | $token = 1;
39 |
40 | $response = \Mockery::mock(ResponseInterface::class);
41 | $response->shouldReceive('getType')->atLeast()->andReturn(ResponseType::SUCCESS_ATOM);
42 |
43 | $buffer = new \stdClass();
44 | $this->catchStreamWrite($buffer);
45 | $this->catchStreamRead(4 + 8, $buffer);
46 | $this->catchStreamRead(20, $buffer);
47 |
48 | $this->querySerializer->shouldReceive('serialize')->once()->andReturn("['serialized': true]");
49 |
50 | $this->responseSerializer->shouldReceive('deserialize')->once()->andReturn($response);
51 |
52 | try {
53 | $this->connection->stopQuery($token);
54 | } catch (\Exception $e) {
55 | $this->fail($e->getMessage());
56 | }
57 |
58 | $this->assertTrue(true);
59 | }
60 |
61 | public function testContinueQuery()
62 | {
63 | $this->connect();
64 |
65 | $token = 1;
66 |
67 | $response = \Mockery::mock(ResponseInterface::class);
68 | $response->shouldReceive('getType')->atLeast()->andReturn(ResponseType::SUCCESS_ATOM);
69 |
70 | $buffer = new \stdClass();
71 | $this->catchStreamWrite($buffer);
72 | $this->catchStreamRead(4 + 8, $buffer);
73 | $this->catchStreamRead(20, $buffer);
74 |
75 | $this->querySerializer->shouldReceive('serialize')->once()->andReturn("['serialized': true]");
76 |
77 | $this->responseSerializer->shouldReceive('deserialize')->once()->andReturn($response);
78 |
79 | try {
80 | $this->connection->continueQuery($token);
81 | } catch (\Exception $e) {
82 | $this->fail($e->getMessage());
83 | }
84 |
85 | $this->assertTrue(true);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/test/unit/Connection/ConnectionTestCase.php:
--------------------------------------------------------------------------------
1 | stream = Mockery::mock(StreamInterface::class);
52 | $this->streamWrapper = function () {
53 | return $this->stream;
54 | };
55 |
56 | $this->handshake = Mockery::mock(HandshakeInterface::class);
57 | $this->querySerializer = Mockery::mock(SerializerInterface::class);
58 | $this->responseSerializer = Mockery::mock(SerializerInterface::class);
59 |
60 | $this->connection = new Connection(
61 | $this->streamWrapper,
62 | $this->handshake,
63 | 'test',
64 | $this->querySerializer,
65 | $this->responseSerializer
66 | );
67 | }
68 |
69 | /**
70 | * @return void
71 | */
72 | protected function connect(): void
73 | {
74 | try {
75 | $this->handshake->shouldReceive('hello')->once();
76 | /** @var ConnectionInterface $connection */
77 | $this->assertInstanceOf(ConnectionInterface::class, $this->connection->connect());
78 | } catch (\Exception $e) {
79 | $this->fail($e->getMessage());
80 | }
81 | }
82 |
83 | /**
84 | * @param MockInterface $response
85 | * @return void
86 | */
87 | protected function setExpectations($response = null): void
88 | {
89 | $this->querySerializer->shouldReceive('serialize')->atLeast()->andReturn("['serialized': true]");
90 |
91 | $buffer = new \stdClass();
92 | $this->catchStreamWrite($buffer);
93 |
94 | if ($response) {
95 | $this->catchStreamRead(4 + 8, $buffer);
96 | $this->catchStreamRead(20, $buffer);
97 |
98 | $this->responseSerializer->shouldReceive('deserialize')->atLeast()->andReturn($response);
99 | }
100 | }
101 |
102 | /**
103 | * @param \stdClass $buffer
104 | * @return \stdClass
105 | */
106 | protected function catchStreamWrite(\stdClass $buffer)
107 | {
108 | $this->stream->shouldReceive('write')->andReturnUsing(function ($string) use ($buffer) {
109 | $buffer->data = $string;
110 |
111 | return 20;
112 | });
113 |
114 | return $buffer;
115 | }
116 |
117 | protected function catchStreamRead(int $bytes, \stdClass $buffer): void
118 | {
119 | $this->stream->shouldReceive('read')->once()->with($bytes)->andReturnUsing(function ($bytes) use (&$buffer) {
120 | $data = '';
121 | if (isset($buffer->data)) {
122 | $data = substr($buffer->data, 0, $bytes);
123 | }
124 |
125 | return $data;
126 | });
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/test/unit/Connection/OptionsTest.php:
--------------------------------------------------------------------------------
1 | 'example.test',
19 | 'port' => 42,
20 | 'dbname' => 'test',
21 | 'user' => 'admin',
22 | 'password' => 'secret',
23 | 'timeout' => 120,
24 | 'timeout_stream' => 300,
25 | 'ssl' => true,
26 | ];
27 |
28 | $options = new Options($config);
29 |
30 | $this->assertEquals($config['hostname'], $options->getHostname());
31 | $this->assertEquals($config['port'], $options->getPort());
32 | $this->assertEquals($config['dbname'], $options->getDbName());
33 | $this->assertEquals($config['user'], $options->getUser());
34 | $this->assertEquals($config['password'], $options->getPassword());
35 | $this->assertEquals($config['timeout'], $options->getTimeout());
36 | $this->assertEquals($config['timeout_stream'], $options->getTimeoutStream());
37 | $this->assertEquals($config['ssl'], $options->isSsl());
38 | }
39 |
40 | /**
41 | * @return void
42 | * @throws \Exception
43 | */
44 | public function testIfHasDefaultDatabaseReturnsTrue(): void
45 | {
46 | $config = [
47 | 'dbname' => 'test',
48 | ];
49 |
50 | $options = new Options($config);
51 |
52 | $this->assertTrue($options->hasDefaultDatabase());
53 | }
54 |
55 | /**
56 | * @return void
57 | * @throws \Exception
58 | */
59 | public function testIfHasDefaultDatabaseReturnsFalse(): void
60 | {
61 | $config = [];
62 |
63 | $options = new Options($config);
64 |
65 | $this->assertFalse($options->hasDefaultDatabase());
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/test/unit/Connection/RegistryTest.php:
--------------------------------------------------------------------------------
1 | 'foo',
22 | ];
23 |
24 | $options = new Options($optionsConfig);
25 |
26 | $options2Config = [
27 | 'dbname' => 'bar',
28 | ];
29 |
30 | $options2 = new Options($options2Config);
31 |
32 | $registry = new Registry(
33 | [
34 | 'fooConnection' => $options,
35 | 'barConnection' => $options2,
36 | 'bazConnection' => [],
37 | ]
38 | );
39 |
40 | $this->assertTrue($registry->hasConnection('fooConnection'));
41 | $this->assertTrue($registry->hasConnection('barConnection'));
42 | $this->assertFalse($registry->hasConnection('bazConnection'));
43 |
44 | $this->assertInstanceOf(Connection::class, $registry->getConnection('fooConnection'));
45 | $this->assertInstanceOf(Connection::class, $registry->getConnection('barConnection'));
46 | }
47 |
48 | /**
49 | * @expectedException \TBolier\RethinkQL\Connection\ConnectionException
50 | * @expectedExceptionMessage The connection fooConnection has already been added
51 | * @expectedExceptionCode 400
52 | * @return void
53 | * @throws \TBolier\RethinkQL\Connection\ConnectionException
54 | */
55 | public function testIfExceptionThrownOnDuplicateConnection(): void
56 | {
57 | $optionsConfig = [
58 | 'dbname' => 'foo',
59 | ];
60 |
61 | $options = new Options($optionsConfig);
62 |
63 | $registry = new Registry(
64 | [
65 | 'fooConnection' => $options,
66 | ]
67 | );
68 |
69 | $registry->addConnection('fooConnection', $options);
70 | }
71 |
72 | /**
73 | * @expectedException \TBolier\RethinkQL\Connection\ConnectionException
74 | * @expectedExceptionMessage The connection fooConnection does not exist
75 | * @expectedExceptionCode 400
76 | * @return void
77 | * @throws \TBolier\RethinkQL\Connection\ConnectionException
78 | */
79 | public function testIfExceptionThrownOnMissingConnection(): void
80 | {
81 | $registry = new Registry([]);
82 |
83 | $registry->getConnection('fooConnection');
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/test/unit/Connection/Socket/HandshakeTest.php:
--------------------------------------------------------------------------------
1 | handshake = new Handshake('foo', 'bar', 42);
24 | }
25 |
26 | /**
27 | * @expectedException \TBolier\RethinkQL\Connection\Socket\Exception
28 | * @expectedExceptionMessage Not connected
29 | * @return void
30 | */
31 | public function testExceptionThrownOnStreamNotWritable(): void
32 | {
33 | $stream = \Mockery::mock(StreamInterface::class);
34 | $stream->shouldReceive('isWritable')->atLeast()->andReturn(false);
35 | $stream->shouldReceive('close');
36 |
37 | $this->handshake->hello($stream);
38 | }
39 |
40 | /**
41 | * @expectedException \TBolier\RethinkQL\Connection\Socket\Exception
42 | * @expectedExceptionMessage Foobar
43 | * @return void
44 | */
45 | public function testExceptionThrownOnError(): void
46 | {
47 | $stream = \Mockery::mock(StreamInterface::class);
48 | $stream->shouldReceive('isWritable')->atLeast()->andReturn(true);
49 | $stream->shouldReceive('close');
50 | $stream->shouldReceive('write');
51 | $stream->shouldReceive('getContents')->atLeast()->andReturn('ERROR: Foobar');
52 |
53 | $this->handshake->hello($stream);
54 | }
55 |
56 | /**
57 | * @expectedException \TBolier\RethinkQL\Connection\Socket\Exception
58 | * @expectedExceptionMessage Foobar
59 | * @return void
60 | */
61 | public function testExceptionThrownOnVerifyProtocolWithError(): void
62 | {
63 | $stream = \Mockery::mock(StreamInterface::class);
64 | $stream->shouldReceive('isWritable')->atLeast()->andReturn(true);
65 | $stream->shouldReceive('close');
66 | $stream->shouldReceive('write');
67 | $stream->shouldReceive('getContents')->atLeast()->andReturn('{"success":false, "error": "Foobar"}');
68 |
69 | $this->handshake->hello($stream);
70 | }
71 |
72 | /**
73 | * @expectedException \TBolier\RethinkQL\Connection\Socket\Exception
74 | * @expectedExceptionMessage Unsupported protocol version.
75 | * @return void
76 | */
77 | public function testExceptionThrownOnInvalidProtocolVersion(): void
78 | {
79 | $stream = \Mockery::mock(StreamInterface::class);
80 | $stream->shouldReceive('isWritable')->atLeast()->andReturn(true);
81 | $stream->shouldReceive('close');
82 | $stream->shouldReceive('write');
83 | $stream->shouldReceive('getContents')->atLeast()
84 | ->andReturn('{"success":true, "max_protocol_version": 1, "min_protocol_version": 1}');
85 |
86 | $this->handshake->hello($stream);
87 | }
88 |
89 |
90 | /**
91 | * @expectedException \TBolier\RethinkQL\Connection\Socket\Exception
92 | * @expectedExceptionMessage Woops!
93 | * @return void
94 | */
95 | public function testExceptionThrownOnProtocolError(): void
96 | {
97 | /** @var MockInterface $stream */
98 | $stream = \Mockery::mock(StreamInterface::class);
99 | $stream->shouldReceive('isWritable')->atLeast()->andReturn(true);
100 | $stream->shouldReceive('close');
101 | $stream->shouldReceive('write');
102 | $stream->shouldReceive('getContents')->atLeast()->andReturn('ERROR: Woops!');
103 |
104 | $this->handshake->hello($stream);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/test/unit/Query/MessageTest.php:
--------------------------------------------------------------------------------
1 | setCommand($queryType);
24 | $message->setQuery($query);
25 | $message->setOptions($options);
26 |
27 | $this->assertEquals(1, $message->getQueryType());
28 | $this->assertEquals([
29 | 1,
30 | ['yo'],
31 | new Options(),
32 | ], $message->toArray());
33 | $this->assertEquals($options, $message->getOptions());
34 | }
35 |
36 | /**
37 | * @return void
38 | * @throws \Exception
39 | */
40 | public function testToArray(): void
41 | {
42 | $queryType = 1;
43 | $query = [];
44 | $options = new Options();
45 |
46 | $message = new Message($queryType, $query, $options);
47 |
48 | $expectedResults = [
49 | 1,
50 | $query,
51 | (object) $options,
52 | ];
53 |
54 | $this->assertEquals($expectedResults, $message->toArray());
55 | }
56 |
57 | /**
58 | * @return void
59 | * @throws \Exception
60 | */
61 | public function testJsonSerialize(): void
62 | {
63 | $queryType = 1;
64 | $query = [];
65 | $options = new Options();
66 |
67 | $message = new Message($queryType, $query, $options);
68 |
69 | $expectedResults = [
70 | 1,
71 | $query,
72 | (object) $options,
73 | ];
74 |
75 | $this->assertEquals($expectedResults, $message->jsonSerialize());
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/test/unit/Response/ResponseTest.php:
--------------------------------------------------------------------------------
1 | 'bar'];
19 | $backtrace = [0 => [1 => []]];
20 | $profile = [2 => [3 => []]];
21 | $note = [4 => [5 => []]];
22 |
23 | $response = new Response(
24 | $type,
25 | $data,
26 | $backtrace,
27 | $profile,
28 | $note
29 | );
30 |
31 | $this->assertEquals($type, $response->getType());
32 | $this->assertEquals($data, $response->getData());
33 | $this->assertEquals($backtrace, $response->getBacktrace());
34 | $this->assertEquals($profile, $response->getProfile());
35 | $this->assertEquals($note, $response->getNote());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/test/unit/Serializer/QueryNormalizerTest.php:
--------------------------------------------------------------------------------
1 | normalizer = new QueryNormalizer();
25 |
26 | $serializer = new Serializer([$this->normalizer]);
27 |
28 | $this->normalizer->setSerializer($serializer);
29 | }
30 |
31 | /**
32 | * @return void
33 | * @throws \Exception
34 | */
35 | public function testNormalizeWithStdClass(): void
36 | {
37 | $object = new \stdClass();
38 | $object->foo = 'bar';
39 |
40 | $data = $this->normalizer->normalize($object);
41 |
42 | $this->assertEquals(['foo' => 'bar'], $data);
43 | }
44 |
45 | /**
46 | * @return void
47 | * @throws \Exception
48 | */
49 | public function testNormalizeWithOptions(): void
50 | {
51 | $object = new Options();
52 | $object->setDb('foobar');
53 |
54 | $expectedObject = new \stdClass();
55 | $expectedObject->db = [0 => 14, 1 => ['foobar']];
56 |
57 | $data = $this->normalizer->normalize($object);
58 |
59 | $this->assertEquals($expectedObject, $data);
60 | }
61 |
62 | /**
63 | * @expectedException \Symfony\Component\Serializer\Exception\CircularReferenceException
64 | * @expectedExceptionMessage A circular reference has been detected when serializing the object of class "stdClass"
65 | * (configured limit: 1)
66 | * @return void
67 | */
68 | public function testNormalizeWithCircularReference(): void
69 | {
70 | $object = new \stdClass();
71 | $object->foo = 'bar';
72 |
73 | $context = [
74 | 'circular_reference_limit' => [
75 | spl_object_hash($object) => 1,
76 | ],
77 | ];
78 |
79 | $this->normalizer->normalize($object, null, $context);
80 | }
81 |
82 | /**
83 | * @return void
84 | * @throws \Exception
85 | */
86 | public function testNormalizeWithJsonSerializable(): void
87 | {
88 | $expectedReturn = ['foo' => 'bar'];
89 |
90 | $object = Mockery::mock('\JsonSerializable');
91 | $object->shouldReceive('jsonSerialize')->once()->andReturn($expectedReturn);
92 |
93 |
94 | $data = $this->normalizer->normalize($object);
95 |
96 | $this->assertEquals($expectedReturn, $data);
97 | }
98 |
99 | /**
100 | * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
101 | * @expectedExceptionMessage The ArrayObject must implement "JsonSerializable"
102 | * @return void
103 | */
104 | public function testInvalidArgumentExceptionThrownOnInvalidClass(): void
105 | {
106 | $object = new \ArrayObject();
107 |
108 | $this->normalizer->normalize($object);
109 | }
110 |
111 | /**
112 | * @expectedException \Symfony\Component\Serializer\Exception\LogicException
113 | * @expectedExceptionMessage Cannot normalize object because injected serializer is not a normalizer
114 | * @return void
115 | */
116 | public function testLogicExceptionThrownOnInvalidNormalizer(): void
117 | {
118 | $object = new \stdClass();
119 | $object->foo = 'bar';
120 |
121 | $serializerMock = Mockery::mock('\Symfony\Component\Serializer\SerializerInterface');
122 | $this->normalizer->setSerializer($serializerMock);
123 |
124 | $this->normalizer->normalize($object);
125 | }
126 |
127 | /**
128 | * @return void
129 | * @throws \Exception
130 | */
131 | public function testSupportsDenormalizationReturnsFalse(): void
132 | {
133 | $this->assertFalse($this->normalizer->supportsDenormalization('foo', 'foo', 'foo'));
134 | }
135 |
136 | /**
137 | * @expectedException \Symfony\Component\Serializer\Exception\LogicException
138 | * @expectedExceptionMessage Cannot denormalize with "TBolier\RethinkQL\Serializer\QueryNormalizer".
139 | * @return void
140 | */
141 | public function testIfDenormalizeThrowsLogicException(): void
142 | {
143 | $this->normalizer->denormalize('foo', 'bar');
144 | }
145 | }
146 |
--------------------------------------------------------------------------------