Skip to content

WIP: Directives Plugin #57

@jhnnsrs

Description

@jhnnsrs

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}" 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions