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

[Question] Idea for making a graphql extension for exposed #316

Open
AllanWang opened this issue May 26, 2018 · 3 comments
Open

[Question] Idea for making a graphql extension for exposed #316

AllanWang opened this issue May 26, 2018 · 3 comments

Comments

@AllanWang
Copy link
Contributor

My goal for some time was to make a simple wrapper for exposed to allow it to generate graphql models and to load graphql queries.

As an example, the following tables:

object TestItems : IntIdTable() {
    val name = varchar("name", 64)
}

object TestSubItems : IntIdTable() {
    val parent = reference("parent", TestItems, ReferenceOption.CASCADE)
    val name = varchar("name", 64)
    val section = integer("section")
}

has all the info required for us to make the following graphql query:

{
    testItems {
        name
        children(section: 5, sortBy: { key: "name", order: ASC }) {
            name
        }
    }
}

I had two ideas around mapping exposed's entity to graphql schema, and have tested one of them at a basic level, but I'd like to have some of your input:


Annotations (Branch)

Example

class TestEntityDb(id: EntityID<Int>) : IntEntity(id) {
    companion object : IntEntityClass<TestItemDb>(TestEntityTable)

    @GraphQLField(name = "itemName")
    var name by TestEntityTable.name

    @GraphQLField(itemType = String::class) // should be TestSubItemDb::class
    val children by TestSubItemDb referrersOn TestSubItems.parent

    val greeting: String? by lazy { "Hello $name" }

    @GraphQLFieldIgnore
    var goodBye = "Bye"
}

Pros:

  • Allows for easy name configuration (pulled from property)
  • Supports all variables, not just those in exposed's DAO
  • Works with entities without any changes

Cons:

  • Uses reflection
  • No access to delegate attributes, making things like specifying a column value when querying a bit more verbose. You'd have to specify the column, and the argument name for graphql, and pay attention that it matches the actual field name (not required but to remain consistent).

Extensions (Branch)

Example:

class TestItemDb(id: EntityID<Int>) : IntEntity(id), GraphQLEntity<Int, TestItemDb> by GraphQLEntityHolder("testItem") {
    companion object : IntEntityClass<TestItemDb>(TestItems)

    var name by TestItems.name.graphQL("name", sortOption = true)

    val children by (TestSubItemDb referrersOn TestSubItems.parent).graphQL("children")
}

Pros:

  • No reflection
  • Makes use of delegates, meaning you will have full reference to Column<*>, Reference<*, *>`, etc. This means that if you extend the column delegate, you'd be able to add a boolean toggle to add it to the list of conditions that can be applied through graphql's arguments.

Cons:

  • Main con is that I can't currently call getValue directly from the delegate, as it requires a KProperty<*>. I'm not sure if kotlin supports/recommends calling getValue with my own created KProperty, or if it's best just to make it nullable, since you don't seem to be using it in most locations.
  • This will take more effort to set up and will be more integrated with exposed, but I do think that's a good thing.

Do you have any other ideas or inputs for this? The general idea is that people would be able to create tables with exposed, then use the dao or some other class to create a full graphql schema and loader, without having to spend a lot more effort. Most of the types and fetchers are already done through exposed with caching, so it should be doable and will save a lot of time in the future.

@Tapac
Copy link
Contributor

Tapac commented May 30, 2018

Hi @AllanWang , I never use GraphQL (only read about it), but from my POV approach with Annotations is much better, because it is more readable and requires less boilerplate. But possibly it is less configurable (I'm not sure).

BTW there is possibility to get access to delegate instance with getDelegate() function (see part in New Features), also you may intercept delegates creation with providingDelegate.

@AllanWang
Copy link
Contributor Author

I'll take a look. From what I saw, a lot of the get delegate methods required an instance of the class, so maybe that was another set of methods

@RdeWilde
Copy link

I prefer the extensions, because you can use more programming features that way. For me annotations always been something of a hack.

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

3 participants