feat: defined logic for schema building
This commit is contained in:
parent
b7674e3278
commit
bb050e75d3
3 changed files with 202 additions and 72 deletions
2
.env
2
.env
|
@ -15,7 +15,7 @@ _APP_DB_PORT=3306
|
||||||
_APP_DB_SCHEMA=appwrite
|
_APP_DB_SCHEMA=appwrite
|
||||||
_APP_DB_USER=user
|
_APP_DB_USER=user
|
||||||
_APP_DB_PASS=password
|
_APP_DB_PASS=password
|
||||||
_APP_STORAGE_ANTIVIRUS=enabled
|
_APP_STORAGE_ANTIVIRUS=disabled
|
||||||
_APP_STORAGE_ANTIVIRUS_HOST=clamav
|
_APP_STORAGE_ANTIVIRUS_HOST=clamav
|
||||||
_APP_STORAGE_ANTIVIRUS_PORT=3310
|
_APP_STORAGE_ANTIVIRUS_PORT=3310
|
||||||
_APP_INFLUXDB_HOST=influxdb
|
_APP_INFLUXDB_HOST=influxdb
|
||||||
|
|
|
@ -4,7 +4,11 @@ use GraphQL\GraphQL;
|
||||||
use GraphQL\Type\Schema;
|
use GraphQL\Type\Schema;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use Appwrite\Utopia\Response;
|
||||||
|
use Appwrite\Utopia\Response\Model;
|
||||||
|
use GraphQL\Type\Definition\NonNull;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
|
use Utopia\Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO:
|
* TODO:
|
||||||
|
@ -34,83 +38,210 @@ use Utopia\App;
|
||||||
* - Objects
|
* - Objects
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
global $typeMapping;
|
||||||
|
|
||||||
|
$typeMapping = [
|
||||||
|
Model::TYPE_BOOLEAN => Type::boolean(),
|
||||||
|
Model::TYPE_STRING => Type::string(),
|
||||||
|
Model::TYPE_INTEGER => Type::int(),
|
||||||
|
Model::TYPE_FLOAT => Type::float(),
|
||||||
|
|
||||||
|
// Outliers
|
||||||
|
Model::TYPE_JSON => Type::string(),
|
||||||
|
Response::MODEL_ANY => Type::string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
function createTypeMapping(Model $model, Response $response) {
|
||||||
|
|
||||||
|
global $typeMapping;
|
||||||
|
|
||||||
|
// If map already contains this complex type, then simply return
|
||||||
|
if (isset($typeMapping[$model->getType()])) return;
|
||||||
|
|
||||||
|
|
||||||
|
$rules = $model->getRules();
|
||||||
|
$name = $model->getType();
|
||||||
|
$fields = [];
|
||||||
|
foreach ($rules as $key => $props) {
|
||||||
|
// Replace this with php regex
|
||||||
|
$key = str_replace('$', '', $key);
|
||||||
|
if (isset( $typeMapping[$props['type']])) {
|
||||||
|
$type = $typeMapping[$props['type']];
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
$complexModel = $response->getModel($props['type']);
|
||||||
|
createTypeMapping($complexModel, $response);
|
||||||
|
$type = $typeMapping[$props['type']];
|
||||||
|
} catch (Exception $e) {
|
||||||
|
var_dump("Could Not find model for : {$props['type']}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($props['array']) {
|
||||||
|
$type = Type::listOf($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields[$key] = [
|
||||||
|
'type' => $type,
|
||||||
|
'description' => $props['description'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$objectType = [
|
||||||
|
'name' => $name,
|
||||||
|
'fields' => $fields
|
||||||
|
];
|
||||||
|
|
||||||
|
$typeMapping[$name] = new ObjectType($objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getArgType(Validator $validator, bool $required) {
|
||||||
|
|
||||||
|
$type = [];
|
||||||
|
switch ((!empty($validator)) ? \get_class($validator) : '') {
|
||||||
|
case 'Utopia\Validator\Text':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\Boolean':
|
||||||
|
$type = Type::boolean();
|
||||||
|
break;
|
||||||
|
case 'Appwrite\Database\Validator\UID':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\Email':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\URL':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\JSON':
|
||||||
|
case 'Utopia\Validator\Mock':
|
||||||
|
case 'Utopia\Validator\Assoc':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Appwrite\Storage\Validator\File':
|
||||||
|
$type = Type::string();
|
||||||
|
case 'Utopia\Validator\ArrayList':
|
||||||
|
$type = Type::listOf(Type::string());
|
||||||
|
break;
|
||||||
|
case 'Appwrite\Auth\Validator\Password':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\Range': /* @var $validator \Utopia\Validator\Range */
|
||||||
|
$type = Type::int();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\Numeric':
|
||||||
|
$type = Type::int();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\Length':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\Host':
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
case 'Utopia\Validator\WhiteList': /* @var $validator \Utopia\Validator\WhiteList */
|
||||||
|
$type = Type::string();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$type = 'string';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($required) {
|
||||||
|
$type = Type::nonNull($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArgs(array $params) {
|
||||||
|
$args = [];
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
var_dump("Key : ${key}");
|
||||||
|
var_dump($value);
|
||||||
|
$args[$key] = [
|
||||||
|
'type' => getArgType($value['validator'],!$value['optional']),
|
||||||
|
'description' => $value['description'],
|
||||||
|
'defaultValue' => $value['default']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSchema($utopia, $response) {
|
||||||
|
$start = microtime(true);
|
||||||
|
|
||||||
|
global $typeMapping;
|
||||||
|
$fields = [];
|
||||||
|
foreach($utopia->getRoutes() as $method => $routes ){
|
||||||
|
if ($method == "GET") {
|
||||||
|
foreach($routes as $route) {
|
||||||
|
$namespace = $route->getLabel('sdk.namespace', '');
|
||||||
|
if( true ) {
|
||||||
|
$methodName = $namespace.'_'.$route->getLabel('sdk.method', '');
|
||||||
|
$responseModelName = $route->getLabel('sdk.response.model', Response::MODEL_NONE);
|
||||||
|
|
||||||
|
var_dump("******************************************");
|
||||||
|
var_dump("Model Name : ${responseModelName}");
|
||||||
|
|
||||||
|
if ( $responseModelName !== Response::MODEL_NONE && $responseModelName !== Response::MODEL_ANY ) {
|
||||||
|
$responseModel = $response->getModel($responseModelName);
|
||||||
|
createTypeMapping($responseModel, $response);
|
||||||
|
$fields[$methodName] = [
|
||||||
|
'type' => $typeMapping[$responseModel->getType()],
|
||||||
|
'description' => $route->getDesc(),
|
||||||
|
'args' => getArgs($route->getParams()),
|
||||||
|
];
|
||||||
|
|
||||||
|
// print_r($fields[$methodName]);
|
||||||
|
var_dump("Processed route : {$route->getURL()}");
|
||||||
|
} else {
|
||||||
|
var_dump("Skipping route : {$route->getURL()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($fields);
|
||||||
|
|
||||||
|
$queryType = new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'description' => 'The root of all your queries',
|
||||||
|
'fields' => $fields
|
||||||
|
]);
|
||||||
|
|
||||||
|
$schema = new Schema([
|
||||||
|
'query' => $queryType
|
||||||
|
]);
|
||||||
|
|
||||||
|
$time_elapsed_secs = microtime(true) - $start;
|
||||||
|
|
||||||
|
var_dump("Time Taken To Build Schema : ${time_elapsed_secs}s");
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
App::post('/v1/graphql')
|
App::post('/v1/graphql')
|
||||||
->desc('GraphQL Endpoint')
|
->desc('GraphQL Endpoint')
|
||||||
->groups(['api', 'graphql'])
|
->groups(['api', 'graphql'])
|
||||||
->label('scope', 'public')
|
->label('scope', 'public')
|
||||||
->action(
|
->inject('request')
|
||||||
function () use ($request, $response, $utopia) {
|
->inject('response')
|
||||||
|
->inject('utopia')
|
||||||
foreach ($utopia->getRoutes() as $method => $routes) {
|
->inject('schema')
|
||||||
var_dump($method);
|
->action(function ($request, $response, $utopia, $schema) {
|
||||||
|
// Generate the Schema of the server on startup.
|
||||||
foreach ($routes as $key => $route) {
|
// Use the routes from utopia and get the params then construct the queries and mutations.
|
||||||
var_dump($key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$userType = new ObjectType([
|
|
||||||
'name' => 'User',
|
|
||||||
'fields' => [
|
|
||||||
'name' => [
|
|
||||||
'type' => Type::string(),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$queryType = new ObjectType([
|
|
||||||
'name' => 'Query',
|
|
||||||
'fields' => [
|
|
||||||
'echo' => [
|
|
||||||
'type' => Type::string(),
|
|
||||||
'args' => [
|
|
||||||
'message' => ['type' => Type::string()],
|
|
||||||
],
|
|
||||||
'resolve' => function ($rootValue, $args) {
|
|
||||||
return $rootValue['prefix'] . $args['message'];
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'users' => [
|
|
||||||
'type' => Type::listOf($userType),
|
|
||||||
//'type' => $userType,
|
|
||||||
'args' => [
|
|
||||||
'message' => ['type' => Type::string()],
|
|
||||||
],
|
|
||||||
'resolve' => function ($rootValue, $args) {
|
|
||||||
return ['name' => 'Eldad Fux'];
|
|
||||||
return [
|
|
||||||
['name' => 'Eldad Fux'],
|
|
||||||
['name' => 'Sharon Kapon'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$mutationType = new ObjectType([
|
|
||||||
'name' => 'Mutation',
|
|
||||||
'fields' => [
|
|
||||||
'sum' => [
|
|
||||||
'type' => Type::int(),
|
|
||||||
'args' => [
|
|
||||||
'x' => ['type' => Type::int()],
|
|
||||||
'y' => ['type' => Type::int()],
|
|
||||||
],
|
|
||||||
'resolve' => function ($calc, $args) {
|
|
||||||
return $args['x'] + $args['y'];
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$schema = new Schema([
|
|
||||||
'query' => $queryType,
|
|
||||||
'mutation' => $mutationType,
|
|
||||||
]);
|
|
||||||
|
|
||||||
|
$schema = buildSchema($utopia, $response);
|
||||||
$query = $request->getPayload('query', '');
|
$query = $request->getPayload('query', '');
|
||||||
$variables = $request->getPayload('variables', null);
|
$variables = $request->getPayload('variables', null);
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$rootValue = [];
|
$rootValue = [];
|
||||||
$result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variables);
|
$result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variables);
|
||||||
|
@ -128,7 +259,6 @@ App::post('/v1/graphql')
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
$response->json($output);
|
$response->json($output);
|
||||||
echo "\n"; //TODO REMOVE THIS
|
echo "\n"; //TODO REMOVE THIS
|
||||||
}
|
}
|
||||||
|
|
|
@ -495,7 +495,7 @@ services:
|
||||||
ports:
|
ports:
|
||||||
- '9505:4000'
|
- '9505:4000'
|
||||||
environment:
|
environment:
|
||||||
- API_URL=http://192.168.1.102/v1/graphql
|
- API_URL=http://localhost/v1/graphql
|
||||||
image: npalm/graphiql
|
image: npalm/graphiql
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
|
|
Loading…
Reference in a new issue