Coder Social home page Coder Social logo

graphql-pagination-plugin's Introduction

Snapshot Release

GraphQL-pagination-plugin

Plugin for the Kotlin compiler to generate boilerplate code for graphql-pagination for use with kgraphql.

The generated pagination is implemented according to the graphQL-best practice.

Project setup

Gradle

Besides the compile dependency

build.gradle.kts

repositories {
    mavenCentral()
    maven { url = uri("https://maven.pkg.github.com/linked-planet/graphql-pagination-plugin") }
}

dependencies {
    implementation(group = "com.apurebase", name = "kgraphql", version = kGraphQLVersion)
    compile(group = "com.linked-planet.plugin", name = "graphql-plugin", version = graphQLPluginVersion) 
}

using this plugin will require letting the compiler know it is supposed to use it. To allow for this, we need to determine the location of its jar-file.

build.gradle.kts

fun classpathOf(dependency: String): File? {
    val regex = Regex(".*${dependency.replace(':', '-')}.*")
    return project.configurations.compile.get().firstOrNull { regex.matches(it.name) }
}

tasks.withType<KotlinCompile> {
    kotlinOptions.jvmTarget = jvmTarget
    kotlinOptions.freeCompilerArgs = listOf(
        "-Xplugin=${classpathOf("graphql-plugin:$graphQLPluginVersion")}",
        "-P", "plugin:arrow.meta.plugin.compiler:generatedSrcOutputDir=${buildDir}"
    )
}

Usage

Usage of this is pretty simple, each data class to be paginated needs two things:

  • @Paginated annotation
  • a property annotated with @Identifier
  • a companion object (may also be empty)
import com.linkedplanet.plugin.graphqlplugin.*

@Paginated
data class Example(
    @Identifier val uniqueId: Int, 
    val someNumber: Int
    ) { companion object }

The Property chosen with @Identifier will influence the type signature of all functions that externalize the pagination (i.e. SQL-Queries).

Now you can extend your schema with the generated functionality:

Connection Properties

In memory pagination

KGraphQL.schema { 
    type<PageInfo>() // part of com.linkedplanet.plugin.graphqlplugin
    Example.registerTypes(this)
    type<SomeType>() {
        Example.connectionProperty(
            this,
            "exampleConnections", 
            { parent: SomeType -> ExampleProvider.getExamplesForParent(parent) }// :(SomeType)->List<Example>
        )
    }
    
    //...
}

Externalized pagination

KGraphQL.schema { 
    type<PageInfo>() // part of com.linkedplanet.plugin.graphqlplugin
    Example.registerTypes(this)
    type<SomeType>() {
        Example.connectionProperty(
            this,
            "exampleConnections",
            // (SomeType)->Int
            ExampleProvider::getTotalCount, 
            // (SomeType, Type of the Identifier-annotated Property) -> Int
            ExampleProvider::getCountAfterCursor, 
            // :(SomeType, Int?, Type of the Identifier-annotated Property)->List<Example>
            ExampleProvider::getPaginatedExamplesForParent 
        )
    }
    
    //...
}

Now, given a query that returns an instance of SomeType, let's call it something we can make use of the paginated property.

{
    something {
        exampleConnections(first: 2, after: "Mg==") {
            edges {
                cursor
                node {
                    someNumber
                }
            }
            pageInfo {
                lastCursor
                lastPage
            }    
            totalCount
        }
    }
} 

Paginated Queries

The usage of paginated queries produces a bit different schema, as direct access to the queried items is preferable to producing a connection-like schema.

Usage however is not more complicated because of this.

KGraphQL.schema {
    type<PageInfo>() // part of com.linkedplanet.plugin.graphqlplugin
    Example.registerTypes(this)
    type<Example>() {
        Example.cursorProperty(this) // provides a property 'cursor' on each object for use with the after-parameter

        property<Int>("totalCount") { // Not necessarily useful as it'd be repeated for each entry
            resolver { _ ->
                ExampleProvider.getExampleCount()
            }
        }
    }
    
    Example.paginatedQuery(
        this, 
        "allExamples", 
        0) // 0 is the default value for the parameter if no after-parameter is provided
    { first: Int, after: Int ->
        ExampleProvider.getExamples
    }
    //...
}

With this snippet, the query is fully usable

{
    allExamples(first: 1, after: "MQ==") {
        cursor
        someNumber
        totalCount
    }
} 

Alternative

One can also use the generated paginateInMemory function:

fun List<Example>.paginateInMemory(first: Int?, after: String?): ExampleConnection

It is more generally useful as it can also be used to build paginated queries in the schema. However, it also exposes one of the generated Types directly (ExampleConnection).

On Identifiers

Currently only values of type Int or String are fully supported to be annotated as Identifier. One can, however, easily extend the support by providing a parse function on the target-type:

fun TargetType.Companion.parse(s: String): TargetType = TODO()

The only requirement to this function is that

val target: TargetType // = ...
TargetType.parse(target.toString()) == target

must hold.

To come

  • Paginated queries helper
  • Non-connection type pagination (no edges or pageInfo)

graphql-pagination-plugin's People

Contributors

p-louis avatar

Watchers

James Cloos avatar Alexander Weickmann avatar  avatar

graphql-pagination-plugin's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.