├── .github └── workflows │ └── tests.yml ├── .gitignore ├── .scrutinizer.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── src ├── DbContext.php ├── Descriptor.php ├── Driver.php ├── DriverFactory.php ├── NullConnection.php ├── descriptors │ ├── InformationSchemaDescriptor.php │ ├── MysqlDescriptor.php │ ├── PostgresqlDescriptor.php │ └── SqliteDescriptor.php ├── drivers │ ├── MysqlDriver.php │ ├── PostgresqlDriver.php │ └── SqliteDriver.php └── exceptions │ ├── ConnectionException.php │ ├── DatabaseDriverException.php │ └── TableNotFoundException.php └── tests ├── cases └── DriverTest.php ├── config ├── github.xml └── sample.xml ├── databases ├── mysql.sql ├── postgresql.sql └── sqlite.sql ├── expected ├── mysql │ ├── database_description.php │ ├── database_description_clean_defaults.php │ ├── strings.json │ └── view_description.php ├── postgresql │ ├── database_description.php │ ├── database_description_clean_defaults.php │ ├── employees_description.php │ ├── strings.json │ └── view_description.php ├── sqlite │ ├── database_description.php │ ├── database_description_clean_defaults.php │ ├── strings.json │ └── view_description.php └── xml │ └── transactions.xml └── lib └── DriverLoader.php /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [push] 3 | jobs: 4 | Integration: 5 | runs-on: ubuntu-latest 6 | services: 7 | server: 8 | image: ${{ matrix.db.services.image }} 9 | env: ${{ matrix.db.services.env }} 10 | ports: 11 | - ${{ matrix.db.services.ports }} 12 | strategy: 13 | matrix: 14 | db: 15 | - env: 16 | ATIAA_DRIVER: sqlite 17 | ATIAA_FILE: sqlite.db 18 | ATIAA_PDO_DSN: sqlite:sqlite.db 19 | ATIAA_SKIP_DB: yes 20 | initialize: sqlite3 sqlite.db < tests/databases/sqlite.sql 21 | services: 22 | image: 'hello-world' 23 | env: 24 | GREET: Hello 25 | ports: '80:80' 26 | 27 | - env: 28 | ATIAA_DRIVER: mysql 29 | ATIAA_HOST: 127.0.0.1 30 | ATIAA_USER: root 31 | ATIAA_DBNAME: atiaa_test 32 | ATIAA_PDO_DSN: mysql:host=127.0.0.1;dbname=atiaa_test;user=root 33 | initialize: | 34 | sleep 10 35 | echo "create database atiaa_test;" | mysql -h 127.0.0.1 --user root 36 | mysql -h 127.0.0.1 --user root atiaa_test < tests/databases/mysql.sql 37 | services: 38 | image: mysql:latest 39 | env: 40 | MYSQL_ALLOW_EMPTY_PASSWORD: yes 41 | ports: '3306:3306' 42 | 43 | - env: 44 | ATIAA_DRIVER: postgresql 45 | ATIAA_HOST: 127.0.0.1 46 | ATIAA_USER: postgres 47 | ATIAA_DBNAME: atiaa_test 48 | ATIAA_PDO_DSN: pgsql:host=127.0.0.1;dbname=atiaa_test;user=postgres 49 | initialize: | 50 | sleep 10 51 | psql -c 'create database atiaa_test;' --host 127.0.0.1 --user postgres 52 | psql -f tests/databases/postgresql.sql -U postgres -d atiaa_test --host 127.0.0.1 53 | services: 54 | image: postgres:latest 55 | env: 56 | POSTGRES_HOST_AUTH_METHOD: trust 57 | ports: '5432:5432' 58 | steps: 59 | - name: Check out repository code 60 | uses: actions/checkout@v2 61 | with: 62 | fetch-depth: 2 63 | - name: Install PHP 64 | uses: shivammathur/setup-php@v2 65 | with: 66 | tools: composer 67 | - name: Running composer 68 | run: composer install 69 | - name: Initializing the database 70 | run: ${{ matrix.db.initialize }} 71 | - name: Running php unit tests 72 | env: ${{ matrix.db.env }} 73 | run: vendor/bin/phpunit --coverage-clover coverage.clover -c tests/config/github.xml 74 | - name: Downloading Ocular Tool 75 | run: composer global require scrutinizer/ocular dev-master 76 | - name: Uploading Code Metrics 77 | run: php ~/.composer/vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject 2 | vendor 3 | tests/config/*.xml 4 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | tools: 2 | php_sim: true 3 | php_pdepend: true 4 | php_analyzer: true 5 | external_code_coverage: 6 | timeout: 1200 # Timeout in seconds. 7 | runs: 3 8 | filter: 9 | excluded_paths: [bin/*, tests/*] 10 | 11 | checks: 12 | php: 13 | unused_variables: true 14 | unused_properties: true 15 | unused_parameters: true 16 | unused_methods: true 17 | unreachable_code: true 18 | too_many_arguments: true 19 | sql_injection_vulnerabilities: true 20 | side_effects_or_types: true 21 | useless_calls: true 22 | return_doc_comments: true 23 | return_doc_comment_if_not_inferrable: true 24 | require_php_tag_first: true 25 | avoid_corrupting_byteorder_marks: true 26 | avoid_tab_indentation: true 27 | avoid_unnecessary_concatenation: true 28 | avoid_useless_overridden_methods: true 29 | code_rating: true 30 | deadlock_detection_in_loops: true 31 | duplication: true 32 | fix_doc_comments: true 33 | fix_identation_4spaces: true 34 | fix_line_ending: true 35 | fix_use_statements: 36 | remove_unused: true 37 | preserve_multiple: false 38 | preserve_blanklines: false 39 | order_alphabetically: true 40 | newline_at_end_of_file: true 41 | no_debug_code: true 42 | no_unnecessary_function_call_in_for_loop: true 43 | prefer_unix_line_ending: true 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | v0.9.0 - 2025-04-05 2 | =================== 3 | - Added a new way to access the driver for transaction management through the database context. 4 | - Cleaned up the documentation and type hints. 5 | 6 | v0.8.0 - 2025-01-20 7 | =================== 8 | Added 9 | ----- 10 | - Can now pass PDO attributes to the connection. 11 | - Some type hints to bring the library in line with modern PHP features. 12 | - Migrated tests from TravisCI to Github workflow. 13 | 14 | v0.7.2 - 2018-12-02 15 | =================== 16 | - First release to have a CHANGELOG 17 | 18 | Removed 19 | ------- 20 | - Boolean type is not defined in a standard way across database drivers, and it is being temporarily disabled. 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 James Ekow Abaka Ainooson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Atiaa PDO Wrapper 2 | ================= 3 | 4 | [![Build Status](https://github.com/ntentan/atiaa/actions/workflows/tests.yml/badge.svg)](https://github.com/ntentan/atiaa/actions/workflows/tests.yml) 5 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ntentan/atiaa/badges/quality-score.png?b=main)](https://scrutinizer-ci.com/g/ntentan/atiaa/?branch=main) 6 | [![Code Coverage](https://scrutinizer-ci.com/g/ntentan/atiaa/badges/coverage.png?b=main)](https://scrutinizer-ci.com/g/ntentan/atiaa/?branch=main) 7 | [![Latest Stable Version](https://poser.pugx.org/ntentan/atiaa/version.svg)](https://packagist.org/packages/ntentan/atiaa) 8 | [![Total Downloads](https://poser.pugx.org/ntentan/atiaa/downloads.svg)](https://packagist.org/packages/ntentan/atiaa) 9 | 10 | Atiaa is a thin wrapper around PHP's PDO database abstraction layer. The main 11 | purpose of atiaa is to provide utility classes that other packages in the 12 | ntentan framework need (which are not available in PDO). 13 | 14 | Currently atiaa provides the following features: 15 | - Wrappers arround the PDO query method which prepare the query and execute in 16 | one stretch. These methods then return all the results as a simple 17 | PHP associative array. 18 | - Methods which describe the schema of the database represented by the connection. 19 | - A platform independent approach for quoting database literals in queries. 20 | 21 | Currently atiaa works only with MySQL, PostgreSQL and SQLite databases. 22 | Support for other platforms is planned for later releases. 23 | 24 | Installation 25 | ------------ 26 | The best way to install atiaa is to use composer. To install atiaa add 27 | `ntentan/atiaa` to your composer dependencies. 28 | 29 | Example 30 | ------- 31 | The following example tries to summarise the entirety of atiaa. 32 | 33 | ````php 34 | 'mysql', 40 | 'user' => 'root', 41 | 'password' => 'rootpassy', 42 | 'host' => 'localhost', 43 | 'dbname' => 'somedb' 44 | ) 45 | ); 46 | $atiaa = $factory->createDriver(); 47 | 48 | // Perform some queries 49 | $data = $atiaa->query('SELECT * FROM some_table'); 50 | $data2 = $atiaa->query( 51 | 'SELECT * FROM some_other_table WHERE id = ? and an_item = ?', 52 | array(2, 'something') 53 | ); 54 | 55 | // Get the description of the database 56 | $description = $atiaa->describe(); 57 | var_dump($description); 58 | 59 | // Perform a query while quoting the literals. 60 | $data3 = $atiaa->quoteQuery('SELECT "First Name" from "Users Table" '); 61 | ```` 62 | 63 | License 64 | ------- 65 | Copyright (c) 2014 James Ekow Abaka Ainooson 66 | 67 | Permission is hereby granted, free of charge, to any person obtaining 68 | a copy of this software and associated documentation files (the 69 | "Software"), to deal in the Software without restriction, including 70 | without limitation the rights to use, copy, modify, merge, publish, 71 | distribute, sublicense, and/or sell copies of the Software, and to 72 | permit persons to whom the Software is furnished to do so, subject to 73 | the following conditions: 74 | 75 | The above copyright notice and this permission notice shall be 76 | included in all copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 79 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 80 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 81 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 82 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 83 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 84 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 85 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ntentan/atiaa", 3 | "description": "A slim wrapper around PDO to provide some extra utilities", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "James Ekow Abaka Ainooson", 8 | "email": "jainooson@gmail.com" 9 | } 10 | ], 11 | "require": { 12 | "ntentan/utils": "0.*", 13 | "ext-pdo": "*" 14 | }, 15 | "require-dev" : { 16 | "phpunit/phpunit" : "11.*", 17 | "ext-json": "*" 18 | }, 19 | "autoload" : { 20 | "psr-4" : { 21 | "ntentan\\atiaa\\" : "src/", 22 | "ntentan\\atiaa\\tests\\" : "tests/" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DbContext.php: -------------------------------------------------------------------------------- 1 | driver = $driver; 50 | self::$instance = $this; 51 | } 52 | 53 | /** 54 | * Create a new database context. 55 | */ 56 | public static function initialize(DriverFactory $driverFactory): DbContext 57 | { 58 | self::$instance = new self($driverFactory->createDriver()); 59 | return self::$instance; 60 | } 61 | 62 | /** 63 | * Get the current singleton instance of the context. 64 | * 65 | * @throws \Exception 66 | */ 67 | public static function getInstance(): self 68 | { 69 | if (!self::$instance) { 70 | throw new \Exception('The database context has not been initialized'); 71 | } 72 | 73 | return self::$instance; 74 | } 75 | 76 | /** 77 | * Get the Driver instance wrapped in the context. 78 | * @throws exceptions\ConnectionException 79 | */ 80 | public function getDriver(): Driver 81 | { 82 | return $this->driver; 83 | } 84 | 85 | /** 86 | * Run a query on the database driver. 87 | * 88 | * @throws exceptions\ConnectionException 89 | * @throws exceptions\DatabaseDriverException 90 | */ 91 | public function query(string $query, array $bindData = []): array 92 | { 93 | return $this->driver->query($query, $bindData); 94 | } 95 | 96 | /** 97 | * Destroy the context. 98 | * 99 | * @throws exceptions\ConnectionException 100 | */ 101 | public static function destroy(): void 102 | { 103 | self::$instance->driver->connect(); 104 | self::$instance->driver->disconnect(); 105 | } 106 | 107 | public static function beginTransaction(): void 108 | { 109 | self::$instance->driver->connect(); 110 | self::$instance->driver->beginTransaction(); 111 | } 112 | 113 | public static function commitTransaction(): void 114 | { 115 | self::$instance->driver->connect(); 116 | self::$instance->driver->commit(); 117 | } 118 | 119 | public static function rollbackTransaction(): void 120 | { 121 | self::$instance->driver->connect(); 122 | self::$instance->driver->rollback(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/Descriptor.php: -------------------------------------------------------------------------------- 1 | driver = $driver; 25 | } 26 | 27 | /** 28 | * Returns a list of schemata available on the database. 29 | * 30 | * @return array 31 | */ 32 | abstract protected function getSchemata(); 33 | 34 | /** 35 | * Retrieve the names of all the tables in a given schema. 36 | * The array returned must be a list of structured arrays which have `name` 37 | * and `schema` as keys. The `name` key should represent the name of the table and 38 | * the `schema` key should represent the name of the schema (which is the same 39 | * as the schema which was passed to the function). 40 | * 41 | * @param string $schema The name of the schema whose tables should be 42 | * describled. 43 | * @param array An array contianing names of specific tables 44 | * who's descriptions should be retrieved. 45 | * 46 | * @return array 47 | */ 48 | abstract protected function getTables($schema, $requestedTables, $includeViews); 49 | 50 | /** 51 | * Retrieve descriptions of all the columns available in a given table as an array. 52 | * The array returned must contain structured arrays with the following keys. 53 | * 54 | * name 55 | * : The name of the column. 56 | * 57 | * type 58 | * : The system specific datatype of the column. 59 | * 60 | * nulls 61 | * : A boolean which is true for columsn which can contain null values 62 | * and false for columns which can't. 63 | * 64 | * default 65 | * : The default value of the column. In cases where there is no default 66 | * this column is set to null. 67 | * 68 | * length 69 | * : The maximum character lenght of the column. 70 | * 71 | * @param array $table An array which contains the name of the table as it's 72 | * `name` key and the schema of the table as it's `schema` key. 73 | * 74 | * @return array> 75 | */ 76 | abstract protected function getColumns(&$table); 77 | 78 | /** 79 | * Retrieve the descriptions of all the views of a given schema in a array. 80 | * The array returned must contain structured arrays with the following keys. 81 | * 82 | * name 83 | * : The name of the view. 84 | * 85 | * schema 86 | * : The schema to which the view belongs. 87 | * 88 | * definition 89 | * : The SQL query which represents the definition of the view. 90 | * 91 | * @param string $schema The name of the database schema 92 | * 93 | * @return array> 94 | */ 95 | abstract protected function getViews(&$schema); 96 | 97 | /** 98 | * Retrieve the description of a primary key on a given table. 99 | * The description returned must be an array which contains structured 100 | * arrays with the following keys. 101 | * 102 | * column 103 | * : The name of a column which is part of the primary key 104 | * 105 | * name 106 | * : The name of the primary key constraint (must be the same throughout 107 | * all the items returned). 108 | * 109 | * For primary keys with multiple columns, the array returned would contain 110 | * one entry for each column. 111 | * 112 | * @param array $table An array which contains the name of the table as it's 113 | * `name` key and the schema of the table as it's `schema` key. 114 | * 115 | * @return array> 116 | */ 117 | abstract protected function getPrimaryKey(&$table); 118 | 119 | /** 120 | * Retrieve the description of unique keys on a given table. 121 | * The description returned must be an array which contains structured 122 | * arrays with the following keys. 123 | * 124 | * column 125 | * : The name of a column which is part of a unique key 126 | * 127 | * name 128 | * : The name of the unique key constraint. 129 | * 130 | * For unique keys with multiple columns, the value of the `name` key must 131 | * be the same for only the columns in the key. 132 | * 133 | * @param array $table An array which contains the name of the table as it's 134 | * `name` key and the schema of the table as it's `schema` key. 135 | * 136 | * @return array> 137 | */ 138 | abstract protected function getUniqueKeys(&$table); 139 | 140 | /** 141 | * Retrieve the description of foreign keys on a given table. 142 | * The description returned must be an array which contains structured 143 | * arrays with the following keys. 144 | * 145 | * name 146 | * : The name of the foreign key constraint. 147 | * 148 | * table 149 | * : The name of the database table (should be same as passed to the function) 150 | * 151 | * schema 152 | * : The schema of the database table (should be same as passed to the 153 | * function) 154 | * 155 | * column 156 | * : The foreign key column on the table. 157 | * 158 | * foreign_table 159 | * : The name of the database table to be referenced. 160 | * 161 | * foreign_schema 162 | * : The schema which contains the database table to be referenced. 163 | * 164 | * foreign_column: 165 | * : The column to be refereced on the foreign table. 166 | * 167 | * For foreign keys with multiple columns, the value of the `name` key must 168 | * be the same for only the columns in the key. 169 | * 170 | * @param array $table An array which contains the name of the table as it's 171 | * `name` key and the schema of the table as it's `schema` key. 172 | * 173 | * @return array> 174 | */ 175 | abstract protected function getForeignKeys(&$table); 176 | 177 | /** 178 | * Retrieve the description of indices on a given table. 179 | * The description returned must be an array which contains structured 180 | * arrays with the following keys. 181 | * 182 | * column 183 | * : The name of a column which is part of an index 184 | * 185 | * name 186 | * : The name of the index. 187 | * 188 | * For unique keys with multiple columns, the value of the `name` key must 189 | * be the same for only the columns in the key. 190 | * 191 | * @param array $table An array which contains the name of the table as it's 192 | * `name` key and the schema of the table as it's `schema` key. 193 | * 194 | * @return array> 195 | */ 196 | abstract protected function getIndices(&$table); 197 | 198 | /** 199 | * Returns a boolean value which tells whether a table has an auto incrementing 200 | * key or not. 201 | * 202 | * @return bool 203 | */ 204 | abstract protected function hasAutoIncrementingKey(&$table); 205 | 206 | /** 207 | * Returns the description of the database as an array. 208 | * 209 | * @return array 210 | */ 211 | public function describe() 212 | { 213 | $defaultSchema = $this->driver->getDefaultSchema(); 214 | $description = [ 215 | 'schemata' => [], 216 | ]; 217 | 218 | $schemata = $this->getSchemata(); 219 | 220 | foreach ($schemata as $schema) { 221 | $description['schemata'][$schema['name']]['name'] = $schema['name']; 222 | $description['schemata'][$schema['name']]['tables'] = $this->describeTables($schema['name']); 223 | $description['schemata'][$schema['name']]['views'] = $this->describeViews($schema['name']); 224 | 225 | if ($schema['name'] == $defaultSchema) { 226 | $description['tables'] = $description['schemata'][$schema['name']]['tables']; //$this->describeTables($defaultSchema); 227 | $description['views'] = $description['schemata'][$schema['name']]['views']; //$this->describeViews($defaultSchema); 228 | } 229 | } 230 | 231 | return $description; 232 | } 233 | 234 | public function setCleanDefaults($cleanDefaults) 235 | { 236 | $this->cleanDefaults = $cleanDefaults; 237 | } 238 | 239 | /** 240 | * Throws exceptions for which are found in the list of requested tables 241 | * but not found in the list of found tables. 242 | * 243 | * @param array $tables 244 | * @param array $requestedTables 245 | * 246 | * @throws exceptions\TableNotFoundException 247 | */ 248 | private function throwTableExceptions($tables, $requestedTables) 249 | { 250 | $foundTables = []; 251 | foreach ($tables as $table) { 252 | $foundTables[] = $table['name']; 253 | } 254 | 255 | foreach ($requestedTables as $requestedTable) { 256 | if (array_search($requestedTable, $foundTables) === false) { 257 | throw new exceptions\TableNotFoundException( 258 | $requestedTable 259 | ? "$requestedTable not found on target database." 260 | : 'Please specify a table name.' 261 | ); 262 | } 263 | } 264 | } 265 | 266 | public function describeTables($schema, $requestedTables = [], $includeViews = false) 267 | { 268 | $description = []; 269 | $tables = $this->getTables($schema, $requestedTables, $includeViews); 270 | 271 | if (count($requestedTables) > 0 && count($tables) < count($requestedTables)) { 272 | $this->throwTableExceptions($tables, $requestedTables); 273 | } 274 | 275 | foreach ($tables as $table) { 276 | $table['columns'] = $this->describeColumns($table); 277 | $table['primary_key'] = $this->describePrimaryKey($table); 278 | $table['unique_keys'] = $this->describeUniqueKeys($table); 279 | $table['foreign_keys'] = $this->describeForeignKeys($table); 280 | $table['indices'] = $this->describeIndices($table); 281 | $table['auto_increment'] = $this->hasAutoIncrementingKey($table); 282 | $table['schema'] = $this->fixSchema($table['schema']); 283 | 284 | $description[$table['name']] = $table; 285 | } 286 | 287 | return $description; 288 | } 289 | 290 | private function describeColumns($table) 291 | { 292 | $columns = []; 293 | $columnDetails = $this->getColumns($table); 294 | foreach ($columnDetails as $column) { 295 | $columns[$column['name']] = $column; 296 | $columns[$column['name']]['nulls'] = $columns[$column['name']]['nulls'] == 'YES' ? true : false; 297 | 298 | if ($this->cleanDefaults) { 299 | $columns[$column['name']]['default'] = $this->cleanDefaultValue($column['default']); 300 | } 301 | } 302 | 303 | return $columns; 304 | } 305 | 306 | private function describeViews($schema) 307 | { 308 | $description = []; 309 | $views = $this->getViews($schema); 310 | foreach ($views as $view) { 311 | $description[$view['name']] = [ 312 | 'name' => $view['name'], 313 | 'schema' => $view['schema'], 314 | 'definition' => $view['definition'], 315 | ]; 316 | } 317 | 318 | return $description; 319 | } 320 | 321 | private function describePrimaryKey($table) 322 | { 323 | return $this->describeKey($this->getPrimaryKey($table)); 324 | } 325 | 326 | private function describeUniqueKeys($table) 327 | { 328 | return $this->describeKey($this->getUniqueKeys($table)); 329 | } 330 | 331 | private function describeForeignKeys($table) 332 | { 333 | return $this->describeKey($this->getForeignKeys($table)); 334 | } 335 | 336 | private function describeIndices($table) 337 | { 338 | return $this->describeKey($this->getIndices($table)); 339 | } 340 | 341 | private function describeKey($constraintColumns) 342 | { 343 | $constraints = []; 344 | foreach ($constraintColumns as $column) { 345 | $name = $column['name']; 346 | unset($column['name']); 347 | foreach ($column as $key => $value) { 348 | if ($key == 'column' || $key == 'foreign_column') { 349 | $constraints[$name]["{$key}s"][] = $value; 350 | } else { 351 | if ($key === 'schema' || $key === 'foreign_schema') { 352 | $value = $this->fixSchema($value); 353 | } 354 | $constraints[$name][$key] = $value; 355 | } 356 | } 357 | } 358 | 359 | return $constraints; 360 | } 361 | 362 | private function fixSchema($schema) 363 | { 364 | $defaultSchema = $this->driver->getDefaultSchema(); 365 | if ($schema == false || $schema == $defaultSchema) { 366 | return ''; 367 | } else { 368 | return $schema; 369 | } 370 | } 371 | 372 | protected function cleanDefaultValue($defaultValue) 373 | { 374 | return $defaultValue; 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /src/Driver.php: -------------------------------------------------------------------------------- 1 | 'mysql', 56 | * 'user' => 'root', 57 | * 'password' => 'rootpassy', 58 | * 'host' => 'localhost', 59 | * 'dbname' => 'somedb' 60 | * ) 61 | * ); 62 | * 63 | * var_dump($driver->query("SELECT * FROM some_table"); 64 | * var_dump($driver->describe()); 65 | * ```` 66 | */ 67 | public function __construct(array $config) 68 | { 69 | $this->config = $config; 70 | $this->defaultSchema = $this->config['schema'] ?? $this->defaultSchema ?? null; 71 | } 72 | 73 | public function connect(): void 74 | { 75 | if ($this->connected) { 76 | return; 77 | } 78 | $username = $this->config['user'] ?? null; 79 | $password = $this->config['password'] ?? null; 80 | 81 | unset($this->config['schema']); 82 | 83 | try { 84 | $options = $this->config['options'] ?? []; 85 | 86 | $options[PDO::ATTR_ERRMODE] = $options[PDO::ATTR_ERRMODE] ?? PDO::ERRMODE_EXCEPTION; 87 | $options[PDO::ATTR_EMULATE_PREPARES] = $options[PDO::ATTR_EMULATE_PREPARES] ?? false; 88 | $options[PDO::ATTR_STRINGIFY_FETCHES] = $options[PDO::ATTR_STRINGIFY_FETCHES] ?? false; 89 | 90 | $this->pdo = new \PDO( 91 | $this->getDriverName().':'.$this->expand($this->config), $username, $password, $options 92 | ); 93 | $this->connected = true; 94 | } catch (\PDOException $e) { 95 | throw new ConnectionException("PDO failed to connect: {$e->getMessage()}"); 96 | } 97 | } 98 | 99 | public function __destruct() 100 | { 101 | $this->disconnect(); 102 | } 103 | 104 | /** 105 | * Close a connection to the database server. 106 | */ 107 | public function disconnect(): void 108 | { 109 | $this->pdo = new NullConnection(); 110 | $this->connected = false; 111 | } 112 | 113 | /** 114 | * Get the default schema of the current connection. 115 | * 116 | * @return string 117 | */ 118 | public function getDefaultSchema(): string 119 | { 120 | return $this->defaultSchema; 121 | } 122 | 123 | /** 124 | * Use the PDO driver to quote a string. 125 | * 126 | * @throws ConnectionException 127 | */ 128 | public function quote(string $string): string 129 | { 130 | return $this->getPDO()->quote($string); 131 | } 132 | 133 | 134 | private function fetchRows(\PDOStatement $statement): array 135 | { 136 | try { 137 | $rows = $statement->fetchAll(\PDO::FETCH_ASSOC); 138 | return $rows; 139 | } catch (\PDOException $e) { 140 | return []; 141 | } 142 | } 143 | 144 | private function prepareQuery($query, $bindData): \PDOStatement 145 | { 146 | $statement = $this->pdo->prepare($query); 147 | foreach ($bindData as $key => $value) { 148 | switch (gettype($value)) { 149 | case 'integer': 150 | case 'boolean': // casts to boolean seems unstable 151 | $type = \PDO::PARAM_INT; 152 | break; 153 | default: 154 | $type = \PDO::PARAM_STR; 155 | break; 156 | } 157 | // Bind values while adjusting numerical indices to start from 1 158 | $statement->bindValue(is_numeric($key) ? $key + 1 : $key, $value, $type); 159 | } 160 | 161 | return $statement; 162 | } 163 | 164 | /** 165 | * Pepare and execute a query, while binding data at the same time. Prevents the writing of repetitive prepare and 166 | * execute statements. This method returns an array which contains the results of the query that was executed. For 167 | * queries which do not return any results a null is returned. 168 | * 169 | * @throws DatabaseDriverException 170 | */ 171 | public function query(string $query, array $bindData = []): array 172 | { 173 | $this->connect(); 174 | try { 175 | if (empty($bindData)) { 176 | $statement = $this->pdo->query($query); 177 | } else { 178 | $statement = $this->prepareQuery($query, $bindData); 179 | $statement->execute(); 180 | $statement->errorCode(); 181 | } 182 | } catch (\PDOException $e) { 183 | $boundData = json_encode($bindData); 184 | 185 | throw new DatabaseDriverException("{$e->getMessage()} [$query] [BOUND DATA:$boundData]"); 186 | } 187 | $rows = $this->fetchRows($statement); 188 | $statement->closeCursor(); 189 | 190 | return $rows; 191 | } 192 | 193 | /** 194 | * Runs a query but ensures that all identifiers are properly quoted by calling the Driver::quoteQueryIdentifiers 195 | * method on the query before executing it. 196 | * 197 | * @throws DatabaseDriverException 198 | */ 199 | public function quotedQuery(string $query, array $bindData = []): array 200 | { 201 | return $this->query($this->quoteQueryIdentifiers($query), $bindData); 202 | } 203 | 204 | /** 205 | * Expands the configuration array into a format that can easily be passed to PDO. 206 | */ 207 | private function expand(array $params): string 208 | { 209 | unset($params['driver']); 210 | if (isset($params['file'])) { 211 | if ($params['file'] != '') { 212 | return $params['file']; 213 | } 214 | } 215 | 216 | $equated = []; 217 | foreach ($params as $key => $value) { 218 | if ($value == '' || $key == 'options') { 219 | continue; 220 | } else { 221 | $equated[] = "$key=$value"; 222 | } 223 | } 224 | 225 | return implode(';', $equated); 226 | } 227 | 228 | /** 229 | * This method provides a system independent way of quoting identifiers in queries. By default all identifiers can 230 | * be quoted with double quotes ("). When a query quoted with double quotes is passed through this method the output 231 | * generated has the double quotes replaced with the quoting character of the target database platform. 232 | */ 233 | public function quoteQueryIdentifiers(string $query): string 234 | { 235 | return preg_replace_callback( 236 | '/\"([a-zA-Z\_ ]*)\"/', 237 | function ($matches) { 238 | return $this->quoteIdentifier($matches[1]); 239 | }, 240 | $query 241 | ); 242 | } 243 | 244 | /** 245 | * Returns an array description of the schema represented by the connection. 246 | * The description returns contains information about `tables`, `columns`, `keys`, 247 | * `constraints`, `views` and `indices`. 248 | */ 249 | public function describe(): array 250 | { 251 | return $this->getDescriptor()->describe(); 252 | } 253 | 254 | /** 255 | * Returns the description of a database table as an associative array. 256 | */ 257 | public function describeTable(string $table): array 258 | { 259 | $table = explode('.', $table); 260 | if (count($table) > 1) { 261 | $schema = $table[0]; 262 | $table = $table[1]; 263 | } else { 264 | $schema = $this->getDefaultSchema(); 265 | $table = $table[0]; 266 | } 267 | 268 | return $this->getDescriptor()->describeTables($schema, [$table], true); 269 | } 270 | 271 | /** 272 | * A wrapper around PDO's beginTransaction method which uses a static reference counter to implement nested 273 | * transactions. 274 | */ 275 | public function beginTransaction() 276 | { 277 | if (self::$transactionCount++ === 0) { 278 | $this->pdo->beginTransaction(); 279 | } 280 | } 281 | 282 | /** 283 | * A wrapper around PDO's commit transaction method which uses a static reference counter to implement nested 284 | * transactions. 285 | */ 286 | public function commit() 287 | { 288 | if (--self::$transactionCount === 0) { 289 | $this->pdo->commit(); 290 | } 291 | } 292 | 293 | /** 294 | * A wrapper around PDO's rollback transaction methd which rolls back all activities performed since the first call 295 | * to begin transaction. Unfortunately, transactions cannot be rolled back in a nested fashion. 296 | */ 297 | public function rollback() 298 | { 299 | if (self::$transactionCount) { 300 | $this->pdo->rollBack(); 301 | self::$transactionCount = 0; 302 | } 303 | } 304 | 305 | /** 306 | * Return the underlying PDO object. 307 | */ 308 | public function getPDO(): PDO 309 | { 310 | return $this->pdo; 311 | } 312 | 313 | /** 314 | * Returns an instance of a descriptor for a given driver. 315 | */ 316 | private function getDescriptor(): Descriptor 317 | { 318 | if (!isset($this->descriptor)) { 319 | $descriptorClass = '\\ntentan\\atiaa\\descriptors\\'.ucfirst($this->config['driver']).'Descriptor'; 320 | $this->descriptor = new $descriptorClass($this); 321 | } 322 | 323 | return $this->descriptor; 324 | } 325 | 326 | /** 327 | * A wrapper around PDO's lastInsertId() method. 328 | */ 329 | public function getLastInsertId(): mixed 330 | { 331 | return $this->pdo->lastInsertId(); 332 | } 333 | 334 | /** 335 | * Specify the default schema to use in cases where a schema is not provided as part of the table reference. 336 | */ 337 | public function setDefaultSchema(string $defaultSchema) 338 | { 339 | $this->defaultSchema = $defaultSchema; 340 | } 341 | 342 | abstract protected function getDriverName(); 343 | 344 | abstract public function quoteIdentifier($identifier); 345 | 346 | public function setCleanDefaults(bool $cleanDefaults): void 347 | { 348 | $this->getDescriptor()->setCleanDefaults($cleanDefaults); 349 | } 350 | 351 | public function isConnected(): bool 352 | { 353 | return $this->connected; 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/DriverFactory.php: -------------------------------------------------------------------------------- 1 | config = $dbConfig; 17 | } 18 | 19 | /** 20 | * Set or replace the configuration found in the factory. 21 | */ 22 | public function setConfig(array $config): void 23 | { 24 | $this->config = $config; 25 | } 26 | 27 | /** 28 | * Return the configuration currently stored in the factory. 29 | */ 30 | public function getConfig(): array 31 | { 32 | return $this->config; 33 | } 34 | 35 | /** 36 | * Create a new driver based on the configuration in the factory. 37 | */ 38 | public function createDriver(): Driver 39 | { 40 | $classname = '\ntentan\atiaa\drivers\\'.Text::ucamelize($this->config['driver']).'Driver'; 41 | return new $classname($this->config); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/NullConnection.php: -------------------------------------------------------------------------------- 1 | driver->quotedQuery( 15 | 'select 16 | "column_name" as "name", 17 | "data_type" as "type", 18 | "is_nullable" as "nulls", 19 | "column_default" as "default", 20 | "character_maximum_length" as "length" 21 | from "information_schema"."columns" 22 | where "table_name" = ? and "table_schema"=? 23 | order by "column_name"', 24 | [ 25 | $table['name'], 26 | $table['schema'], 27 | ] 28 | ); 29 | } 30 | 31 | #[\Override] 32 | protected function getTables($schema, $tables, $includeViews) 33 | { 34 | if ($includeViews) { 35 | $condition = '(table_type = ? or table_type = ?)'; 36 | $bind = ['BASE TABLE', 'VIEW']; 37 | } else { 38 | $condition = 'table_type = ?'; 39 | $bind = ['BASE TABLE']; 40 | } 41 | 42 | if (count($tables) > 0) { 43 | return $this->driver->quotedQuery( 44 | 'select "table_schema" as "schema", "table_name" as "name" 45 | from "information_schema"."tables" 46 | where '.$condition.' and table_schema = ? 47 | and table_name in (?'.str_repeat(', ?', count($tables) - 1).') 48 | order by "table_name"', 49 | array_merge($bind, [$schema], $tables) 50 | ); 51 | } else { 52 | return $this->driver->quotedQuery( 53 | 'select "table_schema" as "schema", "table_name" as "name" 54 | from "information_schema"."tables" 55 | where '.$condition.' and table_schema = ? order by "table_name"', 56 | array_merge($bind, [$schema]) 57 | ); 58 | } 59 | } 60 | 61 | #[\Override] 62 | protected function getPrimaryKey(&$table) 63 | { 64 | return $this->getConstraints($table, 'PRIMARY KEY'); 65 | } 66 | 67 | #[\Override] 68 | protected function getUniqueKeys(&$table) 69 | { 70 | return $this->getConstraints($table, 'UNIQUE'); 71 | } 72 | 73 | /** 74 | * @param string $type 75 | */ 76 | private function getConstraints($table, $type) 77 | { 78 | return $this->driver->quotedQuery( 79 | 'select "column_name" as "column", "pk"."constraint_name" as "name" 80 | from "information_schema"."table_constraints" "pk" 81 | join "information_schema"."key_column_usage" "c" on 82 | "c"."table_name" = "pk"."table_name" and 83 | "c"."constraint_name" = "pk"."constraint_name" and 84 | "c"."constraint_schema" = "pk"."table_schema" 85 | where "pk"."table_name" = ? and pk.table_schema= ? 86 | and constraint_type = ? order by "pk"."constraint_name", "column_name"', 87 | [$table['name'], $table['schema'], $type] 88 | ); 89 | } 90 | 91 | #[\Override] 92 | protected function getViews(&$schema) 93 | { 94 | return $this->driver->quotedQuery( 95 | 'select "table_schema" as "schema", "table_name" as "name", "view_definition" as "definition" 96 | from "information_schema"."views" 97 | where "table_schema" = ? order by "table_name"', 98 | [$schema] 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/descriptors/MysqlDescriptor.php: -------------------------------------------------------------------------------- 1 | driver->query( 9 | sprintf( 10 | "SELECT 11 | kcu.constraint_name as name, 12 | kcu.table_schema as `schema`, 13 | kcu.table_name as `table`, 14 | kcu.column_name as `column`, 15 | kcu.referenced_table_name AS foreign_table, 16 | kcu.referenced_table_schema AS foreign_schema, 17 | kcu.referenced_column_name AS foreign_column, 18 | rc.update_rule as on_update, 19 | rc.delete_rule as on_delete 20 | FROM 21 | information_schema.table_constraints AS tc 22 | JOIN information_schema.key_column_usage AS kcu 23 | ON tc.constraint_name = kcu.constraint_name and tc.table_schema = kcu.table_schema 24 | JOIN information_schema.referential_constraints AS rc 25 | ON rc.constraint_name = tc.constraint_name and rc.constraint_schema = tc.table_schema 26 | WHERE constraint_type = 'FOREIGN KEY' 27 | AND tc.table_name='%s' AND tc.table_schema='%s' order by kcu.constraint_name, kcu.column_name", 28 | $table['name'], 29 | $table['schema'] 30 | ) 31 | ); 32 | } 33 | 34 | protected function getIndices(&$table) 35 | { 36 | return $this->driver->query( 37 | sprintf("SELECT table_name, column_name as `column`,index_name as `name` FROM information_schema.STATISTICS 38 | WHERE INDEX_NAME not in (SELECT CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE) 39 | AND table_name = '%s' and table_schema = '%s' order by index_name, column_name", $table['name'], $table['schema']) 40 | ); 41 | } 42 | 43 | protected function getSchemata() 44 | { 45 | $defaultSchema = $this->driver->getDefaultSchema(); 46 | if ($defaultSchema == '') { 47 | $schemata = $this->driver->query( 48 | "select schema_name as name from information_schema.schemata 49 | where schema_name <> 'information_schema' order by schema_name" 50 | ); 51 | } else { 52 | $schemata = [ 53 | [ 54 | 'name' => $defaultSchema, 55 | ], 56 | ]; 57 | } 58 | 59 | return $schemata; 60 | } 61 | 62 | protected function hasAutoIncrementingKey(&$table) 63 | { 64 | $auto = false; 65 | $found = $this->driver->query( 66 | sprintf( 67 | "select column_name as name 68 | from information_schema.columns 69 | where table_name = '%s' and table_schema='%s' and extra = 'auto_increment'", 70 | $table['name'], 71 | $table['schema'] 72 | ) 73 | ); 74 | 75 | if (count($found) > 0) { 76 | $auto = true; 77 | } 78 | 79 | return $auto; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/descriptors/PostgresqlDescriptor.php: -------------------------------------------------------------------------------- 1 | .*)(::)(?[a-zA-Z0-9\s]*)$/", $defaultValue, $matches)) { 11 | $value = $matches['value']; 12 | 13 | // If numeric 14 | if (is_numeric($value)) { 15 | return $value; 16 | 17 | // If its a string 18 | } elseif (preg_match("/'(?.*)'/", $value, $matches)) { 19 | return $matches['string']; 20 | 21 | // null for anything else 22 | } else { 23 | return; 24 | } 25 | 26 | // Return the nextval as atiaa uses them to detect auto keys 27 | } elseif (preg_match("/nextval\(.*/", $defaultValue)) { 28 | return $defaultValue; 29 | 30 | // Return numeric default values 31 | } elseif (is_numeric($defaultValue)) { 32 | return $defaultValue; 33 | 34 | // Return null for anything else 35 | } else { 36 | return; 37 | } 38 | } 39 | 40 | /** 41 | * @note Query sourced from http://stackoverflow.com/questions/2204058/show-which-columns-an-index-is-on-in-postgresql 42 | * 43 | * @param type $table 44 | * 45 | * @return type 46 | */ 47 | protected function getIndices(&$table) 48 | { 49 | return $this->driver->query( 50 | sprintf( 51 | "select 52 | t.relname as table_name, 53 | i.relname as name, 54 | a.attname as column 55 | from 56 | pg_class t, 57 | pg_class i, 58 | pg_index ix, 59 | pg_attribute a, 60 | pg_namespace n 61 | where 62 | t.oid = ix.indrelid 63 | and i.oid = ix.indexrelid 64 | and a.attrelid = t.oid 65 | and a.attnum = ANY(ix.indkey) 66 | and t.relkind = 'r' 67 | and t.relname = '%s' 68 | and n.nspname = '%s' 69 | and i.relnamespace = n.oid 70 | AND indisunique != 't' 71 | AND indisprimary != 't' 72 | order by i.relname, a.attname", 73 | $table['name'], 74 | $table['schema'] 75 | ) 76 | ); 77 | } 78 | 79 | /** 80 | * @note Query sourced from http://stackoverflow.com/questions/1152260/postgres-sql-to-list-table-foreign-keys 81 | * 82 | * @param type $table 83 | */ 84 | protected function getForeignKeys(&$table) 85 | { 86 | return $this->driver->query( 87 | "SELECT distinct 88 | kcu.constraint_name as name, 89 | kcu.table_schema as schema, 90 | kcu.table_name as table, 91 | kcu.column_name as column, 92 | ccu.table_name AS foreign_table, 93 | ccu.table_schema AS foreign_schema, 94 | ccu.column_name AS foreign_column, 95 | rc.update_rule as on_update, 96 | rc.delete_rule as on_delete 97 | 98 | FROM 99 | information_schema.table_constraints AS tc 100 | JOIN information_schema.key_column_usage AS kcu 101 | ON tc.constraint_name = kcu.constraint_name and tc.table_schema = kcu.table_schema and tc.table_name = kcu.table_name 102 | JOIN information_schema.constraint_column_usage AS ccu 103 | ON ccu.constraint_name = tc.constraint_name and ccu.constraint_schema = tc.table_schema 104 | JOIN information_schema.referential_constraints AS rc 105 | ON rc.constraint_name = tc.constraint_name and rc.constraint_schema = tc.table_schema 106 | WHERE constraint_type = 'FOREIGN KEY' 107 | AND tc.table_name=:name AND tc.table_schema=:schema 108 | AND kcu.table_name=:name AND kcu.table_schema=:schema 109 | order by kcu.constraint_name, kcu.column_name", 110 | //$table['name'], $table['schema'] 111 | ['name'=>$table['name'], 'schema'=>$table['schema']] 112 | ); 113 | } 114 | 115 | public function getSchemata() 116 | { 117 | return $this->driver->query( 118 | "select schema_name as name from information_schema.schemata 119 | where schema_name not like 'pg_temp%' and 120 | schema_name not like 'pg_toast%' and 121 | schema_name not in ('pg_catalog', 'information_schema') 122 | order by schema_name" 123 | ); 124 | } 125 | 126 | protected function hasAutoIncrementingKey(&$table) 127 | { 128 | $auto = false; 129 | $primaryKey = reset($table['primary_key']); 130 | if (is_array($primaryKey)) { 131 | if (count($primaryKey['columns']) == 1 && substr_count($table['columns'][$primaryKey['columns'][0]]['default'], 'nextval')) { 132 | $table['columns'][$primaryKey['columns'][0]]['default'] = null; 133 | $auto = true; 134 | } 135 | } 136 | 137 | return $auto; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/descriptors/SqliteDescriptor.php: -------------------------------------------------------------------------------- 1 | driver->query("PRAGMA table_info({$table['name']})"); 9 | foreach ($pragmaColumns as $column) { 10 | preg_match("/(?[a-zA-Z]*)(\((?[0-9]+)\))*/", $column['type'], $matches); 11 | $columns[] = [ 12 | 'name' => $column['name'], 13 | 'type' => $matches['type'], 14 | 'nulls' => $column['notnull'] == '0', 15 | 'default' => $column['dflt_value'], 16 | 'length' => isset($matches['length']) ? $matches['length'] : null, 17 | ]; 18 | } 19 | 20 | return $columns; 21 | } 22 | 23 | protected function cleanDefaultValue($default) 24 | { 25 | if (preg_match("/(')?(?.*)/", $default, $matches)) { 26 | return substr($matches['value'], 0, strlen($matches['value']) - 1); 27 | } else { 28 | return; 29 | } 30 | } 31 | 32 | protected function getForeignKeys(&$table) 33 | { 34 | $foreignKeys = []; 35 | $pragmaColumns = $this->driver->query("pragma foreign_key_list({$table['name']})"); 36 | foreach ($pragmaColumns as $i => $foreignKey) { 37 | $foreignKeys[] = [ 38 | 'name' => "{$table['name']}_{$foreignKey['table']}_{$i}_fk", 39 | 'schema' => $table['schema'], 40 | 'table' => $table['name'], 41 | 'column' => $foreignKey['from'], 42 | 'foreign_table' => $foreignKey['table'], 43 | 'foreign_schema' => 'main', 44 | 'foreign_column' => $foreignKey['to'], 45 | 'on_update' => $foreignKey['on_update'], 46 | 'on_delete' => $foreignKey['on_delete'], 47 | ]; 48 | } 49 | 50 | return $foreignKeys; 51 | } 52 | 53 | private function extractIndexDetails($details, $index, &$indexDetails) 54 | { 55 | foreach ($details as $detail) { 56 | if ($detail['name'] != '') { 57 | $indexDetails[] = [ 58 | 'column' => $detail['name'], 59 | 'name' => $index['name'], 60 | 'schema' => $index['schema'], 61 | ]; 62 | } 63 | } 64 | } 65 | 66 | private function getIndexDetails($table, $unique) 67 | { 68 | $indices = $this->driver->query("pragma index_list({$table['name']})"); 69 | $indexDetails = []; 70 | 71 | foreach ($indices as $index) { 72 | if ($index['unique'] == $unique) { 73 | $index['schema'] = $table['schema']; 74 | $detail = $this->driver->query("pragma index_info({$index['name']})"); 75 | $this->extractIndexDetails($detail, $index, $indexDetails); 76 | } 77 | } 78 | 79 | return $indexDetails; 80 | } 81 | 82 | protected function getIndices(&$table) 83 | { 84 | return $this->getIndexDetails($table, '0'); 85 | } 86 | 87 | protected function getPrimaryKey(&$table) 88 | { 89 | $keyColumns = []; 90 | $pragmaColumns = $this->driver->query("PRAGMA table_info({$table['name']})"); 91 | foreach ($pragmaColumns as $column) { 92 | if ($column['pk'] > 0) { 93 | $keyColumns[] = [ 94 | 'order' => $column['pk'], 95 | 'column' => $column['name'], 96 | 'name' => "{$table['name']}_pk", 97 | ]; 98 | } 99 | } 100 | 101 | usort($keyColumns, function ($a, $b) { 102 | return $a['order'] - $b['order']; 103 | }); 104 | 105 | return $keyColumns; 106 | } 107 | 108 | protected function getSchemata() 109 | { 110 | return [['name' => 'main']]; 111 | } 112 | 113 | protected function getTables($schema, $tables, $includeViews) 114 | { 115 | if ($includeViews) { 116 | $condition = '(type = ? or type = ?)'; 117 | $bind = ['table', 'view']; 118 | } else { 119 | $condition = 'type = ?'; 120 | $bind = ['table']; 121 | } 122 | 123 | if (count($tables) > 0) { 124 | return $this->driver->quotedQuery( 125 | 'select name as "name", \'main\' as "schema" from sqlite_master 126 | where '.$condition.' and name not in (\'sqlite_master\', \'sqlite_sequence\') and name in (?'.str_repeat(', ?', count($tables) - 1).') 127 | order by name', 128 | array_merge($bind, $tables) 129 | ); 130 | } else { 131 | return $this->driver->quotedQuery( 132 | 'select name as "name", \'main\' as "schema" from sqlite_master 133 | where name not in (\'sqlite_master\', \'sqlite_sequence\') and '.$condition, 134 | array_merge($bind) 135 | ); 136 | } 137 | } 138 | 139 | protected function getUniqueKeys(&$table) 140 | { 141 | return $this->getIndexDetails($table, '1'); 142 | } 143 | 144 | protected function getViews(&$schema) 145 | { 146 | return $this->driver->query("select 'main' as schema, name, sql as definition from sqlite_master where type = 'view'"); 147 | } 148 | 149 | protected function hasAutoIncrementingKey(&$table) 150 | { 151 | $sql = $this->driver->query('select sql from sqlite_master where name = ?', [$table['name']]); 152 | if (preg_match('/AUTOINCREMENT/', $sql[0]['sql'])) { 153 | return true; 154 | } else { 155 | return false; 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/drivers/MysqlDriver.php: -------------------------------------------------------------------------------- 1 | defaultSchema) { 47 | return $this->config['dbname']; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/drivers/PostgresqlDriver.php: -------------------------------------------------------------------------------- 1 | query('SELECT LASTVAL() as last'); 27 | return $lastval[0]['last']; 28 | } 29 | 30 | #[\Override] 31 | public function connect(): void 32 | { 33 | parent::connect(); 34 | if (isset($this->config['schema'])) { 35 | $this->query("SET search_path TO {$this->config['schema']}"); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/drivers/SqliteDriver.php: -------------------------------------------------------------------------------- 1 | defaultSchema = 'main'; 14 | parent::__construct($config); 15 | } 16 | 17 | #[\Override] 18 | public function connect(): void 19 | { 20 | parent::connect(); 21 | $this->query('PRAGMA foreign_keys=ON'); 22 | } 23 | 24 | protected function getDriverName() 25 | { 26 | return 'sqlite'; 27 | } 28 | 29 | public function quoteIdentifier($identifier) 30 | { 31 | return "\"$identifier\""; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/exceptions/ConnectionException.php: -------------------------------------------------------------------------------- 1 | getDriverName()).'Descriptor'; 44 | $descriptor = new $descriptorClass($driver); 45 | 46 | return $descriptor; 47 | } 48 | 49 | public function setUp(): void 50 | { 51 | // Preserve the original dbname just in case it changes in any test 52 | $this->dbName = getenv('ATIAA_DBNAME'); 53 | } 54 | 55 | public function tearDown(): void 56 | { 57 | putenv("ATIAA_DBNAME={$this->dbName}"); 58 | } 59 | 60 | public function testFunctions() 61 | { 62 | $driverName = $this->getDriverName(); 63 | $driver = $this->getDriver(); 64 | 65 | $strings = json_decode(file_get_contents("tests/expected/$driverName/strings.json"), true); 66 | $this->assertEquals($strings['quoted_string'], $driver->quote('string')); 67 | $this->assertEquals($strings['quoted_identifier'], $driver->quoteIdentifier('identifier')); 68 | $this->assertEquals($strings['quoted_query_identifiers'], $driver->quoteQueryIdentifiers('SELECT "some", "identifiers" FROM "some"."table"')); 69 | $pdo = $driver->getPDO(); 70 | $this->assertInstanceOf('PDO', $pdo); 71 | } 72 | 73 | public function testFullDescription() 74 | { 75 | $driver = $this->getDriver(); 76 | $type = $this->getDriverName(); 77 | 78 | $testDbDescription = $driver->describe(); 79 | $views = $testDbDescription['views']; 80 | 81 | // Unset the views since they vary from each other with respect to database drivers. 82 | unset($testDbDescription['views']); 83 | unset($testDbDescription['schemata'][$driver->getDefaultSchema()]['views']); 84 | 85 | require "tests/expected/{$type}/database_description.php"; 86 | $this->assertEquals($databaseDescription, $testDbDescription); 87 | $this->assertArrayHasKey('users_view', $views); 88 | $this->assertArrayHasKey('definition', $views['users_view']); 89 | $this->assertEquals('users_view', $views['users_view']['name']); 90 | } 91 | 92 | public function testCleanDefaultDescription() 93 | { 94 | $driver = $this->getDriver(); 95 | $type = $this->getDriverName(); 96 | $driver->setCleanDefaults(true); 97 | 98 | $testDbDescription = $driver->describe(); 99 | $views = $testDbDescription['views']; 100 | unset($testDbDescription['views']); 101 | unset($testDbDescription['schemata'][$driver->getDefaultSchema()]['views']); 102 | require "tests/expected/{$type}/database_description_clean_defaults.php"; 103 | $this->assertEquals($databaseDescription, $testDbDescription); 104 | $this->assertArrayHasKey('users_view', $views); 105 | $this->assertArrayHasKey('definition', $views['users_view']); 106 | $this->assertEquals('users_view', $views['users_view']['name']); 107 | } 108 | 109 | public function testViewDescriptionAsTable() 110 | { 111 | $driver = $this->getDriver(); 112 | $type = $this->getDriverName(); 113 | 114 | $viewDbDescription = $driver->describeTable('users_view'); 115 | require "tests/expected/{$type}/view_description.php"; 116 | $this->assertEquals($viewDescription, $viewDbDescription); 117 | } 118 | 119 | public function testStringSchema() 120 | { 121 | if (!$this->hasSchemata()) { 122 | $this->markTestSkipped(); 123 | 124 | return; 125 | } 126 | 127 | $driver = $this->getDriver(); 128 | $type = $this->getDriverName(); 129 | 130 | $employeesDbDescription = $driver->describeTable('hr.employees'); 131 | require "tests/expected/{$type}/employees_description.php"; 132 | $this->assertEquals($employeesDescription, $employeesDbDescription); 133 | } 134 | 135 | public function testTableNotFoundException() 136 | { 137 | $this->expectException(TableNotFoundException::class); 138 | $driver = $this->getDriver(); 139 | $driver->describeTable('unknown_table'); 140 | } 141 | 142 | public function testTableNotFoundExceptionAgain() 143 | { 144 | $this->expectException(TableNotFoundException::class); 145 | $driver = $this->getDriver($this); 146 | $this->getDescriptor($driver)->describeTables($driver->getDefaultSchema(), ['users', 'unknown_table']); 147 | } 148 | 149 | public function testFaultyQueryException() 150 | { 151 | $this->expectException(DatabaseDriverException::class); 152 | $driver = $this->getDriver($this); 153 | $driver->query('SPELECT * FROM dummy'); 154 | } 155 | 156 | public function testDisconnect() 157 | { 158 | $this->expectException(DatabaseDriverException::class); 159 | $driver = $this->getDriver($this); 160 | $driver->disconnect(); 161 | $driver->query('SELECT * FROM users'); 162 | } 163 | 164 | private function hasSchemata() 165 | { 166 | return strtolower(getenv('ATIAA_HAS_SCHEMAS')) === 'yes'; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /tests/config/github.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ../cases 9 | 10 | 11 | 12 | 13 | ../../src 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/config/sample.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ../cases 18 | 19 | 20 | 21 | 22 | ../../src 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/databases/mysql.sql: -------------------------------------------------------------------------------- 1 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 2 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 3 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 4 | /*!40101 SET NAMES utf8 */; 5 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 6 | /*!40103 SET TIME_ZONE='+00:00' */; 7 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 8 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 9 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 10 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 11 | 12 | DROP TABLE IF EXISTS `departments`; 13 | /*!40101 SET @saved_cs_client = @@character_set_client */; 14 | /*!40101 SET character_set_client = utf8 */; 15 | CREATE TABLE `departments` ( 16 | `id` int(11) NOT NULL AUTO_INCREMENT, 17 | `name` varchar(255) NOT NULL, 18 | PRIMARY KEY (`id`) 19 | ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; 20 | /*!40101 SET character_set_client = @saved_cs_client */; 21 | 22 | LOCK TABLES `departments` WRITE; 23 | /*!40000 ALTER TABLE `departments` DISABLE KEYS */; 24 | /*!40000 ALTER TABLE `departments` ENABLE KEYS */; 25 | UNLOCK TABLES; 26 | 27 | DROP TABLE IF EXISTS `roles`; 28 | /*!40101 SET @saved_cs_client = @@character_set_client */; 29 | /*!40101 SET character_set_client = utf8 */; 30 | CREATE TABLE `roles` ( 31 | `id` int(11) NOT NULL AUTO_INCREMENT, 32 | `name` varchar(255) NOT NULL, 33 | PRIMARY KEY (`id`), 34 | UNIQUE KEY `name` (`name`) 35 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; 36 | /*!40101 SET character_set_client = @saved_cs_client */; 37 | 38 | LOCK TABLES `roles` WRITE; 39 | /*!40000 ALTER TABLE `roles` DISABLE KEYS */; 40 | /*!40000 ALTER TABLE `roles` ENABLE KEYS */; 41 | UNLOCK TABLES; 42 | 43 | DROP TABLE IF EXISTS `users`; 44 | /*!40101 SET @saved_cs_client = @@character_set_client */; 45 | /*!40101 SET character_set_client = utf8 */; 46 | CREATE TABLE `users` ( 47 | `id` int(11) NOT NULL AUTO_INCREMENT, 48 | `username` varchar(255) NOT NULL, 49 | `password` varchar(255) NOT NULL, 50 | `role_id` int(11) NOT NULL, 51 | `firstname` varchar(255) NOT NULL, 52 | `lastname` varchar(255) NOT NULL, 53 | `othernames` varchar(255) DEFAULT 'None', 54 | `status` int(11) NOT NULL DEFAULT '2', 55 | `email` varchar(255) NOT NULL, 56 | `phone` varchar(64) DEFAULT NULL, 57 | `office` int(11) DEFAULT NULL, 58 | `last_login_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, 59 | `is_admin` tinyint(1) DEFAULT NULL, 60 | PRIMARY KEY (`id`), 61 | KEY `user_role_fk` (`role_id`), 62 | CONSTRAINT `user_role_fk` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) 63 | ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; 64 | /*!40101 SET character_set_client = @saved_cs_client */; 65 | 66 | LOCK TABLES `users` WRITE; 67 | /*!40000 ALTER TABLE `users` DISABLE KEYS */; 68 | /*!40000 ALTER TABLE `users` ENABLE KEYS */; 69 | UNLOCK TABLES; 70 | 71 | DROP TABLE IF EXISTS `users_view`; 72 | /*!50001 DROP VIEW IF EXISTS `users_view`*/; 73 | SET @saved_cs_client = @@character_set_client; 74 | SET character_set_client = utf8; 75 | /*!50001 CREATE TABLE `users_view` ( 76 | `id` tinyint NOT NULL, 77 | `username` tinyint NOT NULL, 78 | `password` tinyint NOT NULL, 79 | `firstname` tinyint NOT NULL, 80 | `lastname` tinyint NOT NULL, 81 | `othernames` tinyint NOT NULL, 82 | `email` tinyint NOT NULL, 83 | `role` tinyint NOT NULL 84 | ) ENGINE=MyISAM */; 85 | SET character_set_client = @saved_cs_client; 86 | 87 | /*!50001 DROP TABLE IF EXISTS `users_view`*/; 88 | /*!50001 DROP VIEW IF EXISTS `users_view`*/; 89 | /*!50001 SET @saved_cs_client = @@character_set_client */; 90 | /*!50001 SET @saved_cs_results = @@character_set_results */; 91 | /*!50001 SET @saved_col_connection = @@collation_connection */; 92 | /*!50001 SET character_set_client = utf8 */; 93 | /*!50001 SET character_set_results = utf8 */; 94 | /*!50001 SET collation_connection = utf8_general_ci */; 95 | /*!50001 CREATE ALGORITHM=UNDEFINED */ 96 | /*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ 97 | /*!50001 VIEW `users_view` AS select `users`.`id` AS `id`,`users`.`username` AS `username`,`users`.`password` AS `password`,`users`.`firstname` AS `firstname`,`users`.`lastname` AS `lastname`,`users`.`othernames` AS `othernames`,`users`.`email` AS `email`,`roles`.`name` AS `role` from (`users` join `roles` on((`users`.`role_id` = `roles`.`id`))) */; 98 | /*!50001 SET character_set_client = @saved_cs_client */; 99 | /*!50001 SET character_set_results = @saved_cs_results */; 100 | /*!50001 SET collation_connection = @saved_col_connection */; 101 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 102 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 103 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 104 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 105 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 106 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 107 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 108 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 109 | -------------------------------------------------------------------------------- /tests/databases/postgresql.sql: -------------------------------------------------------------------------------- 1 | SET statement_timeout = 0; 2 | SET lock_timeout = 0; 3 | SET client_encoding = 'UTF8'; 4 | SET standard_conforming_strings = on; 5 | SET check_function_bodies = false; 6 | SET client_min_messages = warning; 7 | 8 | CREATE SCHEMA crm; 9 | 10 | CREATE SCHEMA hr; 11 | 12 | CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; 13 | 14 | SET search_path = crm, pg_catalog; 15 | SET default_tablespace = ''; 16 | SET default_with_oids = false; 17 | 18 | CREATE TABLE customers ( 19 | id integer NOT NULL, 20 | name character varying(255) NOT NULL, 21 | employee_id integer NOT NULL 22 | ); 23 | 24 | CREATE SEQUENCE customers_id_seq 25 | START WITH 1 26 | INCREMENT BY 1 27 | NO MINVALUE 28 | NO MAXVALUE 29 | CACHE 1; 30 | 31 | 32 | ALTER SEQUENCE customers_id_seq OWNED BY customers.id; 33 | SET search_path = hr, pg_catalog; 34 | 35 | CREATE TABLE categories ( 36 | id integer NOT NULL, 37 | name character varying(255) NOT NULL 38 | ); 39 | 40 | CREATE SEQUENCE departments_id_seq 41 | START WITH 1 42 | INCREMENT BY 1 43 | NO MINVALUE 44 | NO MAXVALUE 45 | CACHE 1; 46 | 47 | 48 | ALTER SEQUENCE departments_id_seq OWNED BY categories.id; 49 | 50 | CREATE TABLE employees ( 51 | id integer NOT NULL, 52 | firstname character varying(255) NOT NULL, 53 | lastname character varying(255), 54 | date_of_birth date 55 | ); 56 | 57 | CREATE SEQUENCE employees_id_seq 58 | START WITH 1 59 | INCREMENT BY 1 60 | NO MINVALUE 61 | NO MAXVALUE 62 | CACHE 1; 63 | 64 | 65 | ALTER SEQUENCE employees_id_seq OWNED BY employees.id; 66 | SET search_path = public, pg_catalog; 67 | 68 | CREATE TABLE departments ( 69 | id integer NOT NULL, 70 | name character varying(255) NOT NULL 71 | ); 72 | 73 | CREATE SEQUENCE departments_id_seq 74 | START WITH 6 75 | INCREMENT BY 1 76 | NO MINVALUE 77 | NO MAXVALUE 78 | CACHE 1; 79 | 80 | 81 | ALTER SEQUENCE departments_id_seq OWNED BY departments.id; 82 | 83 | CREATE TABLE roles ( 84 | id integer NOT NULL, 85 | name character varying(255) NOT NULL 86 | ); 87 | 88 | CREATE SEQUENCE roles_id_seq 89 | START WITH 5 90 | INCREMENT BY 1 91 | NO MINVALUE 92 | NO MAXVALUE 93 | CACHE 1; 94 | 95 | 96 | ALTER SEQUENCE roles_id_seq OWNED BY roles.id; 97 | 98 | CREATE TABLE users ( 99 | id integer NOT NULL, 100 | username character varying(255) NOT NULL, 101 | password character varying(255) NOT NULL, 102 | role_id integer NOT NULL, 103 | firstname character varying(255) NOT NULL, 104 | lastname character varying(255) NOT NULL, 105 | othernames character varying(255) DEFAULT 'None'::character varying, 106 | status integer NOT NULL DEFAULT '2', 107 | email character varying(255) NOT NULL, 108 | phone character varying(64) DEFAULT NULL::character varying, 109 | office integer, 110 | last_login_time timestamp without time zone, 111 | is_admin boolean 112 | ); 113 | 114 | CREATE SEQUENCE users_id_seq 115 | START WITH 8 116 | INCREMENT BY 1 117 | NO MINVALUE 118 | NO MAXVALUE 119 | CACHE 1; 120 | 121 | 122 | ALTER SEQUENCE users_id_seq OWNED BY users.id; 123 | 124 | CREATE VIEW users_view AS 125 | SELECT users.id, 126 | users.username, 127 | users.password, 128 | users.firstname, 129 | users.lastname, 130 | users.othernames, 131 | users.email, 132 | roles.name AS role 133 | FROM (users 134 | JOIN roles ON ((users.role_id = roles.id))); 135 | SET search_path = crm, pg_catalog; 136 | 137 | ALTER TABLE ONLY customers ALTER COLUMN id SET DEFAULT nextval('customers_id_seq'::regclass); 138 | SET search_path = hr, pg_catalog; 139 | 140 | ALTER TABLE ONLY categories ALTER COLUMN id SET DEFAULT nextval('departments_id_seq'::regclass); 141 | 142 | ALTER TABLE ONLY employees ALTER COLUMN id SET DEFAULT nextval('employees_id_seq'::regclass); 143 | SET search_path = public, pg_catalog; 144 | 145 | ALTER TABLE ONLY departments ALTER COLUMN id SET DEFAULT nextval('departments_id_seq'::regclass); 146 | 147 | ALTER TABLE ONLY roles ALTER COLUMN id SET DEFAULT nextval('roles_id_seq'::regclass); 148 | 149 | ALTER TABLE ONLY users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass); 150 | SET search_path = crm, pg_catalog; 151 | 152 | ALTER TABLE ONLY customers 153 | ADD CONSTRAINT customers_pkey PRIMARY KEY (id); 154 | SET search_path = hr, pg_catalog; 155 | 156 | ALTER TABLE ONLY categories 157 | ADD CONSTRAINT departments_pkey PRIMARY KEY (id); 158 | 159 | ALTER TABLE ONLY employees 160 | ADD CONSTRAINT employees_pkey PRIMARY KEY (id); 161 | SET search_path = public, pg_catalog; 162 | 163 | ALTER TABLE ONLY departments 164 | ADD CONSTRAINT departments_pkey PRIMARY KEY (id); 165 | 166 | ALTER TABLE ONLY roles 167 | ADD CONSTRAINT roles_pkey PRIMARY KEY (id); 168 | 169 | ALTER TABLE ONLY users 170 | ADD CONSTRAINT users_pkey PRIMARY KEY (id); 171 | SET search_path = crm, pg_catalog; 172 | 173 | ALTER TABLE ONLY customers 174 | ADD CONSTRAINT customers_employee_id_fkey FOREIGN KEY (employee_id) REFERENCES hr.employees(id); 175 | SET search_path = public, pg_catalog; 176 | 177 | ALTER TABLE ONLY users 178 | ADD CONSTRAINT users_office_fkey FOREIGN KEY (office) REFERENCES departments(id); 179 | 180 | ALTER TABLE ONLY users 181 | ADD CONSTRAINT users_role_id_fkey FOREIGN KEY (role_id) REFERENCES roles(id); 182 | 183 | 184 | -------------------------------------------------------------------------------- /tests/databases/sqlite.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `departments` (`id` INTEGER CONSTRAINT `department_id_pk` PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL); 2 | CREATE TABLE `roles` (`id` INTEGER CONSTRAINT `role_id_pk` PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL); 3 | CREATE TABLE `users` ( 4 | `id` INTEGER NOT NULL CONSTRAINT `user_id_pk` PRIMARY KEY AUTOINCREMENT, 5 | `username` TEXT(255) NOT NULL, 6 | `password` TEXT NOT NULL, 7 | `role_id` INTEGER NOT NULL CONSTRAINT `role_id_fk` REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 8 | `firstname` TEXT NOT NULL, 9 | `lastname` TEXT NOT NULL, 10 | `othernames` TEXT DEFAULT 'None', 11 | `status` INTEGER DEFAULT '2', 12 | `email` TEXT, 13 | `phone` TEXT, 14 | `office` INTEGER NOT NULL CONSTRAINT `office_fk` REFERENCES `departments` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 15 | `last_login_time` TEXT, 16 | `is_admin` INTEGER, 17 | CONSTRAINT `username_uk` UNIQUE (username) 18 | ); 19 | 20 | CREATE INDEX user_email_idx ON users(email); 21 | 22 | CREATE VIEW `users_view` AS SELECT 23 | `users`.`id`, `username`, `password`, `firstname`, `lastname`, `othernames`, 24 | `email`, `roles`.`name` as `role` 25 | FROM `users` JOIN `roles` ON `role_id` = `roles`.`id`; 26 | -------------------------------------------------------------------------------- /tests/expected/mysql/database_description.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'atiaa_test' => [ 30 | 'name' => 'atiaa_test', 31 | 'tables' => [ 32 | 'departments' => [ 33 | 'schema' => '', 34 | 'name' => 'departments', 35 | 'columns' => [ 36 | 'id' => [ 37 | 'name' => 'id', 38 | 'type' => 'int', 39 | 'nulls' => false, 40 | 'default' => null, 41 | 'length' => null, 42 | ], 43 | 'name' => [ 44 | 'name' => 'name', 45 | 'type' => 'varchar', 46 | 'nulls' => false, 47 | 'default' => null, 48 | 'length' => '255', 49 | ], 50 | ], 51 | 'primary_key' => [ 52 | 'PRIMARY' => [ 53 | 'columns' => [ 54 | 0 => 'id', 55 | ], 56 | ], 57 | ], 58 | 'unique_keys' => [ 59 | ], 60 | 'foreign_keys' => [ 61 | ], 62 | 'indices' => [ 63 | ], 64 | 'auto_increment' => true, 65 | ], 66 | 'roles' => [ 67 | 'schema' => '', 68 | 'name' => 'roles', 69 | 'columns' => [ 70 | 'id' => [ 71 | 'name' => 'id', 72 | 'type' => 'int', 73 | 'nulls' => false, 74 | 'default' => null, 75 | 'length' => null, 76 | ], 77 | 'name' => [ 78 | 'name' => 'name', 79 | 'type' => 'varchar', 80 | 'nulls' => false, 81 | 'default' => null, 82 | 'length' => '255', 83 | ], 84 | ], 85 | 'primary_key' => [ 86 | 'PRIMARY' => [ 87 | 'columns' => [ 88 | 0 => 'id', 89 | ], 90 | ], 91 | ], 92 | 'unique_keys' => [ 93 | 'name' => [ 94 | 'columns' => [ 95 | 0 => 'name', 96 | ], 97 | ], 98 | ], 99 | 'foreign_keys' => [ 100 | ], 101 | 'indices' => [ 102 | ], 103 | 'auto_increment' => true, 104 | ], 105 | 'users' => [ 106 | 'schema' => '', 107 | 'name' => 'users', 108 | 'columns' => [ 109 | 'email' => [ 110 | 'name' => 'email', 111 | 'type' => 'varchar', 112 | 'nulls' => false, 113 | 'default' => null, 114 | 'length' => '255', 115 | ], 116 | 'firstname' => [ 117 | 'name' => 'firstname', 118 | 'type' => 'varchar', 119 | 'nulls' => false, 120 | 'default' => null, 121 | 'length' => '255', 122 | ], 123 | 'id' => [ 124 | 'name' => 'id', 125 | 'type' => 'int', 126 | 'nulls' => false, 127 | 'default' => null, 128 | 'length' => null, 129 | ], 130 | 'is_admin' => [ 131 | 'name' => 'is_admin', 132 | 'type' => 'tinyint', 133 | 'nulls' => true, 134 | 'default' => null, 135 | 'length' => null, 136 | ], 137 | 'lastname' => [ 138 | 'name' => 'lastname', 139 | 'type' => 'varchar', 140 | 'nulls' => false, 141 | 'default' => null, 142 | 'length' => '255', 143 | ], 144 | 'last_login_time' => [ 145 | 'name' => 'last_login_time', 146 | 'type' => 'timestamp', 147 | 'nulls' => true, 148 | 'default' => null, 149 | 'length' => null, 150 | ], 151 | 'office' => [ 152 | 'name' => 'office', 153 | 'type' => 'int', 154 | 'nulls' => true, 155 | 'default' => null, 156 | 'length' => null, 157 | ], 158 | 'othernames' => [ 159 | 'name' => 'othernames', 160 | 'type' => 'varchar', 161 | 'nulls' => true, 162 | 'default' => 'None', 163 | 'length' => 255, 164 | ], 165 | 'password' => [ 166 | 'name' => 'password', 167 | 'type' => 'varchar', 168 | 'nulls' => false, 169 | 'default' => null, 170 | 'length' => '255', 171 | ], 172 | 'phone' => [ 173 | 'name' => 'phone', 174 | 'type' => 'varchar', 175 | 'nulls' => true, 176 | 'default' => null, 177 | 'length' => '64', 178 | ], 179 | 'role_id' => [ 180 | 'name' => 'role_id', 181 | 'type' => 'int', 182 | 'nulls' => false, 183 | 'default' => null, 184 | 'length' => null, 185 | ], 186 | 'status' => [ 187 | 'name' => 'status', 188 | 'type' => 'int', 189 | 'nulls' => false, 190 | 'default' => '2', 191 | 'length' => null, 192 | ], 193 | 'username' => [ 194 | 'name' => 'username', 195 | 'type' => 'varchar', 196 | 'nulls' => false, 197 | 'default' => null, 198 | 'length' => '255', 199 | ], 200 | ], 201 | 'primary_key' => [ 202 | 'PRIMARY' => [ 203 | 'columns' => [ 204 | 0 => 'id', 205 | ], 206 | ], 207 | ], 208 | 'unique_keys' => [ 209 | ], 210 | 'foreign_keys' => [ 211 | 'user_role_fk' => [ 212 | 'schema' => '', 213 | 'table' => 'users', 214 | 'columns' => [ 215 | 0 => 'role_id', 216 | ], 217 | 'foreign_table' => 'roles', 218 | 'foreign_schema' => '', 219 | 'foreign_columns' => [ 220 | 0 => 'id', 221 | ], 222 | 'on_update' => 'NO ACTION', 223 | 'on_delete' => 'NO ACTION', 224 | ], 225 | ], 226 | 'indices' => [ 227 | ], 228 | 'auto_increment' => true, 229 | ] 230 | ] 231 | ] 232 | ], 233 | 'tables' => [ 234 | 'departments' => [ 235 | 'schema' => '', 236 | 'name' => 'departments', 237 | 'columns' => [ 238 | 'id' => [ 239 | 'name' => 'id', 240 | 'type' => 'int', 241 | 'nulls' => false, 242 | 'default' => null, 243 | 'length' => null, 244 | ], 245 | 'name' => [ 246 | 'name' => 'name', 247 | 'type' => 'varchar', 248 | 'nulls' => false, 249 | 'default' => null, 250 | 'length' => '255', 251 | ], 252 | ], 253 | 'primary_key' => [ 254 | 'PRIMARY' => [ 255 | 'columns' => [ 256 | 0 => 'id', 257 | ], 258 | ], 259 | ], 260 | 'unique_keys' => [ 261 | ], 262 | 'foreign_keys' => [ 263 | ], 264 | 'indices' => [ 265 | ], 266 | 'auto_increment' => true, 267 | ], 268 | 'roles' => [ 269 | 'schema' => '', 270 | 'name' => 'roles', 271 | 'columns' => [ 272 | 'id' => [ 273 | 'name' => 'id', 274 | 'type' => 'int', 275 | 'nulls' => false, 276 | 'default' => null, 277 | 'length' => null, 278 | ], 279 | 'name' => [ 280 | 'name' => 'name', 281 | 'type' => 'varchar', 282 | 'nulls' => false, 283 | 'default' => null, 284 | 'length' => '255', 285 | ], 286 | ], 287 | 'primary_key' => [ 288 | 'PRIMARY' => [ 289 | 'columns' => [ 290 | 0 => 'id', 291 | ], 292 | ], 293 | ], 294 | 'unique_keys' => [ 295 | 'name' => [ 296 | 'columns' => [ 297 | 0 => 'name', 298 | ], 299 | ], 300 | ], 301 | 'foreign_keys' => [ 302 | ], 303 | 'indices' => [ 304 | ], 305 | 'auto_increment' => true, 306 | ], 307 | 'users' => [ 308 | 'schema' => '', 309 | 'name' => 'users', 310 | 'columns' => [ 311 | 'email' => [ 312 | 'name' => 'email', 313 | 'type' => 'varchar', 314 | 'nulls' => false, 315 | 'default' => null, 316 | 'length' => '255', 317 | ], 318 | 'firstname' => [ 319 | 'name' => 'firstname', 320 | 'type' => 'varchar', 321 | 'nulls' => false, 322 | 'default' => null, 323 | 'length' => '255', 324 | ], 325 | 'id' => [ 326 | 'name' => 'id', 327 | 'type' => 'int', 328 | 'nulls' => false, 329 | 'default' => null, 330 | 'length' => null, 331 | ], 332 | 'is_admin' => [ 333 | 'name' => 'is_admin', 334 | 'type' => 'tinyint', 335 | 'nulls' => true, 336 | 'default' => null, 337 | 'length' => null, 338 | ], 339 | 'lastname' => [ 340 | 'name' => 'lastname', 341 | 'type' => 'varchar', 342 | 'nulls' => false, 343 | 'default' => null, 344 | 'length' => '255', 345 | ], 346 | 'last_login_time' => [ 347 | 'name' => 'last_login_time', 348 | 'type' => 'timestamp', 349 | 'nulls' => true, 350 | 'default' => null, 351 | 'length' => null, 352 | ], 353 | 'office' => [ 354 | 'name' => 'office', 355 | 'type' => 'int', 356 | 'nulls' => true, 357 | 'default' => null, 358 | 'length' => null, 359 | ], 360 | 'othernames' => [ 361 | 'name' => 'othernames', 362 | 'type' => 'varchar', 363 | 'nulls' => true, 364 | 'default' => 'None', 365 | 'length' => 255, 366 | ], 367 | 'password' => [ 368 | 'name' => 'password', 369 | 'type' => 'varchar', 370 | 'nulls' => false, 371 | 'default' => null, 372 | 'length' => '255', 373 | ], 374 | 'phone' => [ 375 | 'name' => 'phone', 376 | 'type' => 'varchar', 377 | 'nulls' => true, 378 | 'default' => null, 379 | 'length' => '64', 380 | ], 381 | 'role_id' => [ 382 | 'name' => 'role_id', 383 | 'type' => 'int', 384 | 'nulls' => false, 385 | 'default' => null, 386 | 'length' => null, 387 | ], 388 | 'status' => [ 389 | 'name' => 'status', 390 | 'type' => 'int', 391 | 'nulls' => false, 392 | 'default' => '2', 393 | 'length' => null, 394 | ], 395 | 'username' => [ 396 | 'name' => 'username', 397 | 'type' => 'varchar', 398 | 'nulls' => false, 399 | 'default' => null, 400 | 'length' => '255', 401 | ], 402 | ], 403 | 'primary_key' => [ 404 | 'PRIMARY' => [ 405 | 'columns' => [ 406 | 0 => 'id', 407 | ], 408 | ], 409 | ], 410 | 'unique_keys' => [ 411 | ], 412 | 'foreign_keys' => [ 413 | 'user_role_fk' => [ 414 | 'schema' => '', 415 | 'table' => 'users', 416 | 'columns' => [ 417 | 0 => 'role_id', 418 | ], 419 | 'foreign_table' => 'roles', 420 | 'foreign_schema' => '', 421 | 'foreign_columns' => [ 422 | 0 => 'id', 423 | ], 424 | 'on_update' => 'NO ACTION', 425 | 'on_delete' => 'NO ACTION', 426 | ], 427 | ], 428 | 'indices' => [ 429 | ], 430 | 'auto_increment' => true, 431 | ], 432 | ], 433 | ]; 434 | -------------------------------------------------------------------------------- /tests/expected/mysql/database_description_clean_defaults.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'atiaa_test' => [ 30 | 'name' => 'atiaa_test', 31 | 'tables' => [ 32 | 'departments' => [ 33 | 'schema' => '', 34 | 'name' => 'departments', 35 | 'columns' => [ 36 | 'id' => [ 37 | 'name' => 'id', 38 | 'type' => 'int', 39 | 'nulls' => false, 40 | 'default' => null, 41 | 'length' => null, 42 | ], 43 | 'name' => [ 44 | 'name' => 'name', 45 | 'type' => 'varchar', 46 | 'nulls' => false, 47 | 'default' => null, 48 | 'length' => '255', 49 | ], 50 | ], 51 | 'primary_key' => [ 52 | 'PRIMARY' => [ 53 | 'columns' => [ 54 | 0 => 'id', 55 | ], 56 | ], 57 | ], 58 | 'unique_keys' => [ 59 | ], 60 | 'foreign_keys' => [ 61 | ], 62 | 'indices' => [ 63 | ], 64 | 'auto_increment' => true, 65 | ], 66 | 'roles' => [ 67 | 'schema' => '', 68 | 'name' => 'roles', 69 | 'columns' => [ 70 | 'id' => [ 71 | 'name' => 'id', 72 | 'type' => 'int', 73 | 'nulls' => false, 74 | 'default' => null, 75 | 'length' => null, 76 | ], 77 | 'name' => [ 78 | 'name' => 'name', 79 | 'type' => 'varchar', 80 | 'nulls' => false, 81 | 'default' => null, 82 | 'length' => '255', 83 | ], 84 | ], 85 | 'primary_key' => [ 86 | 'PRIMARY' => [ 87 | 'columns' => [ 88 | 0 => 'id', 89 | ], 90 | ], 91 | ], 92 | 'unique_keys' => [ 93 | 'name' => [ 94 | 'columns' => [ 95 | 0 => 'name', 96 | ], 97 | ], 98 | ], 99 | 'foreign_keys' => [ 100 | ], 101 | 'indices' => [ 102 | ], 103 | 'auto_increment' => true, 104 | ], 105 | 'users' => [ 106 | 'schema' => '', 107 | 'name' => 'users', 108 | 'columns' => [ 109 | 'email' => [ 110 | 'name' => 'email', 111 | 'type' => 'varchar', 112 | 'nulls' => false, 113 | 'default' => null, 114 | 'length' => '255', 115 | ], 116 | 'firstname' => [ 117 | 'name' => 'firstname', 118 | 'type' => 'varchar', 119 | 'nulls' => false, 120 | 'default' => null, 121 | 'length' => '255', 122 | ], 123 | 'id' => [ 124 | 'name' => 'id', 125 | 'type' => 'int', 126 | 'nulls' => false, 127 | 'default' => null, 128 | 'length' => null, 129 | ], 130 | 'is_admin' => [ 131 | 'name' => 'is_admin', 132 | 'type' => 'tinyint', 133 | 'nulls' => true, 134 | 'default' => null, 135 | 'length' => null, 136 | ], 137 | 'lastname' => [ 138 | 'name' => 'lastname', 139 | 'type' => 'varchar', 140 | 'nulls' => false, 141 | 'default' => null, 142 | 'length' => '255', 143 | ], 144 | 'last_login_time' => [ 145 | 'name' => 'last_login_time', 146 | 'type' => 'timestamp', 147 | 'nulls' => true, 148 | 'default' => null, 149 | 'length' => null, 150 | ], 151 | 'office' => [ 152 | 'name' => 'office', 153 | 'type' => 'int', 154 | 'nulls' => true, 155 | 'default' => null, 156 | 'length' => null, 157 | ], 158 | 'othernames' => [ 159 | 'name' => 'othernames', 160 | 'type' => 'varchar', 161 | 'nulls' => true, 162 | 'default' => 'None', 163 | 'length' => 255, 164 | ], 165 | 'password' => [ 166 | 'name' => 'password', 167 | 'type' => 'varchar', 168 | 'nulls' => false, 169 | 'default' => null, 170 | 'length' => '255', 171 | ], 172 | 'phone' => [ 173 | 'name' => 'phone', 174 | 'type' => 'varchar', 175 | 'nulls' => true, 176 | 'default' => null, 177 | 'length' => '64', 178 | ], 179 | 'role_id' => [ 180 | 'name' => 'role_id', 181 | 'type' => 'int', 182 | 'nulls' => false, 183 | 'default' => null, 184 | 'length' => null, 185 | ], 186 | 'status' => [ 187 | 'name' => 'status', 188 | 'type' => 'int', 189 | 'nulls' => false, 190 | 'default' => '2', 191 | 'length' => null, 192 | ], 193 | 'username' => [ 194 | 'name' => 'username', 195 | 'type' => 'varchar', 196 | 'nulls' => false, 197 | 'default' => null, 198 | 'length' => '255', 199 | ], 200 | ], 201 | 'primary_key' => [ 202 | 'PRIMARY' => [ 203 | 'columns' => [ 204 | 0 => 'id', 205 | ], 206 | ], 207 | ], 208 | 'unique_keys' => [ 209 | ], 210 | 'foreign_keys' => [ 211 | 'user_role_fk' => [ 212 | 'schema' => '', 213 | 'table' => 'users', 214 | 'columns' => [ 215 | 0 => 'role_id', 216 | ], 217 | 'foreign_table' => 'roles', 218 | 'foreign_schema' => '', 219 | 'foreign_columns' => [ 220 | 0 => 'id', 221 | ], 222 | 'on_update' => 'NO ACTION', 223 | 'on_delete' => 'NO ACTION', 224 | ], 225 | ], 226 | 'indices' => [ 227 | ], 228 | 'auto_increment' => true, 229 | ] 230 | ] 231 | ] 232 | ], 233 | 'tables' => [ 234 | 'departments' => [ 235 | 'schema' => '', 236 | 'name' => 'departments', 237 | 'columns' => [ 238 | 'id' => [ 239 | 'name' => 'id', 240 | 'type' => 'int', 241 | 'nulls' => false, 242 | 'default' => null, 243 | 'length' => null, 244 | ], 245 | 'name' => [ 246 | 'name' => 'name', 247 | 'type' => 'varchar', 248 | 'nulls' => false, 249 | 'default' => null, 250 | 'length' => '255', 251 | ], 252 | ], 253 | 'primary_key' => [ 254 | 'PRIMARY' => [ 255 | 'columns' => [ 256 | 0 => 'id', 257 | ], 258 | ], 259 | ], 260 | 'unique_keys' => [ 261 | ], 262 | 'foreign_keys' => [ 263 | ], 264 | 'indices' => [ 265 | ], 266 | 'auto_increment' => true, 267 | ], 268 | 'roles' => [ 269 | 'schema' => '', 270 | 'name' => 'roles', 271 | 'columns' => [ 272 | 'id' => [ 273 | 'name' => 'id', 274 | 'type' => 'int', 275 | 'nulls' => false, 276 | 'default' => null, 277 | 'length' => null, 278 | ], 279 | 'name' => [ 280 | 'name' => 'name', 281 | 'type' => 'varchar', 282 | 'nulls' => false, 283 | 'default' => null, 284 | 'length' => '255', 285 | ], 286 | ], 287 | 'primary_key' => [ 288 | 'PRIMARY' => [ 289 | 'columns' => [ 290 | 0 => 'id', 291 | ], 292 | ], 293 | ], 294 | 'unique_keys' => [ 295 | 'name' => [ 296 | 'columns' => [ 297 | 0 => 'name', 298 | ], 299 | ], 300 | ], 301 | 'foreign_keys' => [ 302 | ], 303 | 'indices' => [ 304 | ], 305 | 'auto_increment' => true, 306 | ], 307 | 'users' => [ 308 | 'schema' => '', 309 | 'name' => 'users', 310 | 'columns' => [ 311 | 'email' => [ 312 | 'name' => 'email', 313 | 'type' => 'varchar', 314 | 'nulls' => false, 315 | 'default' => null, 316 | 'length' => '255', 317 | ], 318 | 'firstname' => [ 319 | 'name' => 'firstname', 320 | 'type' => 'varchar', 321 | 'nulls' => false, 322 | 'default' => null, 323 | 'length' => '255', 324 | ], 325 | 'id' => [ 326 | 'name' => 'id', 327 | 'type' => 'int', 328 | 'nulls' => false, 329 | 'default' => null, 330 | 'length' => null, 331 | ], 332 | 'is_admin' => [ 333 | 'name' => 'is_admin', 334 | 'type' => 'tinyint', 335 | 'nulls' => true, 336 | 'default' => null, 337 | 'length' => null, 338 | ], 339 | 'lastname' => [ 340 | 'name' => 'lastname', 341 | 'type' => 'varchar', 342 | 'nulls' => false, 343 | 'default' => null, 344 | 'length' => '255', 345 | ], 346 | 'last_login_time' => [ 347 | 'name' => 'last_login_time', 348 | 'type' => 'timestamp', 349 | 'nulls' => true, 350 | 'default' => null, 351 | 'length' => null, 352 | ], 353 | 'office' => [ 354 | 'name' => 'office', 355 | 'type' => 'int', 356 | 'nulls' => true, 357 | 'default' => null, 358 | 'length' => null, 359 | ], 360 | 'othernames' => [ 361 | 'name' => 'othernames', 362 | 'type' => 'varchar', 363 | 'nulls' => true, 364 | 'default' => 'None', 365 | 'length' => 255, 366 | ], 367 | 'password' => [ 368 | 'name' => 'password', 369 | 'type' => 'varchar', 370 | 'nulls' => false, 371 | 'default' => null, 372 | 'length' => '255', 373 | ], 374 | 'phone' => [ 375 | 'name' => 'phone', 376 | 'type' => 'varchar', 377 | 'nulls' => true, 378 | 'default' => null, 379 | 'length' => '64', 380 | ], 381 | 'role_id' => [ 382 | 'name' => 'role_id', 383 | 'type' => 'int', 384 | 'nulls' => false, 385 | 'default' => null, 386 | 'length' => null, 387 | ], 388 | 'status' => [ 389 | 'name' => 'status', 390 | 'type' => 'int', 391 | 'nulls' => false, 392 | 'default' => '2', 393 | 'length' => null, 394 | ], 395 | 'username' => [ 396 | 'name' => 'username', 397 | 'type' => 'varchar', 398 | 'nulls' => false, 399 | 'default' => null, 400 | 'length' => '255', 401 | ], 402 | ], 403 | 'primary_key' => [ 404 | 'PRIMARY' => [ 405 | 'columns' => [ 406 | 0 => 'id', 407 | ], 408 | ], 409 | ], 410 | 'unique_keys' => [ 411 | ], 412 | 'foreign_keys' => [ 413 | 'user_role_fk' => [ 414 | 'schema' => '', 415 | 'table' => 'users', 416 | 'columns' => [ 417 | 0 => 'role_id', 418 | ], 419 | 'foreign_table' => 'roles', 420 | 'foreign_schema' => '', 421 | 'foreign_columns' => [ 422 | 0 => 'id', 423 | ], 424 | 'on_update' => 'NO ACTION', 425 | 'on_delete' => 'NO ACTION', 426 | ], 427 | ], 428 | 'indices' => [ 429 | ], 430 | 'auto_increment' => true, 431 | ], 432 | ], 433 | ]; 434 | -------------------------------------------------------------------------------- /tests/expected/mysql/strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "quoted_string": "'string'", 3 | "quoted_identifier" : "`identifier`", 4 | "quoted_query_identifiers" : "SELECT `some`, `identifiers` FROM `some`.`table`" 5 | } 6 | -------------------------------------------------------------------------------- /tests/expected/mysql/view_description.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'schema' => '', 30 | 'name' => 'users_view', 31 | 'columns' => [ 32 | 'email' => [ 33 | 'name' => 'email', 34 | 'type' => 'varchar', 35 | 'nulls' => false, 36 | 'default' => null, 37 | 'length' => '255', 38 | ], 39 | 'firstname' => [ 40 | 'name' => 'firstname', 41 | 'type' => 'varchar', 42 | 'nulls' => false, 43 | 'default' => null, 44 | 'length' => '255', 45 | ], 46 | 'id' => [ 47 | 'name' => 'id', 48 | 'type' => 'int', 49 | 'nulls' => false, 50 | 'default' => '0', 51 | 'length' => null, 52 | ], 53 | 'lastname' => [ 54 | 'name' => 'lastname', 55 | 'type' => 'varchar', 56 | 'nulls' => false, 57 | 'default' => null, 58 | 'length' => '255', 59 | ], 60 | 'othernames' => [ 61 | 'name' => 'othernames', 62 | 'type' => 'varchar', 63 | 'nulls' => true, 64 | 'default' => 'None', 65 | 'length' => 255, 66 | ], 67 | 'password' => [ 68 | 'name' => 'password', 69 | 'type' => 'varchar', 70 | 'nulls' => false, 71 | 'default' => null, 72 | 'length' => '255', 73 | ], 74 | 'role' => [ 75 | 'name' => 'role', 76 | 'type' => 'varchar', 77 | 'nulls' => false, 78 | 'default' => null, 79 | 'length' => '255', 80 | ], 81 | 'username' => [ 82 | 'name' => 'username', 83 | 'type' => 'varchar', 84 | 'nulls' => false, 85 | 'default' => null, 86 | 'length' => '255', 87 | ], 88 | ], 89 | 'primary_key' => [ 90 | ], 91 | 'unique_keys' => [ 92 | ], 93 | 'foreign_keys' => [ 94 | ], 95 | 'indices' => [ 96 | ], 97 | 'auto_increment' => false, 98 | ], 99 | ]; 100 | -------------------------------------------------------------------------------- /tests/expected/postgresql/database_description_clean_defaults.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'public' => [ 30 | 'name' => 'public', 31 | 'tables' => [ 32 | 'departments' => [ 33 | 'schema' => '', 34 | 'name' => 'departments', 35 | 'columns' => [ 36 | 'id' => [ 37 | 'name' => 'id', 38 | 'type' => 'integer', 39 | 'nulls' => false, 40 | 'default' => null, 41 | 'length' => null, 42 | ], 43 | 'name' => [ 44 | 'name' => 'name', 45 | 'type' => 'character varying', 46 | 'nulls' => false, 47 | 'default' => null, 48 | 'length' => 255, 49 | ], 50 | ], 51 | 'primary_key' => [ 52 | 'departments_pkey' => [ 53 | 'columns' => [ 54 | 0 => 'id', 55 | ], 56 | ], 57 | ], 58 | 'unique_keys' => [ 59 | ], 60 | 'foreign_keys' => [ 61 | ], 62 | 'indices' => [ 63 | ], 64 | 'auto_increment' => true, 65 | ], 66 | 'roles' => [ 67 | 'schema' => '', 68 | 'name' => 'roles', 69 | 'columns' => [ 70 | 'id' => [ 71 | 'name' => 'id', 72 | 'type' => 'integer', 73 | 'nulls' => false, 74 | 'default' => null, 75 | 'length' => null, 76 | ], 77 | 'name' => [ 78 | 'name' => 'name', 79 | 'type' => 'character varying', 80 | 'nulls' => false, 81 | 'default' => null, 82 | 'length' => 255, 83 | ], 84 | ], 85 | 'primary_key' => [ 86 | 'roles_pkey' => [ 87 | 'columns' => [ 88 | 0 => 'id', 89 | ], 90 | ], 91 | ], 92 | 'unique_keys' => [ 93 | ], 94 | 'foreign_keys' => [ 95 | ], 96 | 'indices' => [ 97 | ], 98 | 'auto_increment' => true, 99 | ], 100 | 'users' => [ 101 | 'schema' => '', 102 | 'name' => 'users', 103 | 'columns' => [ 104 | 'email' => [ 105 | 'name' => 'email', 106 | 'type' => 'character varying', 107 | 'nulls' => false, 108 | 'default' => null, 109 | 'length' => 255, 110 | ], 111 | 'firstname' => [ 112 | 'name' => 'firstname', 113 | 'type' => 'character varying', 114 | 'nulls' => false, 115 | 'default' => null, 116 | 'length' => 255, 117 | ], 118 | 'id' => [ 119 | 'name' => 'id', 120 | 'type' => 'integer', 121 | 'nulls' => false, 122 | 'default' => null, 123 | 'length' => null, 124 | ], 125 | 'is_admin' => [ 126 | 'name' => 'is_admin', 127 | 'type' => 'boolean', 128 | 'nulls' => true, 129 | 'default' => null, 130 | 'length' => null, 131 | ], 132 | 'last_login_time' => [ 133 | 'name' => 'last_login_time', 134 | 'type' => 'timestamp without time zone', 135 | 'nulls' => true, 136 | 'default' => null, 137 | 'length' => null, 138 | ], 139 | 'lastname' => [ 140 | 'name' => 'lastname', 141 | 'type' => 'character varying', 142 | 'nulls' => false, 143 | 'default' => null, 144 | 'length' => 255, 145 | ], 146 | 'office' => [ 147 | 'name' => 'office', 148 | 'type' => 'integer', 149 | 'nulls' => true, 150 | 'default' => null, 151 | 'length' => null, 152 | ], 153 | 'othernames' => [ 154 | 'name' => 'othernames', 155 | 'type' => 'character varying', 156 | 'nulls' => true, 157 | 'default' => 'None', 158 | 'length' => 255, 159 | ], 160 | 'password' => [ 161 | 'name' => 'password', 162 | 'type' => 'character varying', 163 | 'nulls' => false, 164 | 'default' => null, 165 | 'length' => 255, 166 | ], 167 | 'phone' => [ 168 | 'name' => 'phone', 169 | 'type' => 'character varying', 170 | 'nulls' => true, 171 | 'default' => null, 172 | 'length' => 64, 173 | ], 174 | 'role_id' => [ 175 | 'name' => 'role_id', 176 | 'type' => 'integer', 177 | 'nulls' => false, 178 | 'default' => null, 179 | 'length' => null, 180 | ], 181 | 'status' => [ 182 | 'name' => 'status', 183 | 'type' => 'integer', 184 | 'nulls' => false, 185 | 'default' => '2', 186 | 'length' => null, 187 | ], 188 | 'username' => [ 189 | 'name' => 'username', 190 | 'type' => 'character varying', 191 | 'nulls' => false, 192 | 'default' => null, 193 | 'length' => 255, 194 | ], 195 | ], 196 | 'primary_key' => [ 197 | 'users_pkey' => [ 198 | 'columns' => [ 199 | 0 => 'id', 200 | ], 201 | ], 202 | ], 203 | 'unique_keys' => [ 204 | ], 205 | 'foreign_keys' => [ 206 | 'users_office_fkey' => [ 207 | 'schema' => '', 208 | 'table' => 'users', 209 | 'columns' => [ 210 | 0 => 'office', 211 | ], 212 | 'foreign_table' => 'departments', 213 | 'foreign_schema' => '', 214 | 'foreign_columns' => [ 215 | 0 => 'id', 216 | ], 217 | 'on_update' => 'NO ACTION', 218 | 'on_delete' => 'NO ACTION', 219 | ], 220 | 'users_role_id_fkey' => [ 221 | 'schema' => '', 222 | 'table' => 'users', 223 | 'columns' => [ 224 | 0 => 'role_id', 225 | ], 226 | 'foreign_table' => 'roles', 227 | 'foreign_schema' => '', 228 | 'foreign_columns' => [ 229 | 0 => 'id', 230 | ], 231 | 'on_update' => 'NO ACTION', 232 | 'on_delete' => 'NO ACTION', 233 | ], 234 | ], 235 | 'indices' => [ 236 | ], 237 | 'auto_increment' => true, 238 | ] 239 | ] 240 | ], 241 | 'crm' => [ 242 | 'name' => 'crm', 243 | 'tables' => [ 244 | 'customers' => [ 245 | 'schema' => 'crm', 246 | 'name' => 'customers', 247 | 'columns' => [ 248 | 'employee_id' => [ 249 | 'name' => 'employee_id', 250 | 'type' => 'integer', 251 | 'nulls' => false, 252 | 'default' => null, 253 | 'length' => null, 254 | ], 255 | 'id' => [ 256 | 'name' => 'id', 257 | 'type' => 'integer', 258 | 'nulls' => false, 259 | 'default' => null, 260 | 'length' => null, 261 | ], 262 | 'name' => [ 263 | 'name' => 'name', 264 | 'type' => 'character varying', 265 | 'nulls' => false, 266 | 'default' => null, 267 | 'length' => 255, 268 | ], 269 | ], 270 | 'primary_key' => [ 271 | 'customers_pkey' => [ 272 | 'columns' => [ 273 | 0 => 'id', 274 | ], 275 | ], 276 | ], 277 | 'unique_keys' => [ 278 | ], 279 | 'foreign_keys' => [ 280 | 'customers_employee_id_fkey' => [ 281 | 'schema' => 'crm', 282 | 'table' => 'customers', 283 | 'columns' => [ 284 | 0 => 'employee_id', 285 | ], 286 | 'foreign_table' => 'employees', 287 | 'foreign_schema' => 'hr', 288 | 'foreign_columns' => [ 289 | 0 => 'id', 290 | ], 291 | 'on_update' => 'NO ACTION', 292 | 'on_delete' => 'NO ACTION', 293 | ], 294 | ], 295 | 'indices' => [ 296 | ], 297 | 'auto_increment' => true, 298 | ], 299 | ], 300 | 'views' => [ 301 | ], 302 | ], 303 | 'hr' => [ 304 | 'name' => 'hr', 305 | 'tables' => [ 306 | 'categories' => [ 307 | 'schema' => 'hr', 308 | 'name' => 'categories', 309 | 'columns' => [ 310 | 'id' => [ 311 | 'name' => 'id', 312 | 'type' => 'integer', 313 | 'nulls' => false, 314 | 'default' => null, 315 | 'length' => null, 316 | ], 317 | 'name' => [ 318 | 'name' => 'name', 319 | 'type' => 'character varying', 320 | 'nulls' => false, 321 | 'default' => null, 322 | 'length' => 255, 323 | ], 324 | ], 325 | 'primary_key' => [ 326 | 'departments_pkey' => [ 327 | 'columns' => [ 328 | 0 => 'id', 329 | ], 330 | ], 331 | ], 332 | 'unique_keys' => [ 333 | ], 334 | 'foreign_keys' => [ 335 | ], 336 | 'indices' => [ 337 | ], 338 | 'auto_increment' => true, 339 | ], 340 | 'employees' => [ 341 | 'schema' => 'hr', 342 | 'name' => 'employees', 343 | 'columns' => [ 344 | 'date_of_birth' => [ 345 | 'name' => 'date_of_birth', 346 | 'type' => 'date', 347 | 'nulls' => true, 348 | 'default' => null, 349 | 'length' => null, 350 | ], 351 | 'firstname' => [ 352 | 'name' => 'firstname', 353 | 'type' => 'character varying', 354 | 'nulls' => false, 355 | 'default' => null, 356 | 'length' => 255, 357 | ], 358 | 'id' => [ 359 | 'name' => 'id', 360 | 'type' => 'integer', 361 | 'nulls' => false, 362 | 'default' => null, 363 | 'length' => null, 364 | ], 365 | 'lastname' => [ 366 | 'name' => 'lastname', 367 | 'type' => 'character varying', 368 | 'nulls' => true, 369 | 'default' => null, 370 | 'length' => 255, 371 | ], 372 | ], 373 | 'primary_key' => [ 374 | 'employees_pkey' => [ 375 | 'columns' => [ 376 | 0 => 'id', 377 | ], 378 | ], 379 | ], 380 | 'unique_keys' => [ 381 | ], 382 | 'foreign_keys' => [ 383 | ], 384 | 'indices' => [ 385 | ], 386 | 'auto_increment' => true, 387 | ], 388 | ], 389 | 'views' => [ 390 | ], 391 | ], 392 | ], 393 | 'tables' => [ 394 | 'departments' => [ 395 | 'schema' => '', 396 | 'name' => 'departments', 397 | 'columns' => [ 398 | 'id' => [ 399 | 'name' => 'id', 400 | 'type' => 'integer', 401 | 'nulls' => false, 402 | 'default' => null, 403 | 'length' => null, 404 | ], 405 | 'name' => [ 406 | 'name' => 'name', 407 | 'type' => 'character varying', 408 | 'nulls' => false, 409 | 'default' => null, 410 | 'length' => 255, 411 | ], 412 | ], 413 | 'primary_key' => [ 414 | 'departments_pkey' => [ 415 | 'columns' => [ 416 | 0 => 'id', 417 | ], 418 | ], 419 | ], 420 | 'unique_keys' => [ 421 | ], 422 | 'foreign_keys' => [ 423 | ], 424 | 'indices' => [ 425 | ], 426 | 'auto_increment' => true, 427 | ], 428 | 'roles' => [ 429 | 'schema' => '', 430 | 'name' => 'roles', 431 | 'columns' => [ 432 | 'id' => [ 433 | 'name' => 'id', 434 | 'type' => 'integer', 435 | 'nulls' => false, 436 | 'default' => null, 437 | 'length' => null, 438 | ], 439 | 'name' => [ 440 | 'name' => 'name', 441 | 'type' => 'character varying', 442 | 'nulls' => false, 443 | 'default' => null, 444 | 'length' => 255, 445 | ], 446 | ], 447 | 'primary_key' => [ 448 | 'roles_pkey' => [ 449 | 'columns' => [ 450 | 0 => 'id', 451 | ], 452 | ], 453 | ], 454 | 'unique_keys' => [ 455 | ], 456 | 'foreign_keys' => [ 457 | ], 458 | 'indices' => [ 459 | ], 460 | 'auto_increment' => true, 461 | ], 462 | 'users' => [ 463 | 'schema' => '', 464 | 'name' => 'users', 465 | 'columns' => [ 466 | 'email' => [ 467 | 'name' => 'email', 468 | 'type' => 'character varying', 469 | 'nulls' => false, 470 | 'default' => null, 471 | 'length' => 255, 472 | ], 473 | 'firstname' => [ 474 | 'name' => 'firstname', 475 | 'type' => 'character varying', 476 | 'nulls' => false, 477 | 'default' => null, 478 | 'length' => 255, 479 | ], 480 | 'id' => [ 481 | 'name' => 'id', 482 | 'type' => 'integer', 483 | 'nulls' => false, 484 | 'default' => null, 485 | 'length' => null, 486 | ], 487 | 'is_admin' => [ 488 | 'name' => 'is_admin', 489 | 'type' => 'boolean', 490 | 'nulls' => true, 491 | 'default' => null, 492 | 'length' => null, 493 | ], 494 | 'last_login_time' => [ 495 | 'name' => 'last_login_time', 496 | 'type' => 'timestamp without time zone', 497 | 'nulls' => true, 498 | 'default' => null, 499 | 'length' => null, 500 | ], 501 | 'lastname' => [ 502 | 'name' => 'lastname', 503 | 'type' => 'character varying', 504 | 'nulls' => false, 505 | 'default' => null, 506 | 'length' => 255, 507 | ], 508 | 'office' => [ 509 | 'name' => 'office', 510 | 'type' => 'integer', 511 | 'nulls' => true, 512 | 'default' => null, 513 | 'length' => null, 514 | ], 515 | 'othernames' => [ 516 | 'name' => 'othernames', 517 | 'type' => 'character varying', 518 | 'nulls' => true, 519 | 'default' => 'None', 520 | 'length' => 255, 521 | ], 522 | 'password' => [ 523 | 'name' => 'password', 524 | 'type' => 'character varying', 525 | 'nulls' => false, 526 | 'default' => null, 527 | 'length' => 255, 528 | ], 529 | 'phone' => [ 530 | 'name' => 'phone', 531 | 'type' => 'character varying', 532 | 'nulls' => true, 533 | 'default' => null, 534 | 'length' => 64, 535 | ], 536 | 'role_id' => [ 537 | 'name' => 'role_id', 538 | 'type' => 'integer', 539 | 'nulls' => false, 540 | 'default' => null, 541 | 'length' => null, 542 | ], 543 | 'status' => [ 544 | 'name' => 'status', 545 | 'type' => 'integer', 546 | 'nulls' => false, 547 | 'default' => '2', 548 | 'length' => null, 549 | ], 550 | 'username' => [ 551 | 'name' => 'username', 552 | 'type' => 'character varying', 553 | 'nulls' => false, 554 | 'default' => null, 555 | 'length' => 255, 556 | ], 557 | ], 558 | 'primary_key' => [ 559 | 'users_pkey' => [ 560 | 'columns' => [ 561 | 0 => 'id', 562 | ], 563 | ], 564 | ], 565 | 'unique_keys' => [ 566 | ], 567 | 'foreign_keys' => [ 568 | 'users_office_fkey' => [ 569 | 'schema' => '', 570 | 'table' => 'users', 571 | 'columns' => [ 572 | 0 => 'office', 573 | ], 574 | 'foreign_table' => 'departments', 575 | 'foreign_schema' => '', 576 | 'foreign_columns' => [ 577 | 0 => 'id', 578 | ], 579 | 'on_update' => 'NO ACTION', 580 | 'on_delete' => 'NO ACTION', 581 | ], 582 | 'users_role_id_fkey' => [ 583 | 'schema' => '', 584 | 'table' => 'users', 585 | 'columns' => [ 586 | 0 => 'role_id', 587 | ], 588 | 'foreign_table' => 'roles', 589 | 'foreign_schema' => '', 590 | 'foreign_columns' => [ 591 | 0 => 'id', 592 | ], 593 | 'on_update' => 'NO ACTION', 594 | 'on_delete' => 'NO ACTION', 595 | ], 596 | ], 597 | 'indices' => [ 598 | ], 599 | 'auto_increment' => true, 600 | ], 601 | ], 602 | ]; 603 | -------------------------------------------------------------------------------- /tests/expected/postgresql/employees_description.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'schema' => 'hr', 30 | 'name' => 'employees', 31 | 'columns' => [ 32 | 'date_of_birth' => [ 33 | 'name' => 'date_of_birth', 34 | 'type' => 'date', 35 | 'nulls' => true, 36 | 'default' => null, 37 | 'length' => null, 38 | ], 39 | 'firstname' => [ 40 | 'name' => 'firstname', 41 | 'type' => 'character varying', 42 | 'nulls' => false, 43 | 'default' => null, 44 | 'length' => 255, 45 | ], 46 | 'id' => [ 47 | 'name' => 'id', 48 | 'type' => 'integer', 49 | 'nulls' => false, 50 | 'default' => null, 51 | 'length' => null, 52 | ], 53 | 'lastname' => [ 54 | 'name' => 'lastname', 55 | 'type' => 'character varying', 56 | 'nulls' => true, 57 | 'default' => null, 58 | 'length' => 255, 59 | ], 60 | ], 61 | 'primary_key' => [ 62 | 'employees_pkey' => [ 63 | 'columns' => [ 64 | 0 => 'id', 65 | ], 66 | ], 67 | ], 68 | 'unique_keys' => [ 69 | ], 70 | 'foreign_keys' => [ 71 | ], 72 | 'indices' => [ 73 | ], 74 | 'auto_increment' => true, 75 | ], 76 | ]; 77 | -------------------------------------------------------------------------------- /tests/expected/postgresql/strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "quoted_string": "'string'", 3 | "quoted_identifier" : "\"identifier\"", 4 | "quoted_query_identifiers" : "SELECT \"some\", \"identifiers\" FROM \"some\".\"table\"" 5 | } 6 | -------------------------------------------------------------------------------- /tests/expected/postgresql/view_description.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'schema' => '', 30 | 'name' => 'users_view', 31 | 'columns' => [ 32 | 'email' => [ 33 | 'name' => 'email', 34 | 'type' => 'character varying', 35 | 'nulls' => true, 36 | 'default' => null, 37 | 'length' => 255, 38 | ], 39 | 'firstname' => [ 40 | 'name' => 'firstname', 41 | 'type' => 'character varying', 42 | 'nulls' => true, 43 | 'default' => null, 44 | 'length' => 255, 45 | ], 46 | 'id' => [ 47 | 'name' => 'id', 48 | 'type' => 'integer', 49 | 'nulls' => true, 50 | 'default' => null, 51 | 'length' => null, 52 | ], 53 | 'lastname' => [ 54 | 'name' => 'lastname', 55 | 'type' => 'character varying', 56 | 'nulls' => true, 57 | 'default' => null, 58 | 'length' => 255, 59 | ], 60 | 'othernames' => [ 61 | 'name' => 'othernames', 62 | 'type' => 'character varying', 63 | 'nulls' => true, 64 | 'default' => null, 65 | 'length' => 255, 66 | ], 67 | 'password' => [ 68 | 'name' => 'password', 69 | 'type' => 'character varying', 70 | 'nulls' => true, 71 | 'default' => null, 72 | 'length' => 255, 73 | ], 74 | 'role' => [ 75 | 'name' => 'role', 76 | 'type' => 'character varying', 77 | 'nulls' => true, 78 | 'default' => null, 79 | 'length' => 255, 80 | ], 81 | 'username' => [ 82 | 'name' => 'username', 83 | 'type' => 'character varying', 84 | 'nulls' => true, 85 | 'default' => null, 86 | 'length' => 255, 87 | ], 88 | ], 89 | 'primary_key' => [ 90 | ], 91 | 'unique_keys' => [ 92 | ], 93 | 'foreign_keys' => [ 94 | ], 95 | 'indices' => [ 96 | ], 97 | 'auto_increment' => false, 98 | ], 99 | ]; 100 | -------------------------------------------------------------------------------- /tests/expected/sqlite/database_description.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'main' => [ 30 | 'name' => 'main', 31 | 'tables' => [ 32 | 'departments' => [ 33 | 'name' => 'departments', 34 | 'schema' => '', 35 | 'columns' => [ 36 | 'id' => [ 37 | 'name' => 'id', 38 | 'type' => 'INTEGER', 39 | 'nulls' => true, 40 | 'default' => null, 41 | 'length' => null, 42 | ], 43 | 'name' => [ 44 | 'name' => 'name', 45 | 'type' => 'TEXT', 46 | 'nulls' => false, 47 | 'default' => null, 48 | 'length' => null, 49 | ], 50 | ], 51 | 'primary_key' => [ 52 | 'departments_pk' => [ 53 | 'order' => '1', 54 | 'columns' => [ 55 | 0 => 'id', 56 | ], 57 | ], 58 | ], 59 | 'unique_keys' => [ 60 | ], 61 | 'foreign_keys' => [ 62 | ], 63 | 'indices' => [ 64 | ], 65 | 'auto_increment' => true, 66 | ], 67 | 'roles' => [ 68 | 'name' => 'roles', 69 | 'schema' => '', 70 | 'columns' => [ 71 | 'id' => [ 72 | 'name' => 'id', 73 | 'type' => 'INTEGER', 74 | 'nulls' => true, 75 | 'default' => null, 76 | 'length' => null, 77 | ], 78 | 'name' => [ 79 | 'name' => 'name', 80 | 'type' => 'TEXT', 81 | 'nulls' => false, 82 | 'default' => null, 83 | 'length' => null, 84 | ], 85 | ], 86 | 'primary_key' => [ 87 | 'roles_pk' => [ 88 | 'order' => '1', 89 | 'columns' => [ 90 | 0 => 'id', 91 | ], 92 | ], 93 | ], 94 | 'unique_keys' => [ 95 | ], 96 | 'foreign_keys' => [ 97 | ], 98 | 'indices' => [ 99 | ], 100 | 'auto_increment' => true, 101 | ], 102 | 'users' => [ 103 | 'name' => 'users', 104 | 'schema' => '', 105 | 'columns' => [ 106 | 'id' => [ 107 | 'name' => 'id', 108 | 'type' => 'INTEGER', 109 | 'nulls' => false, 110 | 'default' => null, 111 | 'length' => null, 112 | ], 113 | 'username' => [ 114 | 'name' => 'username', 115 | 'type' => 'TEXT', 116 | 'nulls' => false, 117 | 'default' => null, 118 | 'length' => '255', 119 | ], 120 | 'password' => [ 121 | 'name' => 'password', 122 | 'type' => 'TEXT', 123 | 'nulls' => false, 124 | 'default' => null, 125 | 'length' => null, 126 | ], 127 | 'role_id' => [ 128 | 'name' => 'role_id', 129 | 'type' => 'INTEGER', 130 | 'nulls' => false, 131 | 'default' => null, 132 | 'length' => null, 133 | ], 134 | 'firstname' => [ 135 | 'name' => 'firstname', 136 | 'type' => 'TEXT', 137 | 'nulls' => false, 138 | 'default' => null, 139 | 'length' => null, 140 | ], 141 | 'lastname' => [ 142 | 'name' => 'lastname', 143 | 'type' => 'TEXT', 144 | 'nulls' => false, 145 | 'default' => null, 146 | 'length' => null, 147 | ], 148 | 'othernames' => [ 149 | 'name' => 'othernames', 150 | 'type' => 'TEXT', 151 | 'nulls' => true, 152 | 'default' => '\'None\'', 153 | 'length' => null, 154 | ], 155 | 'status' => [ 156 | 'name' => 'status', 157 | 'type' => 'INTEGER', 158 | 'nulls' => true, 159 | 'default' => '\'2\'', 160 | 'length' => null, 161 | ], 162 | 'email' => [ 163 | 'name' => 'email', 164 | 'type' => 'TEXT', 165 | 'nulls' => true, 166 | 'default' => null, 167 | 'length' => null, 168 | ], 169 | 'phone' => [ 170 | 'name' => 'phone', 171 | 'type' => 'TEXT', 172 | 'nulls' => true, 173 | 'default' => null, 174 | 'length' => null, 175 | ], 176 | 'office' => [ 177 | 'name' => 'office', 178 | 'type' => 'INTEGER', 179 | 'nulls' => false, 180 | 'default' => null, 181 | 'length' => null, 182 | ], 183 | 'last_login_time' => [ 184 | 'name' => 'last_login_time', 185 | 'type' => 'TEXT', 186 | 'nulls' => true, 187 | 'default' => null, 188 | 'length' => null, 189 | ], 190 | 'is_admin' => [ 191 | 'name' => 'is_admin', 192 | 'type' => 'INTEGER', 193 | 'nulls' => true, 194 | 'default' => null, 195 | 'length' => null, 196 | ], 197 | ], 198 | 'primary_key' => [ 199 | 'users_pk' => [ 200 | 'order' => '1', 201 | 'columns' => [ 202 | 0 => 'id', 203 | ], 204 | ], 205 | ], 206 | 'unique_keys' => [ 207 | 'sqlite_autoindex_users_1' => [ 208 | 'columns' => [ 209 | 0 => 'username', 210 | ], 211 | 'schema' => '', 212 | ], 213 | ], 214 | 'foreign_keys' => [ 215 | 'users_departments_0_fk' => [ 216 | 'schema' => '', 217 | 'table' => 'users', 218 | 'columns' => [ 219 | 0 => 'office', 220 | ], 221 | 'foreign_table' => 'departments', 222 | 'foreign_schema' => '', 223 | 'foreign_columns' => [ 224 | 0 => 'id', 225 | ], 226 | 'on_update' => 'CASCADE', 227 | 'on_delete' => 'CASCADE', 228 | ], 229 | 'users_roles_1_fk' => [ 230 | 'schema' => '', 231 | 'table' => 'users', 232 | 'columns' => [ 233 | 0 => 'role_id', 234 | ], 235 | 'foreign_table' => 'roles', 236 | 'foreign_schema' => '', 237 | 'foreign_columns' => [ 238 | 0 => 'id', 239 | ], 240 | 'on_update' => 'CASCADE', 241 | 'on_delete' => 'CASCADE', 242 | ], 243 | ], 244 | 'indices' => [ 245 | 'user_email_idx' => [ 246 | 'columns' => [ 247 | 0 => 'email', 248 | ], 249 | 'schema' => '', 250 | ], 251 | ], 252 | 'auto_increment' => true, 253 | ], 254 | ] 255 | ] 256 | ], 257 | 'tables' => [ 258 | 'departments' => [ 259 | 'name' => 'departments', 260 | 'schema' => '', 261 | 'columns' => [ 262 | 'id' => [ 263 | 'name' => 'id', 264 | 'type' => 'INTEGER', 265 | 'nulls' => true, 266 | 'default' => null, 267 | 'length' => null, 268 | ], 269 | 'name' => [ 270 | 'name' => 'name', 271 | 'type' => 'TEXT', 272 | 'nulls' => false, 273 | 'default' => null, 274 | 'length' => null, 275 | ], 276 | ], 277 | 'primary_key' => [ 278 | 'departments_pk' => [ 279 | 'order' => '1', 280 | 'columns' => [ 281 | 0 => 'id', 282 | ], 283 | ], 284 | ], 285 | 'unique_keys' => [ 286 | ], 287 | 'foreign_keys' => [ 288 | ], 289 | 'indices' => [ 290 | ], 291 | 'auto_increment' => true, 292 | ], 293 | 'roles' => [ 294 | 'name' => 'roles', 295 | 'schema' => '', 296 | 'columns' => [ 297 | 'id' => [ 298 | 'name' => 'id', 299 | 'type' => 'INTEGER', 300 | 'nulls' => true, 301 | 'default' => null, 302 | 'length' => null, 303 | ], 304 | 'name' => [ 305 | 'name' => 'name', 306 | 'type' => 'TEXT', 307 | 'nulls' => false, 308 | 'default' => null, 309 | 'length' => null, 310 | ], 311 | ], 312 | 'primary_key' => [ 313 | 'roles_pk' => [ 314 | 'order' => '1', 315 | 'columns' => [ 316 | 0 => 'id', 317 | ], 318 | ], 319 | ], 320 | 'unique_keys' => [ 321 | ], 322 | 'foreign_keys' => [ 323 | ], 324 | 'indices' => [ 325 | ], 326 | 'auto_increment' => true, 327 | ], 328 | 'users' => [ 329 | 'name' => 'users', 330 | 'schema' => '', 331 | 'columns' => [ 332 | 'id' => [ 333 | 'name' => 'id', 334 | 'type' => 'INTEGER', 335 | 'nulls' => false, 336 | 'default' => null, 337 | 'length' => null, 338 | ], 339 | 'username' => [ 340 | 'name' => 'username', 341 | 'type' => 'TEXT', 342 | 'nulls' => false, 343 | 'default' => null, 344 | 'length' => '255', 345 | ], 346 | 'password' => [ 347 | 'name' => 'password', 348 | 'type' => 'TEXT', 349 | 'nulls' => false, 350 | 'default' => null, 351 | 'length' => null, 352 | ], 353 | 'role_id' => [ 354 | 'name' => 'role_id', 355 | 'type' => 'INTEGER', 356 | 'nulls' => false, 357 | 'default' => null, 358 | 'length' => null, 359 | ], 360 | 'firstname' => [ 361 | 'name' => 'firstname', 362 | 'type' => 'TEXT', 363 | 'nulls' => false, 364 | 'default' => null, 365 | 'length' => null, 366 | ], 367 | 'lastname' => [ 368 | 'name' => 'lastname', 369 | 'type' => 'TEXT', 370 | 'nulls' => false, 371 | 'default' => null, 372 | 'length' => null, 373 | ], 374 | 'othernames' => [ 375 | 'name' => 'othernames', 376 | 'type' => 'TEXT', 377 | 'nulls' => true, 378 | 'default' => '\'None\'', 379 | 'length' => null, 380 | ], 381 | 'status' => [ 382 | 'name' => 'status', 383 | 'type' => 'INTEGER', 384 | 'nulls' => true, 385 | 'default' => '\'2\'', 386 | 'length' => null, 387 | ], 388 | 'email' => [ 389 | 'name' => 'email', 390 | 'type' => 'TEXT', 391 | 'nulls' => true, 392 | 'default' => null, 393 | 'length' => null, 394 | ], 395 | 'phone' => [ 396 | 'name' => 'phone', 397 | 'type' => 'TEXT', 398 | 'nulls' => true, 399 | 'default' => null, 400 | 'length' => null, 401 | ], 402 | 'office' => [ 403 | 'name' => 'office', 404 | 'type' => 'INTEGER', 405 | 'nulls' => false, 406 | 'default' => null, 407 | 'length' => null, 408 | ], 409 | 'last_login_time' => [ 410 | 'name' => 'last_login_time', 411 | 'type' => 'TEXT', 412 | 'nulls' => true, 413 | 'default' => null, 414 | 'length' => null, 415 | ], 416 | 'is_admin' => [ 417 | 'name' => 'is_admin', 418 | 'type' => 'INTEGER', 419 | 'nulls' => true, 420 | 'default' => null, 421 | 'length' => null, 422 | ], 423 | ], 424 | 'primary_key' => [ 425 | 'users_pk' => [ 426 | 'order' => '1', 427 | 'columns' => [ 428 | 0 => 'id', 429 | ], 430 | ], 431 | ], 432 | 'unique_keys' => [ 433 | 'sqlite_autoindex_users_1' => [ 434 | 'columns' => [ 435 | 0 => 'username', 436 | ], 437 | 'schema' => '', 438 | ], 439 | ], 440 | 'foreign_keys' => [ 441 | 'users_departments_0_fk' => [ 442 | 'schema' => '', 443 | 'table' => 'users', 444 | 'columns' => [ 445 | 0 => 'office', 446 | ], 447 | 'foreign_table' => 'departments', 448 | 'foreign_schema' => '', 449 | 'foreign_columns' => [ 450 | 0 => 'id', 451 | ], 452 | 'on_update' => 'CASCADE', 453 | 'on_delete' => 'CASCADE', 454 | ], 455 | 'users_roles_1_fk' => [ 456 | 'schema' => '', 457 | 'table' => 'users', 458 | 'columns' => [ 459 | 0 => 'role_id', 460 | ], 461 | 'foreign_table' => 'roles', 462 | 'foreign_schema' => '', 463 | 'foreign_columns' => [ 464 | 0 => 'id', 465 | ], 466 | 'on_update' => 'CASCADE', 467 | 'on_delete' => 'CASCADE', 468 | ], 469 | ], 470 | 'indices' => [ 471 | 'user_email_idx' => [ 472 | 'columns' => [ 473 | 0 => 'email', 474 | ], 475 | 'schema' => '', 476 | ], 477 | ], 478 | 'auto_increment' => true, 479 | ], 480 | ], 481 | ]; 482 | -------------------------------------------------------------------------------- /tests/expected/sqlite/database_description_clean_defaults.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'main' => [ 30 | 'name' => 'main', 31 | 'tables' => [ 32 | 'departments' => [ 33 | 'name' => 'departments', 34 | 'schema' => '', 35 | 'columns' => [ 36 | 'id' => [ 37 | 'name' => 'id', 38 | 'type' => 'INTEGER', 39 | 'nulls' => true, 40 | 'default' => null, 41 | 'length' => null, 42 | ], 43 | 'name' => [ 44 | 'name' => 'name', 45 | 'type' => 'TEXT', 46 | 'nulls' => false, 47 | 'default' => null, 48 | 'length' => null, 49 | ], 50 | ], 51 | 'primary_key' => [ 52 | 'departments_pk' => [ 53 | 'order' => '1', 54 | 'columns' => [ 55 | 0 => 'id', 56 | ], 57 | ], 58 | ], 59 | 'unique_keys' => [ 60 | ], 61 | 'foreign_keys' => [ 62 | ], 63 | 'indices' => [ 64 | ], 65 | 'auto_increment' => true, 66 | ], 67 | 'roles' => [ 68 | 'name' => 'roles', 69 | 'schema' => '', 70 | 'columns' => [ 71 | 'id' => [ 72 | 'name' => 'id', 73 | 'type' => 'INTEGER', 74 | 'nulls' => true, 75 | 'default' => null, 76 | 'length' => null, 77 | ], 78 | 'name' => [ 79 | 'name' => 'name', 80 | 'type' => 'TEXT', 81 | 'nulls' => false, 82 | 'default' => null, 83 | 'length' => null, 84 | ], 85 | ], 86 | 'primary_key' => [ 87 | 'roles_pk' => [ 88 | 'order' => '1', 89 | 'columns' => [ 90 | 0 => 'id', 91 | ], 92 | ], 93 | ], 94 | 'unique_keys' => [ 95 | ], 96 | 'foreign_keys' => [ 97 | ], 98 | 'indices' => [ 99 | ], 100 | 'auto_increment' => true, 101 | ], 102 | 'users' => [ 103 | 'name' => 'users', 104 | 'schema' => '', 105 | 'columns' => [ 106 | 'id' => [ 107 | 'name' => 'id', 108 | 'type' => 'INTEGER', 109 | 'nulls' => false, 110 | 'default' => null, 111 | 'length' => null, 112 | ], 113 | 'username' => [ 114 | 'name' => 'username', 115 | 'type' => 'TEXT', 116 | 'nulls' => false, 117 | 'default' => null, 118 | 'length' => '255', 119 | ], 120 | 'password' => [ 121 | 'name' => 'password', 122 | 'type' => 'TEXT', 123 | 'nulls' => false, 124 | 'default' => null, 125 | 'length' => null, 126 | ], 127 | 'role_id' => [ 128 | 'name' => 'role_id', 129 | 'type' => 'INTEGER', 130 | 'nulls' => false, 131 | 'default' => null, 132 | 'length' => null, 133 | ], 134 | 'firstname' => [ 135 | 'name' => 'firstname', 136 | 'type' => 'TEXT', 137 | 'nulls' => false, 138 | 'default' => null, 139 | 'length' => null, 140 | ], 141 | 'lastname' => [ 142 | 'name' => 'lastname', 143 | 'type' => 'TEXT', 144 | 'nulls' => false, 145 | 'default' => null, 146 | 'length' => null, 147 | ], 148 | 'othernames' => [ 149 | 'name' => 'othernames', 150 | 'type' => 'TEXT', 151 | 'nulls' => true, 152 | 'default' => 'None', 153 | 'length' => null, 154 | ], 155 | 'status' => [ 156 | 'name' => 'status', 157 | 'type' => 'INTEGER', 158 | 'nulls' => true, 159 | 'default' => '2', 160 | 'length' => null, 161 | ], 162 | 'email' => [ 163 | 'name' => 'email', 164 | 'type' => 'TEXT', 165 | 'nulls' => true, 166 | 'default' => null, 167 | 'length' => null, 168 | ], 169 | 'phone' => [ 170 | 'name' => 'phone', 171 | 'type' => 'TEXT', 172 | 'nulls' => true, 173 | 'default' => null, 174 | 'length' => null, 175 | ], 176 | 'office' => [ 177 | 'name' => 'office', 178 | 'type' => 'INTEGER', 179 | 'nulls' => false, 180 | 'default' => null, 181 | 'length' => null, 182 | ], 183 | 'last_login_time' => [ 184 | 'name' => 'last_login_time', 185 | 'type' => 'TEXT', 186 | 'nulls' => true, 187 | 'default' => null, 188 | 'length' => null, 189 | ], 190 | 'is_admin' => [ 191 | 'name' => 'is_admin', 192 | 'type' => 'INTEGER', 193 | 'nulls' => true, 194 | 'default' => null, 195 | 'length' => null, 196 | ], 197 | ], 198 | 'primary_key' => [ 199 | 'users_pk' => [ 200 | 'order' => '1', 201 | 'columns' => [ 202 | 0 => 'id', 203 | ], 204 | ], 205 | ], 206 | 'unique_keys' => [ 207 | 'sqlite_autoindex_users_1' => [ 208 | 'columns' => [ 209 | 0 => 'username', 210 | ], 211 | 'schema' => '', 212 | ], 213 | ], 214 | 'foreign_keys' => [ 215 | 'users_departments_0_fk' => [ 216 | 'schema' => '', 217 | 'table' => 'users', 218 | 'columns' => [ 219 | 0 => 'office', 220 | ], 221 | 'foreign_table' => 'departments', 222 | 'foreign_schema' => '', 223 | 'foreign_columns' => [ 224 | 0 => 'id', 225 | ], 226 | 'on_update' => 'CASCADE', 227 | 'on_delete' => 'CASCADE', 228 | ], 229 | 'users_roles_1_fk' => [ 230 | 'schema' => '', 231 | 'table' => 'users', 232 | 'columns' => [ 233 | 0 => 'role_id', 234 | ], 235 | 'foreign_table' => 'roles', 236 | 'foreign_schema' => '', 237 | 'foreign_columns' => [ 238 | 0 => 'id', 239 | ], 240 | 'on_update' => 'CASCADE', 241 | 'on_delete' => 'CASCADE', 242 | ], 243 | ], 244 | 'indices' => [ 245 | 'user_email_idx' => [ 246 | 'columns' => [ 247 | 0 => 'email', 248 | ], 249 | 'schema' => '', 250 | ], 251 | ], 252 | 'auto_increment' => true, 253 | ], 254 | ] 255 | ] 256 | ], 257 | 'tables' => [ 258 | 'departments' => [ 259 | 'name' => 'departments', 260 | 'schema' => '', 261 | 'columns' => [ 262 | 'id' => [ 263 | 'name' => 'id', 264 | 'type' => 'INTEGER', 265 | 'nulls' => true, 266 | 'default' => null, 267 | 'length' => null, 268 | ], 269 | 'name' => [ 270 | 'name' => 'name', 271 | 'type' => 'TEXT', 272 | 'nulls' => false, 273 | 'default' => null, 274 | 'length' => null, 275 | ], 276 | ], 277 | 'primary_key' => [ 278 | 'departments_pk' => [ 279 | 'order' => '1', 280 | 'columns' => [ 281 | 0 => 'id', 282 | ], 283 | ], 284 | ], 285 | 'unique_keys' => [ 286 | ], 287 | 'foreign_keys' => [ 288 | ], 289 | 'indices' => [ 290 | ], 291 | 'auto_increment' => true, 292 | ], 293 | 'roles' => [ 294 | 'name' => 'roles', 295 | 'schema' => '', 296 | 'columns' => [ 297 | 'id' => [ 298 | 'name' => 'id', 299 | 'type' => 'INTEGER', 300 | 'nulls' => true, 301 | 'default' => null, 302 | 'length' => null, 303 | ], 304 | 'name' => [ 305 | 'name' => 'name', 306 | 'type' => 'TEXT', 307 | 'nulls' => false, 308 | 'default' => null, 309 | 'length' => null, 310 | ], 311 | ], 312 | 'primary_key' => [ 313 | 'roles_pk' => [ 314 | 'order' => '1', 315 | 'columns' => [ 316 | 0 => 'id', 317 | ], 318 | ], 319 | ], 320 | 'unique_keys' => [ 321 | ], 322 | 'foreign_keys' => [ 323 | ], 324 | 'indices' => [ 325 | ], 326 | 'auto_increment' => true, 327 | ], 328 | 'users' => [ 329 | 'name' => 'users', 330 | 'schema' => '', 331 | 'columns' => [ 332 | 'id' => [ 333 | 'name' => 'id', 334 | 'type' => 'INTEGER', 335 | 'nulls' => false, 336 | 'default' => null, 337 | 'length' => null, 338 | ], 339 | 'username' => [ 340 | 'name' => 'username', 341 | 'type' => 'TEXT', 342 | 'nulls' => false, 343 | 'default' => null, 344 | 'length' => '255', 345 | ], 346 | 'password' => [ 347 | 'name' => 'password', 348 | 'type' => 'TEXT', 349 | 'nulls' => false, 350 | 'default' => null, 351 | 'length' => null, 352 | ], 353 | 'role_id' => [ 354 | 'name' => 'role_id', 355 | 'type' => 'INTEGER', 356 | 'nulls' => false, 357 | 'default' => null, 358 | 'length' => null, 359 | ], 360 | 'firstname' => [ 361 | 'name' => 'firstname', 362 | 'type' => 'TEXT', 363 | 'nulls' => false, 364 | 'default' => null, 365 | 'length' => null, 366 | ], 367 | 'lastname' => [ 368 | 'name' => 'lastname', 369 | 'type' => 'TEXT', 370 | 'nulls' => false, 371 | 'default' => null, 372 | 'length' => null, 373 | ], 374 | 'othernames' => [ 375 | 'name' => 'othernames', 376 | 'type' => 'TEXT', 377 | 'nulls' => true, 378 | 'default' => 'None', 379 | 'length' => null, 380 | ], 381 | 'status' => [ 382 | 'name' => 'status', 383 | 'type' => 'INTEGER', 384 | 'nulls' => true, 385 | 'default' => '2', 386 | 'length' => null, 387 | ], 388 | 'email' => [ 389 | 'name' => 'email', 390 | 'type' => 'TEXT', 391 | 'nulls' => true, 392 | 'default' => null, 393 | 'length' => null, 394 | ], 395 | 'phone' => [ 396 | 'name' => 'phone', 397 | 'type' => 'TEXT', 398 | 'nulls' => true, 399 | 'default' => null, 400 | 'length' => null, 401 | ], 402 | 'office' => [ 403 | 'name' => 'office', 404 | 'type' => 'INTEGER', 405 | 'nulls' => false, 406 | 'default' => null, 407 | 'length' => null, 408 | ], 409 | 'last_login_time' => [ 410 | 'name' => 'last_login_time', 411 | 'type' => 'TEXT', 412 | 'nulls' => true, 413 | 'default' => null, 414 | 'length' => null, 415 | ], 416 | 'is_admin' => [ 417 | 'name' => 'is_admin', 418 | 'type' => 'INTEGER', 419 | 'nulls' => true, 420 | 'default' => null, 421 | 'length' => null, 422 | ], 423 | ], 424 | 'primary_key' => [ 425 | 'users_pk' => [ 426 | 'order' => '1', 427 | 'columns' => [ 428 | 0 => 'id', 429 | ], 430 | ], 431 | ], 432 | 'unique_keys' => [ 433 | 'sqlite_autoindex_users_1' => [ 434 | 'columns' => [ 435 | 0 => 'username', 436 | ], 437 | 'schema' => '', 438 | ], 439 | ], 440 | 'foreign_keys' => [ 441 | 'users_departments_0_fk' => [ 442 | 'schema' => '', 443 | 'table' => 'users', 444 | 'columns' => [ 445 | 0 => 'office', 446 | ], 447 | 'foreign_table' => 'departments', 448 | 'foreign_schema' => '', 449 | 'foreign_columns' => [ 450 | 0 => 'id', 451 | ], 452 | 'on_update' => 'CASCADE', 453 | 'on_delete' => 'CASCADE', 454 | ], 455 | 'users_roles_1_fk' => [ 456 | 'schema' => '', 457 | 'table' => 'users', 458 | 'columns' => [ 459 | 0 => 'role_id', 460 | ], 461 | 'foreign_table' => 'roles', 462 | 'foreign_schema' => '', 463 | 'foreign_columns' => [ 464 | 0 => 'id', 465 | ], 466 | 'on_update' => 'CASCADE', 467 | 'on_delete' => 'CASCADE', 468 | ], 469 | ], 470 | 'indices' => [ 471 | 'user_email_idx' => [ 472 | 'columns' => [ 473 | 0 => 'email', 474 | ], 475 | 'schema' => '', 476 | ], 477 | ], 478 | 'auto_increment' => true, 479 | ], 480 | ], 481 | ]; 482 | -------------------------------------------------------------------------------- /tests/expected/sqlite/strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "quoted_string": "'string'", 3 | "quoted_identifier" : "\"identifier\"", 4 | "quoted_query_identifiers" : "SELECT \"some\", \"identifiers\" FROM \"some\".\"table\"" 5 | } 6 | -------------------------------------------------------------------------------- /tests/expected/sqlite/view_description.php: -------------------------------------------------------------------------------- 1 | [ 29 | 'name' => 'users_view', 30 | 'schema' => '', 31 | 'columns' => [ 32 | 'id' => [ 33 | 'name' => 'id', 34 | 'type' => 'INTEGER', 35 | 'nulls' => true, 36 | 'default' => null, 37 | 'length' => null, 38 | ], 39 | 'username' => [ 40 | 'name' => 'username', 41 | 'type' => 'TEXT', 42 | 'nulls' => true, 43 | 'default' => null, 44 | 'length' => '255', 45 | ], 46 | 'password' => [ 47 | 'name' => 'password', 48 | 'type' => 'TEXT', 49 | 'nulls' => true, 50 | 'default' => null, 51 | 'length' => null, 52 | ], 53 | 'firstname' => [ 54 | 'name' => 'firstname', 55 | 'type' => 'TEXT', 56 | 'nulls' => true, 57 | 'default' => null, 58 | 'length' => null, 59 | ], 60 | 'lastname' => [ 61 | 'name' => 'lastname', 62 | 'type' => 'TEXT', 63 | 'nulls' => true, 64 | 'default' => null, 65 | 'length' => null, 66 | ], 67 | 'othernames' => [ 68 | 'name' => 'othernames', 69 | 'type' => 'TEXT', 70 | 'nulls' => true, 71 | 'default' => null, 72 | 'length' => null, 73 | ], 74 | 'email' => [ 75 | 'name' => 'email', 76 | 'type' => 'TEXT', 77 | 'nulls' => true, 78 | 'default' => null, 79 | 'length' => null, 80 | ], 81 | 'role' => [ 82 | 'name' => 'role', 83 | 'type' => 'TEXT', 84 | 'nulls' => true, 85 | 'default' => null, 86 | 'length' => null, 87 | ], 88 | ], 89 | 'primary_key' => [ 90 | ], 91 | 'unique_keys' => [ 92 | ], 93 | 'foreign_keys' => [ 94 | ], 95 | 'indices' => [ 96 | ], 97 | 'auto_increment' => false, 98 | ], 99 | ]; 100 | -------------------------------------------------------------------------------- /tests/expected/xml/transactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/lib/DriverLoader.php: -------------------------------------------------------------------------------- 1 | getenv('ATIAA_DRIVER'), 40 | 'host' => getenv('ATIAA_HOST'), 41 | 'user' => getenv('ATIAA_USER'), 42 | 'password' => getenv('ATIAA_PASSWORD'), 43 | 'file' => getenv('ATIAA_FILE'), 44 | 'dbname' => getenv('ATIAA_DBNAME'), 45 | 'options' => [\PDO::ATTR_TIMEOUT => 5] 46 | ]); 47 | $driver = $factory->createDriver(); 48 | $driver->connect(); 49 | 50 | return $driver; 51 | } 52 | 53 | public function getDriverName() 54 | { 55 | return getenv('ATIAA_DRIVER'); 56 | } 57 | } 58 | --------------------------------------------------------------------------------