| 
 | 1 | +<?php  | 
 | 2 | + | 
 | 3 | +namespace Nuwave\Lighthouse\Select;  | 
 | 4 | + | 
 | 5 | +use GraphQL\Language\AST\Node;  | 
 | 6 | +use GraphQL\Language\AST\UnionTypeDefinitionNode;  | 
 | 7 | +use Illuminate\Database\Eloquent\Model;  | 
 | 8 | +use Nuwave\Lighthouse\Schema\AST\ASTBuilder;  | 
 | 9 | +use Nuwave\Lighthouse\Schema\AST\ASTHelper;  | 
 | 10 | + | 
 | 11 | +class SelectHelper  | 
 | 12 | +{  | 
 | 13 | +    /**  | 
 | 14 | +     * Given a field definition node, resolve info, and a model name, return the SQL columns that should be selected.  | 
 | 15 | +     * Accounts for relationships and the rename and select directives.  | 
 | 16 | +     *  | 
 | 17 | +     * @param mixed[] $fieldSelection  | 
 | 18 | +     * @return string[]  | 
 | 19 | +     */  | 
 | 20 | +    public static function getSelectColumns(Node $definitionNode, array $fieldSelection, string $modelName): array  | 
 | 21 | +    {  | 
 | 22 | +        $returnTypeName = ASTHelper::getUnderlyingTypeName($definitionNode);  | 
 | 23 | + | 
 | 24 | +        /** @var \Nuwave\Lighthouse\Schema\AST\DocumentAST $documentAST */  | 
 | 25 | +        $documentAST = app(ASTBuilder::class)->documentAST();  | 
 | 26 | + | 
 | 27 | +        $type = $documentAST->types[$returnTypeName];  | 
 | 28 | +        // error_log(print_r($type, true));  | 
 | 29 | + | 
 | 30 | +        if ($type instanceof UnionTypeDefinitionNode) {  | 
 | 31 | +            $type = $documentAST->types[ASTHelper::getUnderlyingTypeName($type->types[0])];  | 
 | 32 | +        }  | 
 | 33 | + | 
 | 34 | + | 
 | 35 | +        /** @var iterable<\GraphQL\Language\AST\FieldDefinitionNode> $fieldDefinitions */  | 
 | 36 | +        $fieldDefinitions = $type->fields;  | 
 | 37 | + | 
 | 38 | +        $model = new $modelName;  | 
 | 39 | + | 
 | 40 | +        $selectColumns = [];  | 
 | 41 | + | 
 | 42 | +        foreach ($fieldSelection as $field) {  | 
 | 43 | +            $fieldDefinition = ASTHelper::firstByName($fieldDefinitions, $field);  | 
 | 44 | + | 
 | 45 | +            if ($fieldDefinition) {  | 
 | 46 | +                $directivesRequiringLocalKey = ['hasOne', 'hasMany', 'count'];  | 
 | 47 | +                $directivesRequiringForeignKey = ['belongsTo', 'belongsToMany', 'morphTo'];  | 
 | 48 | +                $directivesRequiringKeys = array_merge($directivesRequiringLocalKey, $directivesRequiringForeignKey);  | 
 | 49 | + | 
 | 50 | +                foreach ($directivesRequiringKeys as $directiveType) {  | 
 | 51 | +                    if (ASTHelper::hasDirective($fieldDefinition, $directiveType)) {  | 
 | 52 | +                        $directive = ASTHelper::directiveDefinition($fieldDefinition, $directiveType);  | 
 | 53 | + | 
 | 54 | +                        if (in_array($directiveType, $directivesRequiringLocalKey)) {  | 
 | 55 | +                            $relationName = ASTHelper::directiveArgValue($directive, 'relation', $field);  | 
 | 56 | + | 
 | 57 | +                            if (method_exists($model, $relationName)) {  | 
 | 58 | +                                array_push($selectColumns, $model->{$relationName}()->getLocalKeyName());  | 
 | 59 | +                            }  | 
 | 60 | +                        }  | 
 | 61 | + | 
 | 62 | +                        if (in_array($directiveType, $directivesRequiringForeignKey)) {  | 
 | 63 | +                            $relationName = ASTHelper::directiveArgValue($directive, 'relation', $field);  | 
 | 64 | + | 
 | 65 | +                            if (method_exists($model, $relationName)) {  | 
 | 66 | +                                array_push($selectColumns, $model->{$relationName}()->getForeignKeyName());  | 
 | 67 | +                            }  | 
 | 68 | +                        }  | 
 | 69 | + | 
 | 70 | +                        continue 2;  | 
 | 71 | +                    }  | 
 | 72 | +                }  | 
 | 73 | + | 
 | 74 | +                if (ASTHelper::hasDirective($fieldDefinition, 'select')) {  | 
 | 75 | +                    // append selected columns in select directive to seletion  | 
 | 76 | +                    $directive = ASTHelper::directiveDefinition($fieldDefinition, 'select');  | 
 | 77 | + | 
 | 78 | +                    if ($directive) {  | 
 | 79 | +                        $selectFields = ASTHelper::directiveArgValue($directive, 'columns') ?? [];  | 
 | 80 | +                        $selectColumns = array_merge($selectColumns, $selectFields);  | 
 | 81 | +                    }  | 
 | 82 | +                } elseif (ASTHelper::hasDirective($fieldDefinition, 'rename')) {  | 
 | 83 | +                    // append renamed attribute to selection  | 
 | 84 | +                    $directive = ASTHelper::directiveDefinition($fieldDefinition, 'rename');  | 
 | 85 | + | 
 | 86 | +                    if ($directive) {  | 
 | 87 | +                        $renamedAttribute = ASTHelper::directiveArgValue($directive, 'attribute');  | 
 | 88 | +                        array_push($selectColumns, $renamedAttribute);  | 
 | 89 | +                    }  | 
 | 90 | +                } else {  | 
 | 91 | +                    // fallback to selecting the field name  | 
 | 92 | +                    array_push($selectColumns, $field);  | 
 | 93 | +                }  | 
 | 94 | +            }  | 
 | 95 | +        }  | 
 | 96 | + | 
 | 97 | +        return array_unique($selectColumns);  | 
 | 98 | +    }  | 
 | 99 | +}  | 
0 commit comments