Browse Source

Support for views #409

Maurits van der Schee 6 years ago
parent
commit
da352c2a93

+ 19
- 16
src/Tqdev/PhpCrudApi/Column/Reflection/ReflectedDatabase.php View File

@@ -6,36 +6,34 @@ use Tqdev\PhpCrudApi\Database\GenericReflection;
6 6
 class ReflectedDatabase implements \JsonSerializable
7 7
 {
8 8
     private $name;
9
-    private $tableNames;
9
+    private $tableTypes;
10 10
 
11
-    public function __construct(String $name, array $tableNames)
11
+    public function __construct(String $name, array $tableTypes)
12 12
     {
13 13
         $this->name = $name;
14
-        $this->tableNames = [];
15
-        foreach ($tableNames as $tableName) {
16
-            $this->tableNames[$tableName] = true;
17
-        }
14
+        $this->tableTypes = $tableTypes;
18 15
     }
19 16
 
20 17
     public static function fromReflection(GenericReflection $reflection): ReflectedDatabase
21 18
     {
22 19
         $name = $reflection->getDatabaseName();
23
-        $tableNames = [];
20
+        $tableTypes = [];
24 21
         foreach ($reflection->getTables() as $table) {
25 22
             $tableName = $table['TABLE_NAME'];
23
+            $tableType = $table['TABLE_TYPE'];
26 24
             if (in_array($tableName, $reflection->getIgnoredTables())) {
27 25
                 continue;
28 26
             }
29
-            $tableNames[$tableName] = true;
27
+            $tableTypes[$tableName] = $tableType;
30 28
         }
31
-        return new ReflectedDatabase($name, array_keys($tableNames));
29
+        return new ReflectedDatabase($name, $tableTypes);
32 30
     }
33 31
 
34 32
     public static function fromJson( /* object */$json): ReflectedDatabase
35 33
     {
36 34
         $name = $json->name;
37
-        $tableNames = $json->tables;
38
-        return new ReflectedDatabase($name, $tableNames);
35
+        $tableTypes = (array) $json->tables;
36
+        return new ReflectedDatabase($name, $tableTypes);
39 37
     }
40 38
 
41 39
     public function getName(): String
@@ -45,20 +43,25 @@ class ReflectedDatabase implements \JsonSerializable
45 43
 
46 44
     public function hasTable(String $tableName): bool
47 45
     {
48
-        return isset($this->tableNames[$tableName]);
46
+        return isset($this->tableTypes[$tableName]);
47
+    }
48
+
49
+    public function getType(String $tableName): String
50
+    {
51
+        return isset($this->tableTypes[$tableName]) ? $this->tableTypes[$tableName] : '';
49 52
     }
50 53
 
51 54
     public function getTableNames(): array
52 55
     {
53
-        return array_keys($this->tableNames);
56
+        return array_keys($this->tableTypes);
54 57
     }
55 58
 
56 59
     public function removeTable(String $tableName): bool
57 60
     {
58
-        if (!isset($this->tableNames[$tableName])) {
61
+        if (!isset($this->tableTypes[$tableName])) {
59 62
             return false;
60 63
         }
61
-        unset($this->tableNames[$tableName]);
64
+        unset($this->tableTypes[$tableName]);
62 65
         return true;
63 66
     }
64 67
 
@@ -66,7 +69,7 @@ class ReflectedDatabase implements \JsonSerializable
66 69
     {
67 70
         return [
68 71
             'name' => $this->name,
69
-            'tables' => array_keys($this->tableNames),
72
+            'tables' => $this->tableTypes,
70 73
         ];
71 74
     }
72 75
 

+ 14
- 5
src/Tqdev/PhpCrudApi/Column/Reflection/ReflectedTable.php View File

@@ -6,13 +6,15 @@ use Tqdev\PhpCrudApi\Database\GenericReflection;
6 6
 class ReflectedTable implements \JsonSerializable
7 7
 {
8 8
     private $name;
9
+    private $type;
9 10
     private $columns;
10 11
     private $pk;
11 12
     private $fks;
12 13
 
13
-    public function __construct(String $name, array $columns)
14
+    public function __construct(String $name, String $type, array $columns)
14 15
     {
15 16
         $this->name = $name;
17
+        $this->type = $type;
16 18
         // set columns
17 19
         $this->columns = [];
18 20
         foreach ($columns as $column) {
@@ -37,11 +39,11 @@ class ReflectedTable implements \JsonSerializable
37 39
         }
38 40
     }
39 41
 
40
-    public static function fromReflection(GenericReflection $reflection, String $name): ReflectedTable
42
+    public static function fromReflection(GenericReflection $reflection, String $name, String $type): ReflectedTable
41 43
     {
42 44
         // set columns
43 45
         $columns = [];
44
-        foreach ($reflection->getTableColumns($name) as $tableColumn) {
46
+        foreach ($reflection->getTableColumns($name, $type) as $tableColumn) {
45 47
             $column = ReflectedColumn::fromReflection($reflection, $tableColumn);
46 48
             $columns[$column->getName()] = $column;
47 49
         }
@@ -59,19 +61,20 @@ class ReflectedTable implements \JsonSerializable
59 61
         foreach ($fks as $columnName => $table) {
60 62
             $columns[$columnName]->setFk($table);
61 63
         }
62
-        return new ReflectedTable($name, array_values($columns));
64
+        return new ReflectedTable($name, $type, array_values($columns));
63 65
     }
64 66
 
65 67
     public static function fromJson( /* object */$json): ReflectedTable
66 68
     {
67 69
         $name = $json->name;
70
+        $type = $json->type;
68 71
         $columns = [];
69 72
         if (isset($json->columns) && is_array($json->columns)) {
70 73
             foreach ($json->columns as $column) {
71 74
                 $columns[] = ReflectedColumn::fromJson($column);
72 75
             }
73 76
         }
74
-        return new ReflectedTable($name, $columns);
77
+        return new ReflectedTable($name, $type, $columns);
75 78
     }
76 79
 
77 80
     public function hasColumn(String $columnName): bool
@@ -94,6 +97,11 @@ class ReflectedTable implements \JsonSerializable
94 97
         return $this->name;
95 98
     }
96 99
 
100
+    public function getType(): String
101
+    {
102
+        return $this->type;
103
+    }
104
+
97 105
     public function columnNames(): array
98 106
     {
99 107
         return array_keys($this->columns);
@@ -128,6 +136,7 @@ class ReflectedTable implements \JsonSerializable
128 136
     {
129 137
         return [
130 138
             'name' => $this->name,
139
+            'type' => $this->type,
131 140
             'columns' => array_values($this->columns),
132 141
         ];
133 142
     }

+ 7
- 1
src/Tqdev/PhpCrudApi/Column/ReflectionService.php View File

@@ -42,7 +42,8 @@ class ReflectionService
42 42
         if ($data != '') {
43 43
             $table = ReflectedTable::fromJson(json_decode(gzuncompress($data)));
44 44
         } else {
45
-            $table = ReflectedTable::fromReflection($this->db->reflection(), $tableName);
45
+            $tableType = $this->database->getType($tableName);
46
+            $table = ReflectedTable::fromReflection($this->db->reflection(), $tableName, $tableType);
46 47
             $data = gzcompress(json_encode($table, JSON_UNESCAPED_UNICODE));
47 48
             $this->cache->set("ReflectedTable($tableName)", $data, $this->ttl);
48 49
         }
@@ -64,6 +65,11 @@ class ReflectionService
64 65
         return $this->database->hasTable($tableName);
65 66
     }
66 67
 
68
+    public function getType(String $tableName): String
69
+    {
70
+        return $this->database->getType($tableName);
71
+    }
72
+
67 73
     public function getTable(String $tableName): ReflectedTable
68 74
     {
69 75
         if (!isset($this->tables[$tableName])) {

+ 29
- 14
src/Tqdev/PhpCrudApi/Controller/RecordController.php View File

@@ -37,11 +37,14 @@ class RecordController
37 37
     public function read(Request $request): Response
38 38
     {
39 39
         $table = $request->getPathSegment(2);
40
-        $id = $request->getPathSegment(3);
41
-        $params = $request->getParams();
42 40
         if (!$this->service->hasTable($table)) {
43 41
             return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
44 42
         }
43
+        if ($this->service->getType($table) != 'table') {
44
+            return $this->responder->error(ErrorCode::OPERATION_NOT_SUPPORTED, __FUNCTION__);
45
+        }
46
+        $id = $request->getPathSegment(3);
47
+        $params = $request->getParams();
45 48
         if (strpos($id, ',') !== false) {
46 49
             $ids = explode(',', $id);
47 50
             $result = [];
@@ -61,14 +64,17 @@ class RecordController
61 64
     public function create(Request $request): Response
62 65
     {
63 66
         $table = $request->getPathSegment(2);
67
+        if (!$this->service->hasTable($table)) {
68
+            return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
69
+        }
70
+        if ($this->service->getType($table) != 'table') {
71
+            return $this->responder->error(ErrorCode::OPERATION_NOT_SUPPORTED, __FUNCTION__);
72
+        }
64 73
         $record = $request->getBody();
65 74
         if ($record === null) {
66 75
             return $this->responder->error(ErrorCode::HTTP_MESSAGE_NOT_READABLE, '');
67 76
         }
68 77
         $params = $request->getParams();
69
-        if (!$this->service->hasTable($table)) {
70
-            return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
71
-        }
72 78
         if (is_array($record)) {
73 79
             $result = array();
74 80
             foreach ($record as $r) {
@@ -83,15 +89,18 @@ class RecordController
83 89
     public function update(Request $request): Response
84 90
     {
85 91
         $table = $request->getPathSegment(2);
92
+        if (!$this->service->hasTable($table)) {
93
+            return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
94
+        }
95
+        if ($this->service->getType($table) != 'table') {
96
+            return $this->responder->error(ErrorCode::OPERATION_NOT_SUPPORTED, __FUNCTION__);
97
+        }
86 98
         $id = $request->getPathSegment(3);
99
+        $params = $request->getParams();
87 100
         $record = $request->getBody();
88 101
         if ($record === null) {
89 102
             return $this->responder->error(ErrorCode::HTTP_MESSAGE_NOT_READABLE, '');
90 103
         }
91
-        $params = $request->getParams();
92
-        if (!$this->service->hasTable($table)) {
93
-            return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
94
-        }
95 104
         $ids = explode(',', $id);
96 105
         if (is_array($record)) {
97 106
             if (count($ids) != count($record)) {
@@ -113,11 +122,14 @@ class RecordController
113 122
     public function delete(Request $request): Response
114 123
     {
115 124
         $table = $request->getPathSegment(2);
116
-        $id = $request->getPathSegment(3);
117
-        $params = $request->getParams();
118 125
         if (!$this->service->hasTable($table)) {
119 126
             return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
120 127
         }
128
+        if ($this->service->getType($table) != 'table') {
129
+            return $this->responder->error(ErrorCode::OPERATION_NOT_SUPPORTED, __FUNCTION__);
130
+        }
131
+        $id = $request->getPathSegment(3);
132
+        $params = $request->getParams();
121 133
         $ids = explode(',', $id);
122 134
         if (count($ids) > 1) {
123 135
             $result = array();
@@ -133,15 +145,18 @@ class RecordController
133 145
     public function increment(Request $request): Response
134 146
     {
135 147
         $table = $request->getPathSegment(2);
148
+        if (!$this->service->hasTable($table)) {
149
+            return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
150
+        }
151
+        if ($this->service->getType($table) != 'table') {
152
+            return $this->responder->error(ErrorCode::OPERATION_NOT_SUPPORTED, __FUNCTION__);
153
+        }
136 154
         $id = $request->getPathSegment(3);
137 155
         $record = $request->getBody();
138 156
         if ($record === null) {
139 157
             return $this->responder->error(ErrorCode::HTTP_MESSAGE_NOT_READABLE, '');
140 158
         }
141 159
         $params = $request->getParams();
142
-        if (!$this->service->hasTable($table)) {
143
-            return $this->responder->error(ErrorCode::TABLE_NOT_FOUND, $table);
144
-        }
145 160
         $ids = explode(',', $id);
146 161
         if (is_array($record)) {
147 162
             if (count($ids) != count($record)) {

+ 30
- 7
src/Tqdev/PhpCrudApi/Database/GenericReflection.php View File

@@ -20,7 +20,7 @@ class GenericReflection
20 20
     {
21 21
         switch ($this->driver) {
22 22
             case 'mysql':return [];
23
-            case 'pgsql':return ['spatial_ref_sys'];
23
+            case 'pgsql':return ['spatial_ref_sys', 'raster_columns', 'raster_overviews', 'geography_columns', 'geometry_columns'];
24 24
             case 'sqlsrv':return [];
25 25
         }
26 26
     }
@@ -28,9 +28,9 @@ class GenericReflection
28 28
     private function getTablesSQL(): String
29 29
     {
30 30
         switch ($this->driver) {
31
-            case 'mysql':return 'SELECT "TABLE_NAME" FROM "INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_TYPE" IN (\'BASE TABLE\') AND "TABLE_SCHEMA" = ? ORDER BY BINARY "TABLE_NAME"';
32
-            case 'pgsql':return 'SELECT c.relname as "TABLE_NAME" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN (\'r\') AND n.nspname <> \'pg_catalog\' AND n.nspname <> \'information_schema\' AND n.nspname !~ \'^pg_toast\' AND pg_catalog.pg_table_is_visible(c.oid) AND \'\' <> ? ORDER BY "TABLE_NAME";';
33
-            case 'sqlsrv':return 'SELECT o.name as "TABLE_NAME" FROM sysobjects o WHERE o.xtype = \'U\' ORDER BY "TABLE_NAME"';
31
+            case 'mysql':return 'SELECT "TABLE_NAME", "TABLE_TYPE" FROM "INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_TYPE" IN (\'BASE TABLE\' , \'VIEW\') AND "TABLE_SCHEMA" = ? ORDER BY BINARY "TABLE_NAME"';
32
+            case 'pgsql':return 'SELECT c.relname as "TABLE_NAME", c.relkind as "TABLE_TYPE" FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind IN (\'r\', \'v\') AND n.nspname <> \'pg_catalog\' AND n.nspname <> \'information_schema\' AND n.nspname !~ \'^pg_toast\' AND pg_catalog.pg_table_is_visible(c.oid) AND \'\' <> ? ORDER BY "TABLE_NAME";';
33
+            case 'sqlsrv':return 'SELECT o.name as "TABLE_NAME", o.xtype as "TABLE_TYPE" FROM sysobjects o WHERE o.xtype IN (\'U\', \'V\') ORDER BY "TABLE_NAME"';
34 34
         }
35 35
     }
36 36
 
@@ -69,13 +69,36 @@ class GenericReflection
69 69
     public function getTables(): array
70 70
     {
71 71
         $sql = $this->getTablesSQL();
72
-        return $this->query($sql, [$this->database]);
72
+        $results = $this->query($sql, [$this->database]);
73
+        foreach ($results as &$result) {
74
+            switch ($this->driver) {
75
+                case 'mysql':
76
+                    $map = ['BASE TABLE' => 'table', 'VIEW' => 'view'];
77
+                    $result['TABLE_TYPE'] = $map[$result['TABLE_TYPE']];
78
+                    break;
79
+                case 'pgsql':
80
+                    $map = ['r' => 'table', 'v' => 'view'];
81
+                    $result['TABLE_TYPE'] = $map[$result['TABLE_TYPE']];
82
+                    break;
83
+                case 'sqlsrv':
84
+                    $map = ['U' => 'table', 'V' => 'view'];
85
+                    $result['TABLE_TYPE'] = $map[trim($result['TABLE_TYPE'])];
86
+                    break;
87
+            }
88
+        }
89
+        return $results;
73 90
     }
74 91
 
75
-    public function getTableColumns(String $tableName): array
92
+    public function getTableColumns(String $tableName, String $type): array
76 93
     {
77 94
         $sql = $this->getTableColumnsSQL();
78
-        return $this->query($sql, [$tableName, $this->database]);
95
+        $results = $this->query($sql, [$tableName, $this->database]);
96
+        if ($type == 'view') {
97
+            foreach ($results as &$result) {
98
+                $result['IS_NULLABLE'] = false;
99
+            }
100
+        }
101
+        return $results;
79 102
     }
80 103
 
81 104
     public function getTablePrimaryKeys(String $tableName): array

+ 4
- 0
src/Tqdev/PhpCrudApi/OpenApi/OpenApiBuilder.php View File

@@ -87,12 +87,16 @@ class OpenApiBuilder
87 87
     private function setPath(String $tableName) /*: void*/
88 88
     {
89 89
         $table = $this->reflection->getTable($tableName);
90
+        $type = $table->getType($tableName);
90 91
         $pk = $table->getPk();
91 92
         $pkName = $pk ? $pk->getName() : '';
92 93
         foreach ($this->operations as $operation => $method) {
93 94
             if (!$pkName && $operation != 'list') {
94 95
                 continue;
95 96
             }
97
+            if ($type != 'table' && $operation != 'list') {
98
+                continue;
99
+            }
96 100
             if (!$this->isOperationOnTableAllowed($operation, $tableName)) {
97 101
                 continue;
98 102
             }

+ 2
- 0
src/Tqdev/PhpCrudApi/Record/ErrorCode.php View File

@@ -26,6 +26,7 @@ class ErrorCode
26 26
     const ACCESS_DENIED = 1012;
27 27
     const INPUT_VALIDATION_FAILED = 1013;
28 28
     const OPERATION_FORBIDDEN = 1014;
29
+    const OPERATION_NOT_SUPPORTED = 1015;
29 30
 
30 31
     private $values = [
31 32
         9999 => ["%s", Response::INTERNAL_SERVER_ERROR],
@@ -44,6 +45,7 @@ class ErrorCode
44 45
         1012 => ["Access denied for '%s'", Response::FORBIDDEN],
45 46
         1013 => ["Input validation failed for '%s'", Response::UNPROCESSABLE_ENTITY],
46 47
         1014 => ["Operation forbidden", Response::FORBIDDEN],
48
+        1015 => ["Operation '%s' not supported", Response::METHOD_NOT_ALLOWED],
47 49
     ];
48 50
 
49 51
     public function __construct(int $code)

+ 5
- 0
src/Tqdev/PhpCrudApi/Record/RecordService.php View File

@@ -50,6 +50,11 @@ class RecordService
50 50
         return $this->reflection->hasTable($table);
51 51
     }
52 52
 
53
+    public function getType(String $table): bool
54
+    {
55
+        return $this->reflection->getType($table);
56
+    }
57
+
53 58
     public function create(String $tableName, /* object */ $record, array $params)
54 59
     {
55 60
         $this->sanitizeRecord($tableName, $record, '');

+ 1
- 1
src/Tqdev/PhpCrudApi/Response.php View File

@@ -7,10 +7,10 @@ class Response
7 7
     const UNAUTHORIZED = 401;
8 8
     const FORBIDDEN = 403;
9 9
     const NOT_FOUND = 404;
10
+    const METHOD_NOT_ALLOWED = 405;
10 11
     const CONFLICT = 409;
11 12
     const UNPROCESSABLE_ENTITY = 422;
12 13
     const INTERNAL_SERVER_ERROR = 500;
13
-
14 14
     private $status;
15 15
     private $headers;
16 16
     private $body;

+ 10
- 4
tests/fixtures/blog_sqlsrv.sql View File

@@ -1,3 +1,9 @@
1
+IF (OBJECT_ID('FK_kunsthåndværk_users', 'F') IS NOT NULL)
2
+BEGIN
3
+ALTER TABLE [kunsthåndværk] DROP	CONSTRAINT [FK_kunsthåndværk_users]
4
+END
5
+GO
6
+
1 7
 IF (OBJECT_ID('FK_barcodes_products', 'F') IS NOT NULL)
2 8
 BEGIN
3 9
 ALTER TABLE [barcodes] DROP	CONSTRAINT [FK_barcodes_products]
@@ -222,7 +228,7 @@ CREATE TABLE [barcodes](
222 228
 GO
223 229
 
224 230
 CREATE TABLE [kunsthåndværk](
225
-	[id] [nvarchar](36),
231
+	[id] [nvarchar](36) NOT NULL,
226 232
 	[Umlauts ä_ö_ü-COUNT] [int] NOT NULL,
227 233
 	[user_id] [int] NOT NULL,
228 234
 	[invisible] [nvarchar](36),
@@ -232,14 +238,14 @@ CREATE TABLE [kunsthåndværk](
232 238
 GO
233 239
 
234 240
 CREATE TABLE [invisibles](
235
-	[id] [nvarchar](36),
241
+	[id] [nvarchar](36) NOT NULL,
236 242
 	CONSTRAINT [PK_invisibles]
237 243
 	PRIMARY KEY CLUSTERED([id] ASC)
238 244
 )
239 245
 GO
240 246
 
241 247
 CREATE TABLE [nopk](
242
-	[id] [nvarchar](36)
248
+	[id] [nvarchar](36) NOT NULL
243 249
 )
244 250
 GO
245 251
 
@@ -349,4 +355,4 @@ ALTER TABLE [kunsthåndværk]  WITH CHECK ADD 	CONSTRAINT [FK_kunsthåndværk_us
349 355
 REFERENCES [users] ([id])
350 356
 GO
351 357
 ALTER TABLE [kunsthåndværk] CHECK	CONSTRAINT [FK_kunsthåndværk_users]
352
-GO
358
+GO

+ 2
- 2
tests/functional/003_columns/001_get_database.log View File

@@ -2,6 +2,6 @@ GET /columns
2 2
 ===
3 3
 200
4 4
 Content-Type: application/json
5
-Content-Length: 2273
5
+Content-Length: 2579
6 6
 
7
-{"name":"php-crud-api","tables":[{"name":"barcodes","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]},{"name":"categories","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"icon","type":"blob","nullable":true}]},{"name":"comments","columns":[{"name":"id","type":"integer","pk":true},{"name":"post_id","type":"integer","fk":"posts"},{"name":"message","type":"varchar","length":255}]},{"name":"countries","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"shape","type":"geometry"}]},{"name":"events","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"datetime","type":"timestamp"},{"name":"visitors","type":"integer"}]},{"name":"kunsthåndværk","columns":[{"name":"id","type":"varchar","length":36,"pk":true},{"name":"Umlauts ä_ö_ü-COUNT","type":"integer"},{"name":"user_id","type":"integer","fk":"users"}]},{"name":"nopk","columns":[{"name":"id","type":"varchar","length":36}]},{"name":"post_tags","columns":[{"name":"id","type":"integer","pk":true},{"name":"post_id","type":"integer","fk":"posts"},{"name":"tag_id","type":"integer","fk":"tags"}]},{"name":"posts","columns":[{"name":"id","type":"integer","pk":true},{"name":"user_id","type":"integer","fk":"users"},{"name":"category_id","type":"integer","fk":"categories"},{"name":"content","type":"varchar","length":255}]},{"name":"products","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"price","type":"decimal","precision":10,"scale":2},{"name":"properties","type":"clob"},{"name":"created_at","type":"timestamp"},{"name":"deleted_at","type":"timestamp","nullable":true}]},{"name":"tags","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"is_important","type":"boolean"}]},{"name":"users","columns":[{"name":"id","type":"integer","pk":true},{"name":"username","type":"varchar","length":255},{"name":"password","type":"varchar","length":255},{"name":"location","type":"geometry","nullable":true}]}]}
7
+{"name":"php-crud-api","tables":[{"name":"barcodes","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]},{"name":"categories","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"icon","type":"blob","nullable":true}]},{"name":"comments","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"post_id","type":"integer","fk":"posts"},{"name":"message","type":"varchar","length":255}]},{"name":"countries","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"shape","type":"geometry"}]},{"name":"events","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"datetime","type":"timestamp"},{"name":"visitors","type":"integer"}]},{"name":"kunsthåndværk","type":"table","columns":[{"name":"id","type":"varchar","length":36,"pk":true},{"name":"Umlauts ä_ö_ü-COUNT","type":"integer"},{"name":"user_id","type":"integer","fk":"users"}]},{"name":"nopk","type":"table","columns":[{"name":"id","type":"varchar","length":36}]},{"name":"post_tags","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"post_id","type":"integer","fk":"posts"},{"name":"tag_id","type":"integer","fk":"tags"}]},{"name":"posts","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"user_id","type":"integer","fk":"users"},{"name":"category_id","type":"integer","fk":"categories"},{"name":"content","type":"varchar","length":255}]},{"name":"products","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"price","type":"decimal","precision":10,"scale":2},{"name":"properties","type":"clob"},{"name":"created_at","type":"timestamp"},{"name":"deleted_at","type":"timestamp","nullable":true}]},{"name":"tag_usage","type":"view","columns":[{"name":"name","type":"varchar","length":255},{"name":"count","type":"bigint"}]},{"name":"tags","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"name","type":"varchar","length":255},{"name":"is_important","type":"boolean"}]},{"name":"users","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"username","type":"varchar","length":255},{"name":"password","type":"varchar","length":255},{"name":"location","type":"geometry","nullable":true}]}]}

+ 2
- 2
tests/functional/003_columns/002_get_barcodes_table.log View File

@@ -2,6 +2,6 @@ GET /columns/barcodes
2 2
 ===
3 3
 200
4 4
 Content-Type: application/json
5
-Content-Length: 201
5
+Content-Length: 216
6 6
 
7
-{"name":"barcodes","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
7
+{"name":"barcodes","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}

+ 4
- 4
tests/functional/003_columns/008_update_barcodes_table.log View File

@@ -12,9 +12,9 @@ GET /columns/barcodes2
12 12
 ===
13 13
 200
14 14
 Content-Type: application/json
15
-Content-Length: 202
15
+Content-Length: 217
16 16
 
17
-{"name":"barcodes2","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
17
+{"name":"barcodes2","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
18 18
 ===
19 19
 PUT /columns/barcodes2
20 20
 
@@ -30,6 +30,6 @@ GET /columns/barcodes
30 30
 ===
31 31
 200
32 32
 Content-Type: application/json
33
-Content-Length: 201
33
+Content-Length: 216
34 34
 
35
-{"name":"barcodes","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
35
+{"name":"barcodes","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}

+ 3
- 3
tests/functional/003_columns/010_create_barcodes_table.log View File

@@ -1,6 +1,6 @@
1 1
 POST /columns
2 2
 
3
-{"name":"barcodes2","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
3
+{"name":"barcodes2","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
4 4
 ===
5 5
 200
6 6
 Content-Type: application/json
@@ -12,9 +12,9 @@ GET /columns/barcodes2
12 12
 ===
13 13
 200
14 14
 Content-Type: application/json
15
-Content-Length: 202
15
+Content-Length: 217
16 16
 
17
-{"name":"barcodes2","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
17
+{"name":"barcodes2","type":"table","columns":[{"name":"id","type":"integer","pk":true},{"name":"product_id","type":"integer","fk":"products"},{"name":"hex","type":"varchar","length":255},{"name":"bin","type":"blob"}]}
18 18
 ===
19 19
 DELETE /columns/barcodes2
20 20
 ===

Loading…
Cancel
Save