Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Directives Plugin #57

Open
jhnnsrs opened this issue Apr 23, 2023 · 0 comments
Open

WIP: Directives Plugin #57

jhnnsrs opened this issue Apr 23, 2023 · 0 comments

Comments

@jhnnsrs
Copy link
Owner

jhnnsrs commented Apr 23, 2023

This plugin allows for add-in logic through custom directives, that will allow adding in
custom code generation logic through self directives, that then call user defined functions:

turms_directives:
          name_or_directive: #name of the directive
            locations: #the directive locations
              - "variable definition"
            type: "path.to.plugin.plugin_function" #the resolved plugin
            trim: True #will trim this directive from the generated graphql sdl (in the meta class)
            args: #additional args (aka @validator(arg1="arg1string")
              arg1: string 
def plugin_function(v: VariableDefinitionNode, body: List[AST], registry: ClassRegistry, arg1: str) -> List[AST]:

   # Custom logic defining alterations to this specific body (input will vary from plugin to plugin)
    return body

To illustrate the Usecase:

Sometypes it can become useful to introduce custom pydantic validaition logic for specific
arguments on operations:

mutation create_dataset(
  $name: String!
  $parent: ID
  $created_while: ID @validator(path: "mikro.scalars.get_current_id")
) {
  createDataset(name: $name, parent: $parent, createdWhile: $created_while) {
    ...Dataset
  }
}

Defining the plugin in graphql.config.yaml

turms_directives:
          validator:
            locations:
              - "variable definition"
            type: "validator.validator"
            args:
              path: string

Defined in yalidator.py
We define this validator directive plugin, that will import the validation functionality and put it as a call
for the validation function

def validator(v: VariableDefinitionNode, body: List[AST], registry: ClassRegistry, path: str):

    registry.register_import("pydantic.validator") # Custom imports
    registry.register_import(path) #Importing the function

    #Adding the field to the Arguments body
    body.append(
            ast.FunctionDef(
                name=registry.generate_parameter_name(v.variable.name.value) + "_validator",
                args=ast.arguments(
                    args=[
                        ast.arg(
                            arg="cls",
                        ),
                        ast.arg(
                            arg="value",
                        ),
                    ],
                    defaults=[],
                    kw_defaults=[],
                    kwarg=None,
                    kwonlyargs=[],
                    posonlyargs=[],
                    vararg=None,
                ),
                body=[
                    ast.Return(
                        value=ast.Call(
                            func=ast.Name(id=path.split(".")[-1], ctx=ast.Load()),
                            args=[ast.Name(id="cls", ctx=ast.Load()), ast.Name(id="value", ctx=ast.Load())],
                            keywords=[],
                        ),
                    ),
                ],
                decorator_list=[
                    ast.Call(
                            func=ast.Name(id="validator", ctx=ast.Load()),
                            args=[
                                ast.Constant(registry.generate_parameter_name(v.variable.name.value), ctx=ast.Load()),
                            ],
                            keywords=[
                                ast.keyword(arg="pre", value=ast.Constant(True, ctx=ast.Load())),
                                ast.keyword(arg="always", value=ast.Constant(True, ctx=ast.Load())),
                            ],
                        ),
                ],
                returns=None,
        
        )
    )
    return body

When now running the plugin turms will call the directive plugin on encounter and yield this result:

class Create_datasetMutation(BaseModel):
    create_dataset: Optional[DatasetFragment] = Field(alias="createDataset")

    class Arguments(BaseModel):
        name: str
        parent: Optional[ID]
        created_while: Optional[ID]

        @validator("created_while", pre=True, always=True)
        def created_while_validator(cls, value):
            return get_current_id(cls, value)

    class Meta:
        # directive is trimmed from the document
        document = "fragment Dataset on Dataset {\n  id\n  name\n  parent {\n    id\n  }\n  representations {\n    id\n    name\n  }\n  omerofiles {\n    id\n    name\n  }\n}\n\nmutation create_dataset($name: String!, $parent: ID, $created_while: AssignationID) {\n  createDataset(name: $name, parent: $parent, createdWhile: $created_while) {\n    ...Dataset\n  }\n}" 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant