From ceeccf9496b5a7fd2bf236049977e28b3f949928 Mon Sep 17 00:00:00 2001 From: Kareem Ebrahim <89863279+kareemmahlees@users.noreply.github.com> Date: Sat, 28 Dec 2024 21:48:20 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20improve=20the=20documentation=20of=20th?= =?UTF-8?q?e=20endpoints=20=F0=9F=93=9D=20(#13)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(docs): server url * docs: better document default handlers * docs: better document database related operations * docs: change tables tag name and add a description * docs: better document list tables endpoint * docs: better document getting table info * docs: better document create table endpoint * docs: document remaining endpoints * docs: some small fixes * docs: better document query descriptions * docs: finish up documenting graphql operations --- docs/swagger.json | 11 +- docs/swagger.yaml | 355 ++++++++-- internal/db/mysql.go | 6 +- internal/db/pg.go | 6 +- internal/db/sqlite.go | 6 +- internal/db/storage.go | 2 +- internal/graph/generated.go | 866 +++++++++++------------ internal/graph/model/models_gen.go | 51 +- internal/graph/schema.graphql | 46 +- internal/graph/schema.resolvers.go | 8 +- internal/handlers/dbHandlers.go | 20 +- internal/handlers/defaultHandler.go | 41 +- internal/handlers/defaultHandler_test.go | 8 - internal/handlers/tableHandlers.go | 118 +-- internal/handlers/tableHandlers_test.go | 8 +- internal/server.go | 1 + internal/server_test.go | 2 +- main.go | 10 +- models/common.go | 36 +- models/database.go | 5 +- models/tables.go | 50 +- 21 files changed, 1007 insertions(+), 649 deletions(-) diff --git a/docs/swagger.json b/docs/swagger.json index 3458fc0..1fc0a60 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,10 +1,15 @@ { - "components": {"schemas":{"handlers.APIInfoResult":{"properties":{"author":{"type":"string"},"contact":{"type":"string"},"repo":{"type":"string"},"yeaer":{"type":"integer"}},"type":"object"},"handlers.HealthCheckResult":{"properties":{"date":{"type":"string"}},"type":"object"},"models.AddModifyColumnPayload":{"properties":{"column_name":{"type":"string"},"type":{"type":"string"}},"required":["column_name","type"],"type":"object"},"models.CreateTablePayload":{"properties":{"column_name":{"type":"string"},"default":{},"nullable":{},"type":{"type":"string"},"unique":{}},"required":["column_name","type"],"type":"object"},"models.CreateTableResp":{"properties":{"created":{"type":"string"}},"type":"object"},"models.DeleteColumnPayload":{"properties":{"column_name":{"type":"string"}},"required":["column_name"],"type":"object"},"models.ListDatabasesResp":{"properties":{"databases":{"items":{"type":"string"},"type":"array"}},"type":"object"},"models.ListTablesResp":{"properties":{"tables":{"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"models.SuccessResp":{"properties":{"success":{"type":"boolean"}},"type":"object"},"models.TableInfoResp":{"properties":{"default":{},"key":{},"name":{"type":"string"},"nullable":{"type":"string"},"type":{"type":"string"}},"type":"object"}}}, + "components": {"schemas":{"handlers.APIInfo":{"description":"General Info about the API, author name, how to contact, etc.","properties":{"author":{"description":"Author name.","example":"Kareem Ebrahim","type":"string"},"contact":{"description":"How to contact the author.","example":"kareemmahlees@gmail.com","type":"string"},"repo":{"description":"Git repository name for contributions.","example":"https://github.com/kareemmahlees/meta-x","type":"string"},"year":{"description":"Year of launch","example":2024,"type":"integer"}},"type":"object"},"models.AddModifyColumnPayload":{"description":"Adding or Modifying a column payload.","properties":{"column_name":{"description":"Column Name","type":"string"},"type":{"description":"New type","example":"Int","type":"string"}},"required":["column_name","type"],"type":"object"},"models.BadRequestError":{"description":"Request payload failed validation.","properties":{"code":{"description":"HTTP code.","example":422,"type":"integer"},"message":{"description":"Error cause.","example":"Payload Failed Validation"}},"type":"object"},"models.CreatePgMySqlDBPayload":{"properties":{"name":{"description":"Database name.","example":"Users","type":"string"}},"required":["name"],"type":"object"},"models.CreateTablePayload":{"description":"Data about the column to create.","properties":{"column_name":{"description":"Name of the column.","type":"string"},"default":{"description":"Default value of the column."},"nullable":{"description":"If the column accepts null values or not."},"type":{"description":"Data type of the column.","type":"string"},"unique":{"description":"Wether to add a unique constraint on the column."}},"required":["column_name","type"],"type":"object"},"models.CreateTableResp":{"description":"Table Created Successfully.","properties":{"created":{"description":"Created table name.","type":"string"}},"type":"object"},"models.DeleteColumnPayload":{"description":"Column to delete data.","properties":{"column_name":{"description":"Column Name","type":"string"}},"required":["column_name"],"type":"object"},"models.ErrResp":{"description":"Operation Failed. Maybe invalid payload or internal server error.","properties":{"code":{"description":"HTTP code.","example":400,"type":"integer"},"message":{"description":"Error cause.","example":"Malformed payload"}},"type":"object"},"models.InternalServerError":{"description":"Something wrong happened on the server.","properties":{"code":{"description":"HTTP code.","example":500,"type":"integer"},"message":{"description":"Error cause.","example":"Something went wrong"}},"type":"object"},"models.ListDatabasesResp":{"description":"A list of all available databases.","properties":{"databases":{"example":["test","prod","main"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"models.ListTablesResp":{"description":"List of tables.","properties":{"tables":{"example":["table1","table2","table3"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"models.SuccessResp":{"description":"Operation Succeeded.","properties":{"success":{"type":"boolean"}},"type":"object"},"models.TableColumnInfo":{"description":"Info about a table column.","properties":{"default":{"description":"Default value of the column.","example":"123"},"key":{"description":"Constraint name on the column.","example":"PRI"},"name":{"description":"Name of the column.","example":"email","type":"string"},"nullable":{"description":"If the column accepts null values or not.","example":"true","type":"string"},"type":{"description":"Data type of the column.","example":"varchar","type":"string"}},"type":"object"},"models.UnprocessableEntityError":{"description":"Failed to parse payload.","properties":{"code":{"description":"HTTP code.","example":422,"type":"integer"},"message":{"description":"Error cause.","example":"Payload Parsing Failed"}},"type":"object"}}}, "info": {"contact":{"email":"kareemmahlees@gmail.com","name":"Kareem Ebrahim"},"description":"A RESTFull and GraphQL API to supercharge your database","title":"MetaX","version":"0.1.1"}, "externalDocs": {"description":"","url":""}, - "paths": {"/":{"get":{"description":"get info about the api","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.APIInfoResult"}}},"description":"OK"}},"tags":["default"]}},"/database":{"get":{"description":"list databases","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ListDatabasesResp"}}},"description":"OK"}},"tags":["Databases"]}},"/health":{"get":{"description":"check application health by getting current date","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.HealthCheckResult"}}},"description":"OK"}},"tags":["default"]}},"/table":{"get":{"description":"list tables","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ListTablesResp"}}},"description":"OK"}},"tags":["Tables"]}},"/table/{tableName}":{"delete":{"parameters":[{"description":"table name","in":"path","name":"tableName","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"OK"}},"tags":["Tables"]},"post":{"description":"create table","parameters":[{"description":"table name","in":"path","name":"tableName","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreateTablePayload"}}},"description":"create table data","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreateTableResp"}}},"description":"Created"}},"tags":["Tables"]}},"/table/{tableName}/column/add":{"post":{"description":"Add column to table","parameters":[{"description":"table name","in":"path","name":"tableName","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AddModifyColumnPayload"}}},"description":"column data","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"Created"}},"tags":["Tables"]}},"/table/{tableName}/column/delete":{"delete":{"description":"Delete/Drop table column","parameters":[{"description":"table name","in":"path","name":"tableName","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.DeleteColumnPayload"}}},"description":"column name","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"OK"}},"tags":["Tables"]}},"/table/{tableName}/column/modify":{"put":{"description":"Update table column","parameters":[{"description":"table name","in":"path","name":"tableName","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AddModifyColumnPayload"}}},"description":"column data","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"OK"}},"tags":["Tables"]}},"/table/{tableName}/describe":{"get":{"description":"Get detailed info about a specific table","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.TableInfoResp"},"type":"array"}}},"description":"OK"}},"tags":["Tables"]}}}, + "paths": {"/":{"get":{"description":"Get general info about the API","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/handlers.APIInfo"}}},"description":"OK"}},"summary":"Get API Info","tags":["General"]}},"/database":{"get":{"description":"Get all the available databases.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ListDatabasesResp"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"List Databases","tags":["Database"]},"post":{"description":"Creates a new database with the specified table schema.\n\n**NOTE**: SQLite is Unsupported.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreatePgMySqlDBPayload"}}},"description":"Database Info","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrResp"}}},"description":"Bad Request"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"Create a new Database","tags":["Database"]}},"/table":{"get":{"description":"Get a list of the available tables in the database.","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ListTablesResp"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"List tables.","tags":["Table"]}},"/table/{table_name}":{"delete":{"description":"Delete the given table.","parameters":[{"description":"Table Name","in":"path","name":"table_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"Delete Table","tags":["Table"]},"post":{"description":"Creates a new table with the specified columns.","parameters":[{"description":"Table Name","in":"path","name":"table_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.CreateTablePayload"},"type":"array"}}},"description":"Table Data","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreateTableResp"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.BadRequestError"}}},"description":"Bad Request"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.UnprocessableEntityError"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"Create a Table.","tags":["Table"]}},"/table/{table_name}/column/add":{"post":{"description":"Adds a column with the provided data to the given table.","parameters":[{"description":"Table Name","in":"path","name":"table_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AddModifyColumnPayload"}}},"description":"Column Data","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.BadRequestError"}}},"description":"Bad Request"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.UnprocessableEntityError"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"Add a column","tags":["Table"]}},"/table/{table_name}/column/delete":{"delete":{"description":"Delete table column","parameters":[{"description":"Table Name","in":"path","name":"table_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.DeleteColumnPayload"}}},"description":"Column Name","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.BadRequestError"}}},"description":"Bad Request"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.UnprocessableEntityError"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"Delete Column","tags":["Table"]}},"/table/{table_name}/column/modify":{"put":{"description":"Update table column properties, **Only supports updating the column type for now**.","parameters":[{"description":"Table Name","in":"path","name":"table_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AddModifyColumnPayload"}}},"description":"Column Data","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.SuccessResp"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.BadRequestError"}}},"description":"Bad Request"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.UnprocessableEntityError"}}},"description":"Unprocessable Entity"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"Update Column","tags":["Table"]}},"/table/{table_name}/describe":{"get":{"description":"Get detailed info about a table's fields.","parameters":[{"description":"Table Name","in":"path","name":"table_name","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/models.TableColumnInfo"},"type":"array"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.InternalServerError"}}},"description":"Internal Server Error"}},"summary":"Get table info","tags":["Table"]}}}, "openapi": "3.1.0", + "tags": [ + {"description":"general info about the API.","name":"General"}, + {"description":"Database level related operations.","name":"Database"}, + {"description":"Table Level related operations.","name":"Table"} + ], "servers": [ - {"description":"Home town of Meta-X","url":"localhost:5522"} + {"description":"Home town of Meta-X","url":"http://localhost:5522"} ] } \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 8fa11a6..edc16ed 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,87 +1,181 @@ components: schemas: - handlers.APIInfoResult: + handlers.APIInfo: + description: General Info about the API, author name, how to contact, etc. properties: author: + description: Author name. + example: Kareem Ebrahim type: string contact: + description: How to contact the author. + example: kareemmahlees@gmail.com type: string repo: + description: Git repository name for contributions. + example: https://github.com/kareemmahlees/meta-x type: string - yeaer: + year: + description: Year of launch + example: 2024 type: integer type: object - handlers.HealthCheckResult: - properties: - date: - type: string - type: object models.AddModifyColumnPayload: + description: Adding or Modifying a column payload. properties: column_name: + description: Column Name type: string type: + description: New type + example: Int type: string required: - column_name - type type: object + models.BadRequestError: + description: Request payload failed validation. + properties: + code: + description: HTTP code. + example: 422 + type: integer + message: + description: Error cause. + example: Payload Failed Validation + type: object + models.CreatePgMySqlDBPayload: + properties: + name: + description: Database name. + example: Users + type: string + required: + - name + type: object models.CreateTablePayload: + description: Data about the column to create. properties: column_name: + description: Name of the column. type: string - default: {} - nullable: {} + default: + description: Default value of the column. + nullable: + description: If the column accepts null values or not. type: + description: Data type of the column. type: string - unique: {} + unique: + description: Wether to add a unique constraint on the column. required: - column_name - type type: object models.CreateTableResp: + description: Table Created Successfully. properties: created: + description: Created table name. type: string type: object models.DeleteColumnPayload: + description: Column to delete data. properties: column_name: + description: Column Name type: string required: - column_name type: object + models.ErrResp: + description: Operation Failed. Maybe invalid payload or internal server error. + properties: + code: + description: HTTP code. + example: 400 + type: integer + message: + description: Error cause. + example: Malformed payload + type: object + models.InternalServerError: + description: Something wrong happened on the server. + properties: + code: + description: HTTP code. + example: 500 + type: integer + message: + description: Error cause. + example: Something went wrong + type: object models.ListDatabasesResp: + description: A list of all available databases. properties: databases: + example: + - test + - prod + - main items: type: string type: array + uniqueItems: false type: object models.ListTablesResp: + description: List of tables. properties: tables: + example: + - table1 + - table2 + - table3 items: type: string type: array uniqueItems: false type: object models.SuccessResp: + description: Operation Succeeded. properties: success: type: boolean type: object - models.TableInfoResp: + models.TableColumnInfo: + description: Info about a table column. properties: - default: {} - key: {} + default: + description: Default value of the column. + example: "123" + key: + description: Constraint name on the column. + example: PRI name: + description: Name of the column. + example: email type: string nullable: + description: If the column accepts null values or not. + example: "true" type: string type: + description: Data type of the column. + example: varchar type: string type: object + models.UnprocessableEntityError: + description: Failed to parse payload. + properties: + code: + description: HTTP code. + example: 422 + type: integer + message: + description: Error cause. + example: Payload Parsing Failed + type: object externalDocs: description: "" url: "" @@ -96,19 +190,20 @@ openapi: 3.1.0 paths: /: get: - description: get info about the api + description: Get general info about the API responses: "200": content: application/json: schema: - $ref: '#/components/schemas/handlers.APIInfoResult' + $ref: '#/components/schemas/handlers.APIInfo' description: OK + summary: Get API Info tags: - - default + - General /database: get: - description: list databases + description: Get all the available databases. responses: "200": content: @@ -116,23 +211,52 @@ paths: schema: $ref: '#/components/schemas/models.ListDatabasesResp' description: OK + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: List Databases tags: - - Databases - /health: - get: - description: check application health by getting current date + - Database + post: + description: |- + Creates a new database with the specified table schema. + + **NOTE**: SQLite is Unsupported. + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/models.CreatePgMySqlDBPayload' + description: Database Info + required: true responses: "200": content: application/json: schema: - $ref: '#/components/schemas/handlers.HealthCheckResult' + $ref: '#/components/schemas/models.SuccessResp' description: OK + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/models.ErrResp' + description: Bad Request + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: Create a new Database tags: - - default + - Database /table: get: - description: list tables + description: Get a list of the available tables in the database. responses: "200": content: @@ -140,14 +264,22 @@ paths: schema: $ref: '#/components/schemas/models.ListTablesResp' description: OK + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: List tables. tags: - - Tables - /table/{tableName}: + - Table + /table/{table_name}: delete: + description: Delete the given table. parameters: - - description: table name + - description: Table Name in: path - name: tableName + name: table_name required: true schema: type: string @@ -163,14 +295,21 @@ paths: schema: $ref: '#/components/schemas/models.SuccessResp' description: OK + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: Delete Table tags: - - Tables + - Table post: - description: create table + description: Creates a new table with the specified columns. parameters: - - description: table name + - description: Table Name in: path - name: tableName + name: table_name required: true schema: type: string @@ -178,8 +317,10 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/models.CreateTablePayload' - description: create table data + items: + $ref: '#/components/schemas/models.CreateTablePayload' + type: array + description: Table Data required: true responses: "201": @@ -188,15 +329,34 @@ paths: schema: $ref: '#/components/schemas/models.CreateTableResp' description: Created + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/models.BadRequestError' + description: Bad Request + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/models.UnprocessableEntityError' + description: Unprocessable Entity + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: Create a Table. tags: - - Tables - /table/{tableName}/column/add: + - Table + /table/{table_name}/column/add: post: - description: Add column to table + description: Adds a column with the provided data to the given table. parameters: - - description: table name + - description: Table Name in: path - name: tableName + name: table_name required: true schema: type: string @@ -205,7 +365,7 @@ paths: application/json: schema: $ref: '#/components/schemas/models.AddModifyColumnPayload' - description: column data + description: Column Data required: true responses: "201": @@ -214,15 +374,34 @@ paths: schema: $ref: '#/components/schemas/models.SuccessResp' description: Created + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/models.BadRequestError' + description: Bad Request + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/models.UnprocessableEntityError' + description: Unprocessable Entity + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: Add a column tags: - - Tables - /table/{tableName}/column/delete: + - Table + /table/{table_name}/column/delete: delete: - description: Delete/Drop table column + description: Delete table column parameters: - - description: table name + - description: Table Name in: path - name: tableName + name: table_name required: true schema: type: string @@ -231,7 +410,7 @@ paths: application/json: schema: $ref: '#/components/schemas/models.DeleteColumnPayload' - description: column name + description: Column Name required: true responses: "200": @@ -240,15 +419,35 @@ paths: schema: $ref: '#/components/schemas/models.SuccessResp' description: OK + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/models.BadRequestError' + description: Bad Request + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/models.UnprocessableEntityError' + description: Unprocessable Entity + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: Delete Column tags: - - Tables - /table/{tableName}/column/modify: + - Table + /table/{table_name}/column/modify: put: - description: Update table column + description: Update table column properties, **Only supports updating the column + type for now**. parameters: - - description: table name + - description: Table Name in: path - name: tableName + name: table_name required: true schema: type: string @@ -257,7 +456,7 @@ paths: application/json: schema: $ref: '#/components/schemas/models.AddModifyColumnPayload' - description: column data + description: Column Data required: true responses: "200": @@ -266,22 +465,62 @@ paths: schema: $ref: '#/components/schemas/models.SuccessResp' description: OK + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/models.BadRequestError' + description: Bad Request + "422": + content: + application/json: + schema: + $ref: '#/components/schemas/models.UnprocessableEntityError' + description: Unprocessable Entity + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: Update Column tags: - - Tables - /table/{tableName}/describe: + - Table + /table/{table_name}/describe: get: - description: Get detailed info about a specific table + description: Get detailed info about a table's fields. + parameters: + - description: Table Name + in: path + name: table_name + required: true + schema: + type: string responses: "200": content: application/json: schema: items: - $ref: '#/components/schemas/models.TableInfoResp' + $ref: '#/components/schemas/models.TableColumnInfo' type: array description: OK + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/models.InternalServerError' + description: Internal Server Error + summary: Get table info tags: - - Tables + - Table servers: - description: Home town of Meta-X - url: localhost:5522 + url: http://localhost:5522 +tags: +- description: general info about the API. + name: General +- description: Database level related operations. + name: Database +- description: Table Level related operations. + name: Table diff --git a/internal/db/mysql.go b/internal/db/mysql.go index 5f14476..df6ece4 100644 --- a/internal/db/mysql.go +++ b/internal/db/mysql.go @@ -43,7 +43,7 @@ func (p *mysqlProvider) CreateDB(dbName string) error { } return nil } -func (p *mysqlProvider) GetTable(tableName string) ([]*models.TableInfoResp, error) { +func (p *mysqlProvider) GetTable(tableName string) ([]*models.TableColumnInfo, error) { queryString := ` SELECT column_name AS name, column_type AS type, @@ -58,9 +58,9 @@ func (p *mysqlProvider) GetTable(tableName string) ([]*models.TableInfoResp, err return nil, err } defer rows.Close() - tablesDescriptions := []*models.TableInfoResp{} + tablesDescriptions := []*models.TableColumnInfo{} for rows.Next() { - tableDesc := new(models.TableInfoResp) + tableDesc := new(models.TableColumnInfo) err := rows.StructScan(tableDesc) if err != nil { return nil, err diff --git a/internal/db/pg.go b/internal/db/pg.go index 79ea181..b5e6836 100644 --- a/internal/db/pg.go +++ b/internal/db/pg.go @@ -46,7 +46,7 @@ func (p *pgProvider) CreateDB(dbName string) error { return nil } -func (p *pgProvider) GetTable(tableName string) ([]*models.TableInfoResp, error) { +func (p *pgProvider) GetTable(tableName string) ([]*models.TableColumnInfo, error) { queryString := ` SELECT col.column_name AS name, col.data_type AS type, @@ -61,9 +61,9 @@ func (p *pgProvider) GetTable(tableName string) ([]*models.TableInfoResp, error) return nil, err } defer rows.Close() - tablesDescriptions := []*models.TableInfoResp{} + tablesDescriptions := []*models.TableColumnInfo{} for rows.Next() { - tableDesc := new(models.TableInfoResp) + tableDesc := new(models.TableColumnInfo) err := rows.StructScan(tableDesc) if err != nil { return nil, err diff --git a/internal/db/sqlite.go b/internal/db/sqlite.go index f7540b1..eb365cc 100644 --- a/internal/db/sqlite.go +++ b/internal/db/sqlite.go @@ -45,7 +45,7 @@ func (p *SqliteProvider) CreateDB(dbName string) error { return errors.New("Unsupported") } -func (p *SqliteProvider) GetTable(tableName string) ([]*models.TableInfoResp, error) { +func (p *SqliteProvider) GetTable(tableName string) ([]*models.TableColumnInfo, error) { queryString := ` SELECT name,type, CASE when 'notnull' = 1 @@ -63,9 +63,9 @@ func (p *SqliteProvider) GetTable(tableName string) ([]*models.TableInfoResp, er return nil, err } defer rows.Close() - tablesDescriptions := []*models.TableInfoResp{} + tablesDescriptions := []*models.TableColumnInfo{} for rows.Next() { - tableDesc := new(models.TableInfoResp) + tableDesc := new(models.TableColumnInfo) err := rows.StructScan(tableDesc) if err != nil { return nil, err diff --git a/internal/db/storage.go b/internal/db/storage.go index f5f7dc1..6231799 100644 --- a/internal/db/storage.go +++ b/internal/db/storage.go @@ -14,7 +14,7 @@ type DatabaseExecuter interface { // Interface that must be implemented by any // storage driver dealing with table logic type TableExecuter interface { - GetTable(tableName string) ([]*models.TableInfoResp, error) + GetTable(tableName string) ([]*models.TableColumnInfo, error) ListTables() ([]*string, error) CreateTable(tableName string, data []models.CreateTablePayload) error DeleteTable(tableName string) error diff --git a/internal/graph/generated.go b/internal/graph/generated.go index 310c637..722cd66 100644 --- a/internal/graph/generated.go +++ b/internal/graph/generated.go @@ -45,6 +45,14 @@ type DirectiveRoot struct { } type ComplexityRoot struct { + ColumnInfo struct { + Default func(childComplexity int) int + Key func(childComplexity int) int + Name func(childComplexity int) int + Nullable func(childComplexity int) int + Type func(childComplexity int) int + } + CreateTableResponse struct { Created func(childComplexity int) int } @@ -52,7 +60,7 @@ type ComplexityRoot struct { Mutation struct { AddColumn func(childComplexity int, tableName string, data model.AddUpdateColumnData) int CreateDatabase func(childComplexity int, name string) int - CreateTable func(childComplexity int, name string, data []*model.CreateTableData) int + CreateTable func(childComplexity int, name string, data []*model.CreateColumnData) int DeleteColumn func(childComplexity int, tableName string, data *model.DeleteColumnData) int DeleteTable func(childComplexity int, name string) int ModifyColumn func(childComplexity int, tableName string, data model.AddUpdateColumnData) int @@ -67,19 +75,11 @@ type ComplexityRoot struct { SuccessResponse struct { Success func(childComplexity int) int } - - TableInfo struct { - Default func(childComplexity int) int - Key func(childComplexity int) int - Name func(childComplexity int) int - Nullable func(childComplexity int) int - Type func(childComplexity int) int - } } type MutationResolver interface { CreateDatabase(ctx context.Context, name string) (*model.SuccessResponse, error) - CreateTable(ctx context.Context, name string, data []*model.CreateTableData) (*model.CreateTableResponse, error) + CreateTable(ctx context.Context, name string, data []*model.CreateColumnData) (*model.CreateTableResponse, error) DeleteTable(ctx context.Context, name string) (*model.SuccessResponse, error) AddColumn(ctx context.Context, tableName string, data model.AddUpdateColumnData) (*model.SuccessResponse, error) ModifyColumn(ctx context.Context, tableName string, data model.AddUpdateColumnData) (*model.SuccessResponse, error) @@ -88,7 +88,7 @@ type MutationResolver interface { type QueryResolver interface { Databases(ctx context.Context) ([]*string, error) Tables(ctx context.Context) ([]*string, error) - Table(ctx context.Context, name *string) ([]*model.TableInfo, error) + Table(ctx context.Context, name *string) ([]*model.ColumnInfo, error) } type executableSchema struct { @@ -106,6 +106,41 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in _ = ec switch typeName + "." + field { + case "ColumnInfo.default": + if e.complexity.ColumnInfo.Default == nil { + break + } + + return e.complexity.ColumnInfo.Default(childComplexity), true + + case "ColumnInfo.key": + if e.complexity.ColumnInfo.Key == nil { + break + } + + return e.complexity.ColumnInfo.Key(childComplexity), true + + case "ColumnInfo.name": + if e.complexity.ColumnInfo.Name == nil { + break + } + + return e.complexity.ColumnInfo.Name(childComplexity), true + + case "ColumnInfo.nullable": + if e.complexity.ColumnInfo.Nullable == nil { + break + } + + return e.complexity.ColumnInfo.Nullable(childComplexity), true + + case "ColumnInfo.type": + if e.complexity.ColumnInfo.Type == nil { + break + } + + return e.complexity.ColumnInfo.Type(childComplexity), true + case "CreateTableResponse.created": if e.complexity.CreateTableResponse.Created == nil { break @@ -147,7 +182,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } - return e.complexity.Mutation.CreateTable(childComplexity, args["name"].(string), args["data"].([]*model.CreateTableData)), true + return e.complexity.Mutation.CreateTable(childComplexity, args["name"].(string), args["data"].([]*model.CreateColumnData)), true case "Mutation.deleteColumn": if e.complexity.Mutation.DeleteColumn == nil { @@ -218,41 +253,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.SuccessResponse.Success(childComplexity), true - case "TableInfo.default": - if e.complexity.TableInfo.Default == nil { - break - } - - return e.complexity.TableInfo.Default(childComplexity), true - - case "TableInfo.key": - if e.complexity.TableInfo.Key == nil { - break - } - - return e.complexity.TableInfo.Key(childComplexity), true - - case "TableInfo.name": - if e.complexity.TableInfo.Name == nil { - break - } - - return e.complexity.TableInfo.Name(childComplexity), true - - case "TableInfo.nullable": - if e.complexity.TableInfo.Nullable == nil { - break - } - - return e.complexity.TableInfo.Nullable(childComplexity), true - - case "TableInfo.type": - if e.complexity.TableInfo.Type == nil { - break - } - - return e.complexity.TableInfo.Type(childComplexity), true - } return 0, false } @@ -262,7 +262,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)} inputUnmarshalMap := graphql.BuildUnmarshalerMap( ec.unmarshalInputAddUpdateColumnData, - ec.unmarshalInputCreateTableData, + ec.unmarshalInputCreateColumnData, ec.unmarshalInputDeleteColumnData, ) first := true @@ -431,10 +431,10 @@ func (ec *executionContext) field_Mutation_createTable_args(ctx context.Context, } } args["name"] = arg0 - var arg1 []*model.CreateTableData + var arg1 []*model.CreateColumnData if tmp, ok := rawArgs["data"]; ok { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("data")) - arg1, err = ec.unmarshalNCreateTableData2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateTableDataᚄ(ctx, tmp) + arg1, err = ec.unmarshalNCreateColumnData2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateColumnDataᚄ(ctx, tmp) if err != nil { return nil, err } @@ -574,8 +574,8 @@ func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArg // region **************************** field.gotpl ***************************** -func (ec *executionContext) _CreateTableResponse_created(ctx context.Context, field graphql.CollectedField, obj *model.CreateTableResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_CreateTableResponse_created(ctx, field) +func (ec *executionContext) _ColumnInfo_name(ctx context.Context, field graphql.CollectedField, obj *model.ColumnInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ColumnInfo_name(ctx, field) if err != nil { return graphql.Null } @@ -588,26 +588,23 @@ func (ec *executionContext) _CreateTableResponse_created(ctx context.Context, fi }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Created, nil + return obj.Name, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(string) + res := resTmp.(*string) fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_CreateTableResponse_created(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ColumnInfo_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "CreateTableResponse", + Object: "ColumnInfo", Field: field, IsMethod: false, IsResolver: false, @@ -618,8 +615,8 @@ func (ec *executionContext) fieldContext_CreateTableResponse_created(ctx context return fc, nil } -func (ec *executionContext) _Mutation_createDatabase(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_createDatabase(ctx, field) +func (ec *executionContext) _ColumnInfo_type(ctx context.Context, field graphql.CollectedField, obj *model.ColumnInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ColumnInfo_type(ctx, field) if err != nil { return graphql.Null } @@ -632,7 +629,7 @@ func (ec *executionContext) _Mutation_createDatabase(ctx context.Context, field }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().CreateDatabase(rctx, fc.Args["name"].(string)) + return obj.Type, nil }) if err != nil { ec.Error(ctx, err) @@ -641,41 +638,26 @@ func (ec *executionContext) _Mutation_createDatabase(ctx context.Context, field if resTmp == nil { return graphql.Null } - res := resTmp.(*model.SuccessResponse) + res := resTmp.(*string) fc.Result = res - return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_createDatabase(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ColumnInfo_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "ColumnInfo", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "success": - return ec.fieldContext_SuccessResponse_success(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) + return nil, errors.New("field of type String does not have child fields") }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_createDatabase_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } -func (ec *executionContext) _Mutation_createTable(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_createTable(ctx, field) +func (ec *executionContext) _ColumnInfo_nullable(ctx context.Context, field graphql.CollectedField, obj *model.ColumnInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ColumnInfo_nullable(ctx, field) if err != nil { return graphql.Null } @@ -688,7 +670,7 @@ func (ec *executionContext) _Mutation_createTable(ctx context.Context, field gra }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().CreateTable(rctx, fc.Args["name"].(string), fc.Args["data"].([]*model.CreateTableData)) + return obj.Nullable, nil }) if err != nil { ec.Error(ctx, err) @@ -697,41 +679,26 @@ func (ec *executionContext) _Mutation_createTable(ctx context.Context, field gra if resTmp == nil { return graphql.Null } - res := resTmp.(*model.CreateTableResponse) + res := resTmp.(*string) fc.Result = res - return ec.marshalOCreateTableResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateTableResponse(ctx, field.Selections, res) + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_createTable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ColumnInfo_nullable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "ColumnInfo", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "created": - return ec.fieldContext_CreateTableResponse_created(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type CreateTableResponse", field.Name) + return nil, errors.New("field of type String does not have child fields") }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_createTable_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } -func (ec *executionContext) _Mutation_deleteTable(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_deleteTable(ctx, field) +func (ec *executionContext) _ColumnInfo_key(ctx context.Context, field graphql.CollectedField, obj *model.ColumnInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ColumnInfo_key(ctx, field) if err != nil { return graphql.Null } @@ -744,7 +711,7 @@ func (ec *executionContext) _Mutation_deleteTable(ctx context.Context, field gra }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().DeleteTable(rctx, fc.Args["name"].(string)) + return obj.Key, nil }) if err != nil { ec.Error(ctx, err) @@ -753,41 +720,26 @@ func (ec *executionContext) _Mutation_deleteTable(ctx context.Context, field gra if resTmp == nil { return graphql.Null } - res := resTmp.(*model.SuccessResponse) + res := resTmp.(interface{}) fc.Result = res - return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) + return ec.marshalOAny2interface(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_deleteTable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ColumnInfo_key(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "ColumnInfo", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "success": - return ec.fieldContext_SuccessResponse_success(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) + return nil, errors.New("field of type Any does not have child fields") }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_deleteTable_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } -func (ec *executionContext) _Mutation_addColumn(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_addColumn(ctx, field) +func (ec *executionContext) _ColumnInfo_default(ctx context.Context, field graphql.CollectedField, obj *model.ColumnInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ColumnInfo_default(ctx, field) if err != nil { return graphql.Null } @@ -800,7 +752,7 @@ func (ec *executionContext) _Mutation_addColumn(ctx context.Context, field graph }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AddColumn(rctx, fc.Args["tableName"].(string), fc.Args["data"].(model.AddUpdateColumnData)) + return obj.Default, nil }) if err != nil { ec.Error(ctx, err) @@ -809,41 +761,26 @@ func (ec *executionContext) _Mutation_addColumn(ctx context.Context, field graph if resTmp == nil { return graphql.Null } - res := resTmp.(*model.SuccessResponse) + res := resTmp.(interface{}) fc.Result = res - return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) + return ec.marshalOAny2interface(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_addColumn(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ColumnInfo_default(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "ColumnInfo", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "success": - return ec.fieldContext_SuccessResponse_success(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) + return nil, errors.New("field of type Any does not have child fields") }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_addColumn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } -func (ec *executionContext) _Mutation_modifyColumn(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_modifyColumn(ctx, field) +func (ec *executionContext) _CreateTableResponse_created(ctx context.Context, field graphql.CollectedField, obj *model.CreateTableResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CreateTableResponse_created(ctx, field) if err != nil { return graphql.Null } @@ -856,50 +793,38 @@ func (ec *executionContext) _Mutation_modifyColumn(ctx context.Context, field gr }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().ModifyColumn(rctx, fc.Args["tableName"].(string), fc.Args["data"].(model.AddUpdateColumnData)) + return obj.Created, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(*model.SuccessResponse) + res := resTmp.(string) fc.Result = res - return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) + return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_modifyColumn(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_CreateTableResponse_created(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Mutation", + Object: "CreateTableResponse", Field: field, - IsMethod: true, - IsResolver: true, + IsMethod: false, + IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "success": - return ec.fieldContext_SuccessResponse_success(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) + return nil, errors.New("field of type String does not have child fields") }, } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_modifyColumn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return fc, err - } return fc, nil } -func (ec *executionContext) _Mutation_deleteColumn(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_deleteColumn(ctx, field) +func (ec *executionContext) _Mutation_createDatabase(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_createDatabase(ctx, field) if err != nil { return graphql.Null } @@ -912,7 +837,7 @@ func (ec *executionContext) _Mutation_deleteColumn(ctx context.Context, field gr }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().DeleteColumn(rctx, fc.Args["tableName"].(string), fc.Args["data"].(*model.DeleteColumnData)) + return ec.resolvers.Mutation().CreateDatabase(rctx, fc.Args["name"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -926,7 +851,7 @@ func (ec *executionContext) _Mutation_deleteColumn(ctx context.Context, field gr return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Mutation_deleteColumn(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_createDatabase(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Mutation", Field: field, @@ -947,15 +872,15 @@ func (ec *executionContext) fieldContext_Mutation_deleteColumn(ctx context.Conte } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_deleteColumn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Mutation_createDatabase_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query_databases(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_databases(ctx, field) +func (ec *executionContext) _Mutation_createTable(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_createTable(ctx, field) if err != nil { return graphql.Null } @@ -968,7 +893,7 @@ func (ec *executionContext) _Query_databases(ctx context.Context, field graphql. }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Databases(rctx) + return ec.resolvers.Mutation().CreateTable(rctx, fc.Args["name"].(string), fc.Args["data"].([]*model.CreateColumnData)) }) if err != nil { ec.Error(ctx, err) @@ -977,26 +902,41 @@ func (ec *executionContext) _Query_databases(ctx context.Context, field graphql. if resTmp == nil { return graphql.Null } - res := resTmp.([]*string) + res := resTmp.(*model.CreateTableResponse) fc.Result = res - return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res) + return ec.marshalOCreateTableResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateTableResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_databases(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_createTable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Query", + Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "created": + return ec.fieldContext_CreateTableResponse_created(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CreateTableResponse", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_createTable_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _Query_tables(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_tables(ctx, field) +func (ec *executionContext) _Mutation_deleteTable(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteTable(ctx, field) if err != nil { return graphql.Null } @@ -1009,7 +949,7 @@ func (ec *executionContext) _Query_tables(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Tables(rctx) + return ec.resolvers.Mutation().DeleteTable(rctx, fc.Args["name"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1018,26 +958,41 @@ func (ec *executionContext) _Query_tables(ctx context.Context, field graphql.Col if resTmp == nil { return graphql.Null } - res := resTmp.([]*string) + res := resTmp.(*model.SuccessResponse) fc.Result = res - return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res) + return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_tables(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_deleteTable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Query", + Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "success": + return ec.fieldContext_SuccessResponse_success(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_deleteTable_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _Query_table(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_table(ctx, field) +func (ec *executionContext) _Mutation_addColumn(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_addColumn(ctx, field) if err != nil { return graphql.Null } @@ -1050,7 +1005,7 @@ func (ec *executionContext) _Query_table(ctx context.Context, field graphql.Coll }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Table(rctx, fc.Args["name"].(*string)) + return ec.resolvers.Mutation().AddColumn(rctx, fc.Args["tableName"].(string), fc.Args["data"].(model.AddUpdateColumnData)) }) if err != nil { ec.Error(ctx, err) @@ -1059,31 +1014,23 @@ func (ec *executionContext) _Query_table(ctx context.Context, field graphql.Coll if resTmp == nil { return graphql.Null } - res := resTmp.([]*model.TableInfo) + res := resTmp.(*model.SuccessResponse) fc.Result = res - return ec.marshalOTableInfo2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐTableInfo(ctx, field.Selections, res) + return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query_table(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_addColumn(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Query", + Object: "Mutation", Field: field, IsMethod: true, IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "name": - return ec.fieldContext_TableInfo_name(ctx, field) - case "type": - return ec.fieldContext_TableInfo_type(ctx, field) - case "nullable": - return ec.fieldContext_TableInfo_nullable(ctx, field) - case "key": - return ec.fieldContext_TableInfo_key(ctx, field) - case "default": - return ec.fieldContext_TableInfo_default(ctx, field) + case "success": + return ec.fieldContext_SuccessResponse_success(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type TableInfo", field.Name) + return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) }, } defer func() { @@ -1093,15 +1040,15 @@ func (ec *executionContext) fieldContext_Query_table(ctx context.Context, field } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_table_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Mutation_addColumn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___type(ctx, field) +func (ec *executionContext) _Mutation_modifyColumn(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_modifyColumn(ctx, field) if err != nil { return graphql.Null } @@ -1114,7 +1061,7 @@ func (ec *executionContext) _Query___type(ctx context.Context, field graphql.Col }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.introspectType(fc.Args["name"].(string)) + return ec.resolvers.Mutation().ModifyColumn(rctx, fc.Args["tableName"].(string), fc.Args["data"].(model.AddUpdateColumnData)) }) if err != nil { ec.Error(ctx, err) @@ -1123,41 +1070,23 @@ func (ec *executionContext) _Query___type(ctx context.Context, field graphql.Col if resTmp == nil { return graphql.Null } - res := resTmp.(*introspection.Type) + res := resTmp.(*model.SuccessResponse) fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) + return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_modifyColumn(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Query", + Object: "Mutation", Field: field, IsMethod: true, - IsResolver: false, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) + case "success": + return ec.fieldContext_SuccessResponse_success(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) }, } defer func() { @@ -1167,15 +1096,15 @@ func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field } }() ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + if fc.Args, err = ec.field_Mutation_modifyColumn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { ec.Error(ctx, err) return fc, err } return fc, nil } -func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___schema(ctx, field) +func (ec *executionContext) _Mutation_deleteColumn(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_deleteColumn(ctx, field) if err != nil { return graphql.Null } @@ -1188,7 +1117,7 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.introspectSchema() + return ec.resolvers.Mutation().DeleteColumn(rctx, fc.Args["tableName"].(string), fc.Args["data"].(*model.DeleteColumnData)) }) if err != nil { ec.Error(ctx, err) @@ -1197,40 +1126,41 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C if resTmp == nil { return graphql.Null } - res := resTmp.(*introspection.Schema) + res := resTmp.(*model.SuccessResponse) fc.Result = res - return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) + return ec.marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐSuccessResponse(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Mutation_deleteColumn(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "Query", + Object: "Mutation", Field: field, IsMethod: true, - IsResolver: false, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { switch field.Name { - case "description": - return ec.fieldContext___Schema_description(ctx, field) - case "types": - return ec.fieldContext___Schema_types(ctx, field) - case "queryType": - return ec.fieldContext___Schema_queryType(ctx, field) - case "mutationType": - return ec.fieldContext___Schema_mutationType(ctx, field) - case "subscriptionType": - return ec.fieldContext___Schema_subscriptionType(ctx, field) - case "directives": - return ec.fieldContext___Schema_directives(ctx, field) + case "success": + return ec.fieldContext_SuccessResponse_success(ctx, field) } - return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) + return nil, fmt.Errorf("no field named %q was found under type SuccessResponse", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_deleteColumn_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _SuccessResponse_success(ctx context.Context, field graphql.CollectedField, obj *model.SuccessResponse) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_SuccessResponse_success(ctx, field) +func (ec *executionContext) _Query_databases(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_databases(ctx, field) if err != nil { return graphql.Null } @@ -1243,38 +1173,35 @@ func (ec *executionContext) _SuccessResponse_success(ctx context.Context, field }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Success, nil + return ec.resolvers.Query().Databases(rctx) }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(bool) + res := resTmp.([]*string) fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) + return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_SuccessResponse_success(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_databases(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "SuccessResponse", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") + return nil, errors.New("field of type String does not have child fields") }, } return fc, nil } -func (ec *executionContext) _TableInfo_name(ctx context.Context, field graphql.CollectedField, obj *model.TableInfo) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_TableInfo_name(ctx, field) +func (ec *executionContext) _Query_tables(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_tables(ctx, field) if err != nil { return graphql.Null } @@ -1287,7 +1214,7 @@ func (ec *executionContext) _TableInfo_name(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Name, nil + return ec.resolvers.Query().Tables(rctx) }) if err != nil { ec.Error(ctx, err) @@ -1296,17 +1223,17 @@ func (ec *executionContext) _TableInfo_name(ctx context.Context, field graphql.C if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.([]*string) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_TableInfo_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_tables(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "TableInfo", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { return nil, errors.New("field of type String does not have child fields") }, @@ -1314,8 +1241,8 @@ func (ec *executionContext) fieldContext_TableInfo_name(ctx context.Context, fie return fc, nil } -func (ec *executionContext) _TableInfo_type(ctx context.Context, field graphql.CollectedField, obj *model.TableInfo) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_TableInfo_type(ctx, field) +func (ec *executionContext) _Query_table(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_table(ctx, field) if err != nil { return graphql.Null } @@ -1328,7 +1255,7 @@ func (ec *executionContext) _TableInfo_type(ctx context.Context, field graphql.C }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Type, nil + return ec.resolvers.Query().Table(rctx, fc.Args["name"].(*string)) }) if err != nil { ec.Error(ctx, err) @@ -1337,26 +1264,49 @@ func (ec *executionContext) _TableInfo_type(ctx context.Context, field graphql.C if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.([]*model.ColumnInfo) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalOColumnInfo2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐColumnInfo(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_TableInfo_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query_table(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "TableInfo", + Object: "Query", Field: field, - IsMethod: false, - IsResolver: false, + IsMethod: true, + IsResolver: true, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "name": + return ec.fieldContext_ColumnInfo_name(ctx, field) + case "type": + return ec.fieldContext_ColumnInfo_type(ctx, field) + case "nullable": + return ec.fieldContext_ColumnInfo_nullable(ctx, field) + case "key": + return ec.fieldContext_ColumnInfo_key(ctx, field) + case "default": + return ec.fieldContext_ColumnInfo_default(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ColumnInfo", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_table_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _TableInfo_nullable(ctx context.Context, field graphql.CollectedField, obj *model.TableInfo) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_TableInfo_nullable(ctx, field) +func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___type(ctx, field) if err != nil { return graphql.Null } @@ -1369,7 +1319,7 @@ func (ec *executionContext) _TableInfo_nullable(ctx context.Context, field graph }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Nullable, nil + return ec.introspectType(fc.Args["name"].(string)) }) if err != nil { ec.Error(ctx, err) @@ -1378,26 +1328,59 @@ func (ec *executionContext) _TableInfo_nullable(ctx context.Context, field graph if resTmp == nil { return graphql.Null } - res := resTmp.(*string) + res := resTmp.(*introspection.Type) fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_TableInfo_nullable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "TableInfo", + Object: "Query", Field: field, - IsMethod: false, + IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) }, } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } return fc, nil } -func (ec *executionContext) _TableInfo_key(ctx context.Context, field graphql.CollectedField, obj *model.TableInfo) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_TableInfo_key(ctx, field) +func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___schema(ctx, field) if err != nil { return graphql.Null } @@ -1410,7 +1393,7 @@ func (ec *executionContext) _TableInfo_key(ctx context.Context, field graphql.Co }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Key, nil + return ec.introspectSchema() }) if err != nil { ec.Error(ctx, err) @@ -1419,26 +1402,40 @@ func (ec *executionContext) _TableInfo_key(ctx context.Context, field graphql.Co if resTmp == nil { return graphql.Null } - res := resTmp.(interface{}) + res := resTmp.(*introspection.Schema) fc.Result = res - return ec.marshalOAny2interface(ctx, field.Selections, res) + return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_TableInfo_key(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "TableInfo", + Object: "Query", Field: field, - IsMethod: false, + IsMethod: true, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Any does not have child fields") + switch field.Name { + case "description": + return ec.fieldContext___Schema_description(ctx, field) + case "types": + return ec.fieldContext___Schema_types(ctx, field) + case "queryType": + return ec.fieldContext___Schema_queryType(ctx, field) + case "mutationType": + return ec.fieldContext___Schema_mutationType(ctx, field) + case "subscriptionType": + return ec.fieldContext___Schema_subscriptionType(ctx, field) + case "directives": + return ec.fieldContext___Schema_directives(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) }, } return fc, nil } -func (ec *executionContext) _TableInfo_default(ctx context.Context, field graphql.CollectedField, obj *model.TableInfo) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_TableInfo_default(ctx, field) +func (ec *executionContext) _SuccessResponse_success(ctx context.Context, field graphql.CollectedField, obj *model.SuccessResponse) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SuccessResponse_success(ctx, field) if err != nil { return graphql.Null } @@ -1451,28 +1448,31 @@ func (ec *executionContext) _TableInfo_default(ctx context.Context, field graphq }() resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.Default, nil + return obj.Success, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } return graphql.Null } - res := resTmp.(interface{}) + res := resTmp.(bool) fc.Result = res - return ec.marshalOAny2interface(ctx, field.Selections, res) + return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_TableInfo_default(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_SuccessResponse_success(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ - Object: "TableInfo", + Object: "SuccessResponse", Field: field, IsMethod: false, IsResolver: false, Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Any does not have child fields") + return nil, errors.New("field of type Boolean does not have child fields") }, } return fc, nil @@ -3289,8 +3289,8 @@ func (ec *executionContext) unmarshalInputAddUpdateColumnData(ctx context.Contex return it, nil } -func (ec *executionContext) unmarshalInputCreateTableData(ctx context.Context, obj interface{}) (model.CreateTableData, error) { - var it model.CreateTableData +func (ec *executionContext) unmarshalInputCreateColumnData(ctx context.Context, obj interface{}) (model.CreateColumnData, error) { + var it model.CreateColumnData asMap := map[string]interface{}{} for k, v := range obj.(map[string]interface{}) { asMap[k] = v @@ -3391,6 +3391,50 @@ func (ec *executionContext) unmarshalInputDeleteColumnData(ctx context.Context, // region **************************** object.gotpl **************************** +var columnInfoImplementors = []string{"ColumnInfo"} + +func (ec *executionContext) _ColumnInfo(ctx context.Context, sel ast.SelectionSet, obj *model.ColumnInfo) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, columnInfoImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ColumnInfo") + case "name": + out.Values[i] = ec._ColumnInfo_name(ctx, field, obj) + case "type": + out.Values[i] = ec._ColumnInfo_type(ctx, field, obj) + case "nullable": + out.Values[i] = ec._ColumnInfo_nullable(ctx, field, obj) + case "key": + out.Values[i] = ec._ColumnInfo_key(ctx, field, obj) + case "default": + out.Values[i] = ec._ColumnInfo_default(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var createTableResponseImplementors = []string{"CreateTableResponse"} func (ec *executionContext) _CreateTableResponse(ctx context.Context, sel ast.SelectionSet, obj *model.CreateTableResponse) graphql.Marshaler { @@ -3642,50 +3686,6 @@ func (ec *executionContext) _SuccessResponse(ctx context.Context, sel ast.Select return out } -var tableInfoImplementors = []string{"TableInfo"} - -func (ec *executionContext) _TableInfo(ctx context.Context, sel ast.SelectionSet, obj *model.TableInfo) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, tableInfoImplementors) - - out := graphql.NewFieldSet(fields) - deferred := make(map[string]*graphql.FieldSet) - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("TableInfo") - case "name": - out.Values[i] = ec._TableInfo_name(ctx, field, obj) - case "type": - out.Values[i] = ec._TableInfo_type(ctx, field, obj) - case "nullable": - out.Values[i] = ec._TableInfo_nullable(ctx, field, obj) - case "key": - out.Values[i] = ec._TableInfo_key(ctx, field, obj) - case "default": - out.Values[i] = ec._TableInfo_default(ctx, field, obj) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch(ctx) - if out.Invalids > 0 { - return graphql.Null - } - - atomic.AddInt32(&ec.deferred, int32(len(deferred))) - - for label, dfs := range deferred { - ec.processDeferredGroup(graphql.DeferredGroup{ - Label: label, - Path: graphql.GetPath(ctx), - FieldSet: dfs, - Context: ctx, - }) - } - - return out -} - var __DirectiveImplementors = []string{"__Directive"} func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { @@ -4032,16 +4032,16 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se return res } -func (ec *executionContext) unmarshalNCreateTableData2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateTableDataᚄ(ctx context.Context, v interface{}) ([]*model.CreateTableData, error) { +func (ec *executionContext) unmarshalNCreateColumnData2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateColumnDataᚄ(ctx context.Context, v interface{}) ([]*model.CreateColumnData, error) { var vSlice []interface{} if v != nil { vSlice = graphql.CoerceList(v) } var err error - res := make([]*model.CreateTableData, len(vSlice)) + res := make([]*model.CreateColumnData, len(vSlice)) for i := range vSlice { ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalNCreateTableData2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateTableData(ctx, vSlice[i]) + res[i], err = ec.unmarshalNCreateColumnData2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateColumnData(ctx, vSlice[i]) if err != nil { return nil, err } @@ -4049,8 +4049,8 @@ func (ec *executionContext) unmarshalNCreateTableData2ᚕᚖgithubᚗcomᚋkaree return res, nil } -func (ec *executionContext) unmarshalNCreateTableData2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateTableData(ctx context.Context, v interface{}) (*model.CreateTableData, error) { - res, err := ec.unmarshalInputCreateTableData(ctx, v) +func (ec *executionContext) unmarshalNCreateColumnData2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateColumnData(ctx context.Context, v interface{}) (*model.CreateColumnData, error) { + res, err := ec.unmarshalInputCreateColumnData(ctx, v) return &res, graphql.ErrorOnPath(ctx, err) } @@ -4364,6 +4364,54 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast return res } +func (ec *executionContext) marshalOColumnInfo2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐColumnInfo(ctx context.Context, sel ast.SelectionSet, v []*model.ColumnInfo) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOColumnInfo2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐColumnInfo(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + return ret +} + +func (ec *executionContext) marshalOColumnInfo2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐColumnInfo(ctx context.Context, sel ast.SelectionSet, v *model.ColumnInfo) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._ColumnInfo(ctx, sel, v) +} + func (ec *executionContext) marshalOCreateTableResponse2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐCreateTableResponse(ctx context.Context, sel ast.SelectionSet, v *model.CreateTableResponse) graphql.Marshaler { if v == nil { return graphql.Null @@ -4434,54 +4482,6 @@ func (ec *executionContext) marshalOSuccessResponse2ᚖgithubᚗcomᚋkareemmahl return ec._SuccessResponse(ctx, sel, v) } -func (ec *executionContext) marshalOTableInfo2ᚕᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐTableInfo(ctx context.Context, sel ast.SelectionSet, v []*model.TableInfo) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalOTableInfo2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐTableInfo(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) marshalOTableInfo2ᚖgithubᚗcomᚋkareemmahleesᚋmetaᚑxᚋinternalᚋgraphᚋmodelᚐTableInfo(ctx context.Context, sel ast.SelectionSet, v *model.TableInfo) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._TableInfo(ctx, sel, v) -} - func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { if v == nil { return graphql.Null diff --git a/internal/graph/model/models_gen.go b/internal/graph/model/models_gen.go index 43f3f1d..007b0e2 100644 --- a/internal/graph/model/models_gen.go +++ b/internal/graph/model/models_gen.go @@ -2,37 +2,54 @@ package model +// Data used when adding or updating a column type AddUpdateColumnData struct { + // Column name ColName *string `json:"colName,omitempty"` - Type *string `json:"type,omitempty"` + // Column data type + Type *string `json:"type,omitempty"` } -type CreateTableData struct { - ColName *string `json:"colName,omitempty"` - Type *string `json:"type,omitempty"` - Nullable *bool `json:"nullable,omitempty"` - Default interface{} `json:"default,omitempty"` - Unique *bool `json:"unique,omitempty"` +// Several info about a table column +type ColumnInfo struct { + // Column name + Name *string `json:"name,omitempty"` + // Column data type + Type *string `json:"type,omitempty"` + // If the table accepts null values or not + Nullable *string `json:"nullable,omitempty"` + // Constraint name of the column, e.g PRI + Key interface{} `json:"key,omitempty"` + // Column default value + Default interface{} `json:"default,omitempty"` } +// General data about the column to create +type CreateColumnData struct { + // Column name + ColName *string `json:"colName,omitempty"` + // Data type of the column + Type *string `json:"type,omitempty"` + // Wether the column accepts null values + Nullable *bool `json:"nullable,omitempty"` + // Default value of the column + Default interface{} `json:"default,omitempty"` + // Wether to add unique constraint on the column + Unique *bool `json:"unique,omitempty"` +} + +// Table created successfully type CreateTableResponse struct { - // name of created table + // Name of created table Created string `json:"created"` } type DeleteColumnData struct { + // Deleted column name ColName *string `json:"colName,omitempty"` } +// Generic operation success response type SuccessResponse struct { Success bool `json:"success"` } - -// Table info like field name returned from table query -type TableInfo struct { - Name *string `json:"name,omitempty"` - Type *string `json:"type,omitempty"` - Nullable *string `json:"nullable,omitempty"` - Key interface{} `json:"key,omitempty"` - Default interface{} `json:"default,omitempty"` -} diff --git a/internal/graph/schema.graphql b/internal/graph/schema.graphql index 90db9f3..3c3e59d 100644 --- a/internal/graph/schema.graphql +++ b/internal/graph/schema.graphql @@ -3,61 +3,81 @@ # https://gqlgen.com/getting-started/ type Query { - "returns a list of all databases" + "Returns a list of all available databases" databases: [String] - "return a list of all tables" + "Return a list of all available tables" tables: [String] - "returns the info of a single table" - table(name: String): [TableInfo] + "Returns info about the columns of a table" + table(name: String): [ColumnInfo] } -"Table info like field name returned from table query" -type TableInfo { +"Several info about a table column" +type ColumnInfo { + "Column name" name: String + "Column data type" type: String + "If the table accepts null values or not" nullable: String + "Constraint name of the column, e.g PRI" key: Any + "Column default value" default: Any } type Mutation { - "creates a database with the specified name" + "Creates a database with the specified name" createDatabase(name: String!): SuccessResponse - "creates a table with the specified name" - createTable(name: String!, data: [CreateTableData!]!): CreateTableResponse - "deletes the table by name" + "Creates a table with the specified name and columns info" + createTable(name: String!, data: [CreateColumnData!]!): CreateTableResponse + "Deletes specified table" deleteTable(name: String!): SuccessResponse - "updated the table by name" # updateTable(name: String!, prop: UpdateTableData): SuccessResponse + "Add a new column to the table" addColumn(tableName: String!, data: AddUpdateColumnData!): SuccessResponse + "Modifies a column datatype" modifyColumn(tableName: String!, data: AddUpdateColumnData!): SuccessResponse + "Deletes a column" deleteColumn(tableName: String!, data: DeleteColumnData): SuccessResponse } -input CreateTableData { +"General data about the column to create" +input CreateColumnData { + "Column name" colName: String + "Data type of the column" type: String + "Wether the column accepts null values" nullable: Boolean + "Default value of the column" default: Any + "Wether to add unique constraint on the column" unique: Boolean } +"Table created successfully" type CreateTableResponse { - "name of created table" + "Name of created table" created: String! } +"Data used when adding or updating a column" input AddUpdateColumnData { + "Column name" colName: String + "Column data type" type: String } input DeleteColumnData { + "Deleted column name" colName: String } +"Generic operation success response" type SuccessResponse { success: Boolean! } +"The `Any` scalar type represent any value/data-type" scalar Any diff --git a/internal/graph/schema.resolvers.go b/internal/graph/schema.resolvers.go index 48cb4e3..eb2c3f8 100644 --- a/internal/graph/schema.resolvers.go +++ b/internal/graph/schema.resolvers.go @@ -23,7 +23,7 @@ func (r *mutationResolver) CreateDatabase(ctx context.Context, name string) (*mo } // CreateTable is the resolver for the createTable field. -func (r *mutationResolver) CreateTable(ctx context.Context, name string, data []*model.CreateTableData) (*model.CreateTableResponse, error) { +func (r *mutationResolver) CreateTable(ctx context.Context, name string, data []*model.CreateColumnData) (*model.CreateTableResponse, error) { convertedData := []models.CreateTablePayload{} for _, props := range data { convertedData = append(convertedData, models.CreateTablePayload{ @@ -113,18 +113,18 @@ func (r *queryResolver) Tables(ctx context.Context) ([]*string, error) { } // Table is the resolver for the table field. -func (r *queryResolver) Table(ctx context.Context, name *string) ([]*model.TableInfo, error) { +func (r *queryResolver) Table(ctx context.Context, name *string) ([]*model.ColumnInfo, error) { result, err := r.Storage.GetTable(*name) if err != nil { return nil, err } - var tableInfo []*model.TableInfo + var tableInfo []*model.ColumnInfo for _, info := range result { name := info.Name dataType := info.Type nullable := info.Nullable key := info.Key - mod := &model.TableInfo{ + mod := &model.ColumnInfo{ Name: &name, Type: &dataType, Nullable: &nullable, diff --git a/internal/handlers/dbHandlers.go b/internal/handlers/dbHandlers.go index cdef022..2b34eb7 100644 --- a/internal/handlers/dbHandlers.go +++ b/internal/handlers/dbHandlers.go @@ -26,11 +26,13 @@ func (dh *DBHandler) RegisterRoutes(r *chi.Mux) { // Lists databases // -// @tags Databases -// @description list databases +// @summary List Databases +// @description Get all the available databases. +// @tags Database // @router /database [get] // @produce json // @success 200 {object} models.ListDatabasesResp +// @failure 500 {object} models.InternalServerError func (dh *DBHandler) handleListDatabases(w http.ResponseWriter, r *http.Request) { dbs, err := dh.storage.ListDBs() @@ -41,6 +43,20 @@ func (dh *DBHandler) handleListDatabases(w http.ResponseWriter, r *http.Request) writeJson(w, models.ListDatabasesResp{Databases: dbs}) } +// Creates a new Database +// +// @summary Create a new Database +// @description Creates a new database with the specified table schema. +// @description +// @description **NOTE**: SQLite is Unsupported. +// @tags Database +// @router /database [post] +// @accept json +// @produce json +// @param payload body models.CreatePgMySqlDBPayload true "Database Info" +// @success 200 {object} models.SuccessResp +// @failure 400 {object} models.ErrResp +// @failure 500 {object} models.InternalServerError func (dh *DBHandler) handleCreateDatabase(w http.ResponseWriter, r *http.Request) { var payload models.CreatePgMySqlDBPayload diff --git a/internal/handlers/defaultHandler.go b/internal/handlers/defaultHandler.go index 8a3fd6a..3eeb67a 100644 --- a/internal/handlers/defaultHandler.go +++ b/internal/handlers/defaultHandler.go @@ -2,7 +2,6 @@ package handlers import ( "net/http" - "time" "github.com/go-chi/chi/v5" ) @@ -14,43 +13,29 @@ func NewDefaultHandler() *DefaultHandler { } func (h *DefaultHandler) RegisterRoutes(r *chi.Mux) { - r.Get("/health", h.healthCheck) r.Get("/", h.apiInfo) } -type HealthCheckResult struct { - Date string -} - -// Checks the health +// General API Info // -// @description check application health by getting current date -// @produce json -// @tags default -// @router /health [get] -// @success 200 {object} HealthCheckResult -func (h *DefaultHandler) healthCheck(w http.ResponseWriter, r *http.Request) { - writeJson(w, map[string]time.Time{ - "date": time.Now(), - }) -} - -type APIInfoResult struct { - Author string `json:"author"` - Contact string `json:"contact"` - Repo string `json:"repo"` - Year int `json:"yeaer"` +// @description General Info about the API, author name, how to contact, etc. +type APIInfo struct { + Author string `json:"author" example:"Kareem Ebrahim"` // Author name. + Contact string `json:"contact" example:"kareemmahlees@gmail.com"` // How to contact the author. + Repo string `json:"repo" example:"https://github.com/kareemmahlees/meta-x"` // Git repository name for contributions. + Year int `json:"year" example:"2024"` // Year of launch } -// Get info about the api +// Gets general info about the API // -// @description get info about the api +// @summary Get API Info +// @description Get general info about the API // @produce json -// @tags default +// @tags General // @router / [get] -// @success 200 {object} APIInfoResult +// @success 200 {object} APIInfo func (h *DefaultHandler) apiInfo(w http.ResponseWriter, r *http.Request) { - writeJson(w, APIInfoResult{ + writeJson(w, APIInfo{ Author: "Kareem Ebrahim", Year: 2024, Contact: "kareemmahlees@gmail.com", diff --git a/internal/handlers/defaultHandler_test.go b/internal/handlers/defaultHandler_test.go index e9abab3..a38ff54 100644 --- a/internal/handlers/defaultHandler_test.go +++ b/internal/handlers/defaultHandler_test.go @@ -31,17 +31,9 @@ func (suite *DefaultHandlerTestSuite) TestRegisterDefaultRoutes() { routes = append(routes, route.Pattern) } - assert.Contains(routes, "/health") assert.Contains(routes, "/") } -func (suite *DefaultHandlerTestSuite) TestHealthCheck() { - assert := suite.Assert() - - assert.HTTPSuccess(suite.handler.healthCheck, http.MethodGet, "/health", nil) - assert.HTTPBodyContains(suite.handler.healthCheck, http.MethodGet, "/health", nil, "date") -} - func (suite *DefaultHandlerTestSuite) TestAPIInfo() { assert := suite.Assert() diff --git a/internal/handlers/tableHandlers.go b/internal/handlers/tableHandlers.go index 8b71e92..d078e03 100644 --- a/internal/handlers/tableHandlers.go +++ b/internal/handlers/tableHandlers.go @@ -29,13 +29,34 @@ func (h *TableHandler) RegisterRoutes(r *chi.Mux) { }) } +// Lists all tables in the database +// +// @summary List tables. +// @description Get a list of the available tables in the database. +// @tags Table +// @router /table [get] +// @produce json +// @success 200 {object} models.ListTablesResp +// @failure 500 {object} models.InternalServerError +func (h *TableHandler) handleListTables(w http.ResponseWriter, r *http.Request) { + tables, err := h.storage.ListTables() + if err != nil { + httpError(w, http.StatusInternalServerError, err.Error()) + return + } + writeJson(w, models.ListTablesResp{Tables: tables}) +} + // Get detailed info about the specified table // -// @tags Tables -// @description Get detailed info about a specific table -// @router /table/{tableName}/describe [get] +// @summary Get table info +// @description Get detailed info about a table's fields. +// @tags Table +// @router /table/{table_name}/describe [get] +// @param table_name path string true "Table Name" // @produce json -// @success 200 {object} []models.TableInfoResp +// @success 200 {array} models.TableColumnInfo +// @failure 500 {object} models.InternalServerError func (h *TableHandler) handleGetTableInfo(w http.ResponseWriter, r *http.Request) { params := struct { TableName string `validate:"required,alpha"` @@ -55,32 +76,20 @@ func (h *TableHandler) handleGetTableInfo(w http.ResponseWriter, r *http.Request writeJson(w, tableInfo) } -// Lists all tables in the database -// -// @tags Tables -// @description list tables -// @router /table [get] -// @produce json -// @success 200 {object} models.ListTablesResp -func (h *TableHandler) handleListTables(w http.ResponseWriter, r *http.Request) { - tables, err := h.storage.ListTables() - if err != nil { - httpError(w, http.StatusInternalServerError, err.Error()) - return - } - writeJson(w, models.ListTablesResp{Tables: tables}) -} - // Creates a Table // -// @tags Tables -// @description create table -// @router /table/{tableName} [post] -// @param tableName path string true "table name" -// @param tableData body models.CreateTablePayload true "create table data" +// @tags Table +// @summary Create a Table. +// @description Creates a new table with the specified columns. +// @router /table/{table_name} [post] +// @param table_name path string true "Table Name" +// @param table_data body []models.CreateTablePayload true "Table Data" // @accept json // @produce json // @success 201 {object} models.CreateTableResp +// @failure 400 {object} models.BadRequestError +// @failure 422 {object} models.UnprocessableEntityError +// @failure 500 {object} models.InternalServerError func (h *TableHandler) handleCreateTable(w http.ResponseWriter, r *http.Request) { params := struct { TableName string `validate:"required,alphanum"` @@ -105,6 +114,7 @@ func (h *TableHandler) handleCreateTable(w http.ResponseWriter, r *http.Request) err := h.storage.CreateTable(params.TableName, payload) if err != nil { httpError(w, http.StatusInternalServerError, err.Error()) + return } w.WriteHeader(http.StatusCreated) @@ -113,14 +123,18 @@ func (h *TableHandler) handleCreateTable(w http.ResponseWriter, r *http.Request) // Updates a table by adding a column // -// @tags Tables -// @description Add column to table -// @router /table/{tableName}/column/add [post] -// @param tableName path string true "table name" -// @param columnData body models.AddModifyColumnPayload true "column data" +// @tags Table +// @summary Add a column +// @description Adds a column with the provided data to the given table. +// @router /table/{table_name}/column/add [post] +// @param table_name path string true "Table Name" +// @param column_data body models.AddModifyColumnPayload true "Column Data" // @accept json // @produce json // @success 201 {object} models.SuccessResp +// @failure 400 {object} models.BadRequestError +// @failure 422 {object} models.UnprocessableEntityError +// @failure 500 {object} models.InternalServerError func (h *TableHandler) handleAddColumn(w http.ResponseWriter, r *http.Request) { params := struct { TableName string `validate:"required,alphanum"` @@ -152,14 +166,18 @@ func (h *TableHandler) handleAddColumn(w http.ResponseWriter, r *http.Request) { // Updates a table by modifying a column // -// @tags Tables -// @description Update table column -// @router /table/{tableName}/column/modify [put] -// @param tableName path string true "table name" -// @param columnData body models.AddModifyColumnPayload true "column data" +// @tags Table +// @summary Update Column +// @description Update table column properties, **Only supports updating the column type for now**. +// @router /table/{table_name}/column/modify [put] +// @param table_name path string true "Table Name" +// @param column_data body models.AddModifyColumnPayload true "Column Data" // @accept json // @produce json // @success 200 {object} models.SuccessResp +// @failure 400 {object} models.BadRequestError +// @failure 422 {object} models.UnprocessableEntityError +// @failure 500 {object} models.InternalServerError func (h *TableHandler) handleModifyColumn(w http.ResponseWriter, r *http.Request) { params := struct { TableName string `validate:"required,alphanum"` @@ -190,14 +208,18 @@ func (h *TableHandler) handleModifyColumn(w http.ResponseWriter, r *http.Request // Updates a table by deleting/dropping a column // -// @tags Tables -// @description Delete/Drop table column -// @router /table/{tableName}/column/delete [delete] -// @param tableName path string true "table name" -// @param columnData body models.DeleteColumnPayload true "column name" +// @tags Table +// @summary Delete Column +// @description Delete table column +// @router /table/{table_name}/column/delete [delete] +// @param table_name path string true "Table Name" +// @param column_data body models.DeleteColumnPayload true "Column Name" // @accept json // @produce json // @success 200 {object} models.SuccessResp +// @failure 400 {object} models.BadRequestError +// @failure 422 {object} models.UnprocessableEntityError +// @failure 500 {object} models.InternalServerError func (h *TableHandler) handleDeleteColumn(w http.ResponseWriter, r *http.Request) { params := struct { TableName string `params:"tableName" validate:"required,alphanum"` @@ -228,13 +250,15 @@ func (h *TableHandler) handleDeleteColumn(w http.ResponseWriter, r *http.Request // Deletes a table // -// @tags Tables -// @decription delete table -// @router /table/{tableName} [delete] -// @param tableName path string true "table name" -// @accept json -// @produce json -// @success 200 {object} models.SuccessResp +// @tags Table +// @summary Delete Table +// @description Delete the given table. +// @router /table/{table_name} [delete] +// @param table_name path string true "Table Name" +// @accept json +// @produce json +// @success 200 {object} models.SuccessResp +// @failure 500 {object} models.InternalServerError func (h *TableHandler) handleDeleteTable(w http.ResponseWriter, r *http.Request) { params := struct { TableName string `params:"tableName" validate:"required,alpha"` diff --git a/internal/handlers/tableHandlers_test.go b/internal/handlers/tableHandlers_test.go index fc28c27..363aeea 100644 --- a/internal/handlers/tableHandlers_test.go +++ b/internal/handlers/tableHandlers_test.go @@ -343,13 +343,13 @@ func NewMockTableExecutor() *MockTableExecutor { return &MockTableExecutor{} } -func (ms *MockTableExecutor) GetTable(tableName string) ([]*models.TableInfoResp, error) { - tableInfo := models.TableInfoResp{ +func (ms *MockTableExecutor) GetTable(tableName string) ([]*models.TableColumnInfo, error) { + tableInfo := models.TableColumnInfo{ Name: "name", Type: "varchar(255)", Nullable: "Yes", } - return []*models.TableInfoResp{&tableInfo}, nil + return []*models.TableColumnInfo{&tableInfo}, nil } func (ms *MockTableExecutor) ListTables() ([]*string, error) { table := "test" @@ -379,7 +379,7 @@ func NewFaultyTableExecutor() *FaultyTableExecutor { var err = errors.New("error") -func (ms *FaultyTableExecutor) GetTable(tableName string) ([]*models.TableInfoResp, error) { +func (ms *FaultyTableExecutor) GetTable(tableName string) ([]*models.TableColumnInfo, error) { return nil, err } func (ms *FaultyTableExecutor) ListTables() ([]*string, error) { diff --git a/internal/server.go b/internal/server.go index 1f5a421..359ca26 100644 --- a/internal/server.go +++ b/internal/server.go @@ -31,6 +31,7 @@ func (s *Server) Serve() error { h := graphQlHandler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{Storage: s.storage}})) s.router.Use(middleware.Logger) + s.router.Use(middleware.Heartbeat("/health")) s.router.Post("/graphql", h.ServeHTTP) s.router.Get("/playground", playground.ApolloSandboxHandler("GraphQL", "/graphql")) s.router.HandleFunc("/spec", func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/server_test.go b/internal/server_test.go index f0bb1a8..5ae1f0b 100644 --- a/internal/server_test.go +++ b/internal/server_test.go @@ -20,7 +20,7 @@ func (ms *MockStorage) ListDBs() ([]*string, error) { func (ms *MockStorage) CreateDB(dbName string) error { return nil } -func (ms *MockStorage) GetTable(tableName string) ([]*models.TableInfoResp, error) { +func (ms *MockStorage) GetTable(tableName string) ([]*models.TableColumnInfo, error) { return nil, nil } func (ms *MockStorage) ListTables() ([]*string, error) { diff --git a/main.go b/main.go index 262f653..a8a0080 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,15 @@ import ( // @description A RESTFull and GraphQL API to supercharge your database // @contact.name Kareem Ebrahim // @contact.email kareemmahlees@gmail.com -// @servers.url localhost:5522 +// +// @tag.name General +// @tag.description general info about the API. +// @tag.name Database +// @tag.description Database level related operations. +// @tag.name Table +// @tag.description Table Level related operations. +// +// @servers.url http://localhost:5522 // @servers.description Home town of Meta-X func main() { cmd.Execute() diff --git a/models/common.go b/models/common.go index 4ac6ae8..0b0e42d 100644 --- a/models/common.go +++ b/models/common.go @@ -1,10 +1,42 @@ package models +// The generic successful operation response. +// +// @description Operation Succeeded. type SuccessResp struct { Success bool `json:"success"` } +// This is the error struct returned from all requests and +// others are just used for documentation purposes. +// +// @description Operation Failed. +// @description Maybe invalid payload or internal server error. type ErrResp struct { - Message any `json:"message"` - Code int `json:"code"` + Message any `json:"message" example:"Malformed payload"` // Error cause. + Code int `json:"code" example:"400"` // HTTP code. +} + +// Used, for e.g, for database related error. +// +// @description Something wrong happened on the server. +type InternalServerError struct { + Message any `json:"message" example:"Something went wrong"` // Error cause. + Code int `json:"code" example:"500"` // HTTP code. +} + +// BadRequestError used for errors of validation. +// +// @description Request payload failed validation. +type BadRequestError struct { + Message any `json:"message" example:"Payload Failed Validation"` // Error cause. + Code int `json:"code" example:"422"` // HTTP code. +} + +// UnprocessableEntityError used for errors of parsing request body. +// +// @description Failed to parse payload. +type UnprocessableEntityError struct { + Message any `json:"message" example:"Payload Parsing Failed"` // Error cause. + Code int `json:"code" example:"422"` // HTTP code. } diff --git a/models/database.go b/models/database.go index 492f352..fc56eeb 100644 --- a/models/database.go +++ b/models/database.go @@ -1,7 +1,8 @@ package models +// @description A list of all available databases. type ListDatabasesResp struct { - Databases []*string + Databases []*string `json:"databases" example:"test,prod,main"` } type AttachSqliteDBPayload struct { @@ -10,5 +11,5 @@ type AttachSqliteDBPayload struct { } type CreatePgMySqlDBPayload struct { - Name string `json:"name" validate:"required,alphanum"` + Name string `json:"name" validate:"required,alphanum" example:"Users"` // Database name. } diff --git a/models/tables.go b/models/tables.go index a8f55b3..c16cc33 100644 --- a/models/tables.go +++ b/models/tables.go @@ -1,34 +1,52 @@ package models +// List of Tables. +// +// @description List of tables. type ListTablesResp struct { - Tables []*string `json:"tables"` + Tables []*string `json:"tables" example:"table1,table2,table3"` } -type TableInfoResp struct { - Key any `db:"key" json:"key"` - Default any `db:"default" json:"default"` - Name string `db:"name" json:"name"` - Type string `db:"type" json:"type"` - Nullable string `db:"nullable" json:"nullable"` +// Table Info. +// +// @description Info about a table column. +type TableColumnInfo struct { + Key any `db:"key" json:"key" example:"PRI"` // Constraint name on the column. + Default any `db:"default" json:"default" example:"123"` // Default value of the column. + Name string `db:"name" json:"name" example:"email"` // Name of the column. + Type string `db:"type" json:"type" example:"varchar"` // Data type of the column. + Nullable string `db:"nullable" json:"nullable" example:"true"` // If the column accepts null values or not. } +// Create Table Payload. +// +// @description Data about the column to create. type CreateTablePayload struct { - Nullable interface{} `json:"nullable" validate:"omitempty,boolean"` - Default interface{} `json:"default" validate:"omitempty,alphanum" ` - Unique interface{} `json:"unique" validate:"omitempty,boolean"` - ColName string `json:"column_name" validate:"required,alphanum"` - Type string `json:"type" validate:"required,ascii"` + Nullable interface{} `json:"nullable" validate:"omitempty,boolean"` // If the column accepts null values or not. + Default interface{} `json:"default" validate:"omitempty,alphanum"` // Default value of the column. + Unique interface{} `json:"unique" validate:"omitempty,boolean"` // Wether to add a unique constraint on the column. + ColName string `json:"column_name" validate:"required,alphanum"` // Name of the column. + Type string `json:"type" validate:"required,ascii"` // Data type of the column. } +// Table Created Successfully. +// +// @description Table Created Successfully. type CreateTableResp struct { - Created string `json:"created"` + Created string `json:"created"` // Created table name. } +// Add/Modify a column payload. +// +// @description Adding or Modifying a column payload. type AddModifyColumnPayload struct { - ColName string `json:"column_name" validate:"required,alphanum"` - Type string `json:"type" validate:"required,ascii"` + ColName string `json:"column_name" validate:"required,alphanum"` // Column Name + Type string `json:"type" validate:"required,ascii" example:"Int"` // New type } +// Column deletion payload. +// +// @description Column to delete data. type DeleteColumnPayload struct { - ColName string `json:"column_name" validate:"required,alphanum"` + ColName string `json:"column_name" validate:"required,alphanum"` // Column Name }