{"id":18456321,"url":"https://github.com/martmists-gh/graphql-exposed","last_synced_at":"2026-05-03T05:44:12.485Z","repository":{"id":237456818,"uuid":"663678373","full_name":"Martmists-GH/GraphQL-Exposed","owner":"Martmists-GH","description":"This repository holds a prototype for binding KGraphQL to Exposed's DAO models","archived":false,"fork":false,"pushed_at":"2023-07-07T21:23:22.000Z","size":71,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-16T14:58:22.471Z","etag":null,"topics":["exposed","exposed-orm","graphql","kotlin","ksp"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Martmists-GH.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-07T21:23:06.000Z","updated_at":"2023-07-08T12:42:26.000Z","dependencies_parsed_at":"2024-05-02T02:43:03.281Z","dependency_job_id":"e59cdd36-14f0-46d5-86ce-66db8b388828","html_url":"https://github.com/Martmists-GH/GraphQL-Exposed","commit_stats":null,"previous_names":["martmists-gh/graphql-exposed"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Martmists-GH%2FGraphQL-Exposed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Martmists-GH%2FGraphQL-Exposed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Martmists-GH%2FGraphQL-Exposed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Martmists-GH%2FGraphQL-Exposed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Martmists-GH","download_url":"https://codeload.github.com/Martmists-GH/GraphQL-Exposed/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250307794,"owners_count":21409146,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["exposed","exposed-orm","graphql","kotlin","ksp"],"created_at":"2024-11-06T08:11:09.537Z","updated_at":"2026-05-03T05:44:07.454Z","avatar_url":"https://github.com/Martmists-GH.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GraphQL-Exposed Prototype\n\nThis is a prototype project to showcase codegen for binding Exposed's DAO API to KGraphQL.\nIn a production environment, the gql-annotations and gql-processor folders would be external libraries.\n\n## How it works\n\nLet's look at an example DAO:\n\n```kotlin\n@GraphQLModel\nclass Film(id: EntityID\u003cInt\u003e) : IntEntity(id) {\n    companion object : IntEntityClass\u003cFilm\u003e(FilmTable)\n\n    var name by FilmTable.name\n    var year by FilmTable.year\n    var director by Person referencedOn FilmTable.director\n    var characters by Character via FilmCharacterTable\n    var actors by Person via FilmCharacterTable\n}\n```\n\nThe `@GraphQLModel` annotation is processed by the gql-processor, which generates a `FilmGraphQLModel` class, remapping the properties:\n\n```kotlin\n// Automatically generated from the public properties and @GraphQLModel annotation on Film\nclass FilmGraphQL(internal val instance: Film) {\n    val id = instance.id.value\n    var name: kotlin.String\n        get() = instance.name\n        set(value) { instance.name = value }\n    var year: kotlin.Int\n        get() = instance.year\n        set(value) { instance.year = value }\n    var director: com.example.db.models.PersonGraphQL\n        get() = instance.director.graphql\n        set(value) { instance.director = value.instance }\n    var characters: Iterable\u003ccom.example.db.models.CharacterGraphQL\u003e\n        get() = instance.characters.map { com.example.db.models.CharacterGraphQL(it) }\n        set(value) { instance.characters = SizedCollection(value.map { it.instance }) }\n    var actors: Iterable\u003ccom.example.db.models.PersonGraphQL\u003e\n        get() = instance.actors.map { com.example.db.models.PersonGraphQL(it) }\n        set(value) { instance.actors = SizedCollection(value.map { it.instance }) }\n}\n```\n\nThen an autogenerated remapper can be used to convert DAOs to GraphQL models:\n\n```kotlin\nquery(\"films\") {\n    resolver { -\u003e\n        Film.all().map(Film::graphql)\n    }\n}\n```     \n\nThe reason for this is that the DAOs have their attributes computed lazily in a manner which is incompatible with KGraphQL's reflection-based approach. \nThe FilmGraphQL class instead just generates getters and setters, which KGraphQL can use to access the DAO's properties indirectly. (Except for the ID property, which is always retrieved.)\n\nHowever, due to the way Exposed's DAOs work, we need to be in a transaction to access the properties. As such, we need to add the following snippet to Ktor. Note that in production, this would just be `install(GraphQLExposedPatch)`\n\n```kotlin\ninstall(GraphQL) {\n    // ...\n    // The Executor must NOT be set to Parallel, as this will cause ConcurrentModificationExceptions in the Transaction.\n    executor = Executor.DataLoaderPrepared\n}\n\ninstall(object : Plugin\u003cApplication, Unit, Unit\u003e {\n    override val key: AttributeKey\u003cUnit\u003e = AttributeKey(\"GraphQL-Database\")\n\n    override fun install(pipeline: Application, configure: Unit.() -\u003e Unit) {\n        pipeline.intercept(ApplicationCallPipeline.Plugins) {\n            if (call.request.path() == \"/graphql\" \u0026\u0026 call.request.httpMethod == HttpMethod.Post) {\n                // Start a transaction for GraphQL POST requests\n                newSuspendedTransaction {\n                    proceed()\n                }\n            } else {\n                proceed()\n            }\n        }\n    }\n})\n```\n\n## Hiding Fields\n\nFields can be hidden by using the `@HideGraphQLField` annotation:\n\n```kotlin\n@GraphQLModel\nclass Film(id: EntityID\u003cInt\u003e) : IntEntity(id) {\n    companion object : IntEntityClass\u003cFilm\u003e(FilmTable)\n\n    var name by FilmTable.name\n    var year by FilmTable.year\n    var director by Person referencedOn FilmTable.director\n    var characters by Character via FilmCharacterTable\n    var actors by Person via FilmCharacterTable\n\n    @HideGraphQLField\n    var hiddenField by FilmTable.hiddenField\n}\n```\n\n`hiddenField` will not be added to the FilmGraphQL class, and as such will not show up in the Schema.\n\n## Limitations\n\nUnfortunately this breaks inheritance in autogenerated models, but this can still be done by manually converting DAOs to GraphQL models.\n\nAll other features such as access rules still work, but must be defined on their GraphQL models:\n\n```kotlin\ntype\u003cFilmGraphQL\u003e {\n    property(\"characters\") {\n        // A resolver must be manually defined for accessRule to not crash\n        resolver { film -\u003e\n            film.characters\n        }\n\n        accessRule { film, context -\u003e\n            GraphQLError(\"Nobody can see the characters of a film\")\n        }\n    }\n}\n```\n\n## License\n\nThis project is licensed under CC0; Do whatever you want with it. However, I would appreciate it if you could credit me where applicable, in the event you were to use this as basis for a proper library and processor.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartmists-gh%2Fgraphql-exposed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartmists-gh%2Fgraphql-exposed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartmists-gh%2Fgraphql-exposed/lists"}