autogql

package module
v0.4.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 7, 2023 License: MIT Imports: 17 Imported by: 1

README

AutoGql

AutoGQL is a GraphQL GORM CRUD generator. It's a plugin for 99designs/gqlgen that helps you quickly create CRUD functionality for your application so you can focus on the unique aspects of your business

Setup

  1. Follow the steps from Gqlgen
  2. Create a folder plugin and add a main.go inside.
  3. Copy the following code into main.go:
package main

import (
	"fmt"
	"os"

	"github.com/99designs/gqlgen/api"
	"github.com/99designs/gqlgen/codegen/config"
	"github.com/fasibio/autogql"
)

func main() {
	cfg, err := config.LoadConfigFromDefaultLocations()

	if err != nil {
		fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
		os.Exit(2)
	}
	sqlPlugin, muateHookPlugin := autogql.NewAutoGqlPlugin()
	err = api.Generate(cfg, api.AddPlugin(sqlPlugin), api.ReplacePlugin(muateHookPlugin))
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(3)
	}
}
  1. Install dependencies
go mod tidy
  1. Add a example autogql struct to schema.graphqls
type Company @SQL{
  id: Int! @SQL_PRIMARY
  Name: String!
}
  1. Run the following command to generate the GQLgen code:
go run plugin/main.go
  1. Add SQL entity to Resolver struct at resolver.go
type Resolver struct {
	Sql *db.AutoGqlDB // this is the new line the package db is autogenerate by this plugin
}
  1. Add SQL GORM Connection(SQLite used as an example) to server.go:

import (
  // ... more imports
  "gorm.io/driver/sqlite"
	"gorm.io/gorm"
)
func main() {
  dbCon, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
  if err != nil {
		panic(err)
	}
  dborm := db.NewAutoGqlDB(dbCon)
  dborm.Init()

  srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{Sql: &dborm} //.... <- here set dborm to resolver
}

How to Use Autogql

Autogql is designed to work similarly to gorm for declaring database tables and relations. To get started, it's helpful to familiarize yourself with how gorm models work:

Little introduction

At gorm you describe Database tables and relations like this

type User struct {
	ID        uint           `gorm:"primaryKey;autoIncrement:true"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt gorm.DeletedAt `gorm:"index"`
	Name string
}

func (u User) Calculation() int {
	return 10
}

With Autogql, you can describe GraphQL schemas and directives in the same way:


type User @SQL{
	id: Int! @SQL_PRIMARY @SQL_GORM(value: "autoIncrement")
	createdAt: Time
	updatedAt: Time
	deletedAt: Time @SQL_INDEX
	name: String
	calculation: Int! @SQL_GORM(value: "-")
}

In this example, the @SQL directive tells Autogql that this type should be mapped to a GORM model. The @SQL_GORM directive specifies the corresponding GORM tag for the field.

You can find more examples of Autogql schema descriptions in the test schema file. Autogql also allows you to define relationships between models using GORM's foreign key syntax:


type Cat @SQL(order: 4){
  id: ID! @SQL_PRIMARY @SQL_GORM(value: "autoIncrement")
  name: String!
  birthDay: Time!
  age: Int @SQL_GORM(value:"-")
  userID: Int! #<--- foreign Key to user
  alive: Boolean @SQL_GORM(value: "default:true")
}

type User @SQL(order: 2){
  id: ID! @SQL_PRIMARY @SQL_GORM(value: "autoIncrement")
  name: String!
  createdAt: Time
  updatedAt: Time
  deletedAt: Time
  cat: Cat @SQL_GORM(value:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;")# <--- cat defintion. SQL_GORM not needed for relation only a constraint line
  companyID: Int
  company: Company
  smartPhones: [SmartPhone]
}

In this example, the userID field in the Cat type is a foreign key that points to the id field in the User type. The @SQL_GORM directive can be used to specify GORM tags for relationships, as well as other constraints.

To work with queries and mutations, Autogql will automatically generate them for you, as well as create resolvers and fill in GORM database code. Additionally, you can manipulate each query and mutation over hooks, as described in the db/db_gen.go file. For an example of how to include hooks, check out the autogql_example repository and the hooks.go file.

Directives

Add the @SQL directive to each type that you want managed by AutoGQL.

...
type Company @SQL{
	id: Int! @SQL_PRIMARY
	...
}
...

It will autogenerate Queries and Mutations based on your GraphQL schema. Also, it will create resolvers and fill them with GORM Database code.

Description:


	input SqlCreateExtension {
		value: Boolean! # active this query or mutation
		directiveExt: [String!] # add directive to query or mutation
	}

	input SqlMutationParams {
		add: SqlCreateExtension
		update: SqlCreateExtension
		delete: SqlCreateExtension
		directiveExt: [String!] # add directive to all mutation
	}

	input SqlQueryParams {
		get: SqlCreateExtension
		query: SqlCreateExtension
		directiveExt: [String!] # add directive to all mutations
	}
	# order to define relations (if Type A(order: 1) have a releation to type B(order: 2)
	directive @SQL(order: Int, query:SqlQueryParams, mutation: SqlMutationParams ) on OBJECT 

	# database primary key
	directive @SQL_PRIMARY on FIELD_DEFINITION

	# database index
	directive @SQL_INDEX on FIELD_DEFINITION

	# each gorm command ==> not all useable at the moment pls open issue if you find one
	directive @SQL_GORM (value: String)on FIELD_DEFINITION 

	# to remove this value from input and patch generated Inputs
	directive @SQL_SKIP_MUTATION on FIELD_DEFINITION 

	# to add a tag to input go struct
	directive @SQL_INPUTTYPE_TAGS (value: [String!]) on FIELD_DEFINITION 

	#to add a directive to input graphql type (directive have to be decelerated with INPUT_FIELD_DEFINITION or INPUT_OBJECT )
	directive @SQL_INPUTTYPE_DIRECTIVE (value: [String!]) on FIELD_DEFINITION | OBJECT


	scalar Time #activated for createdAt, deletedAt, updatedAt etc

If an field has Tag autoIncrement it will be not include into patch and input Types. f.E.:

type Cat @SQL{
  id: Int! @SQL_PRIMARY @SQL_GORM(value: "autoIncrement") // id will be removed from add and patch types
  name: String!
  age: Int
  userID: Int!
  alive: Boolean @SQL_GORM(value: "default:true")
}

Scalar ID as autoIncrement Primary key

To use ID as autoIncrement Primary key you have to update gqlgen.yml from :

models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.ID

to

models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.IntID

to use Int instand of String

Hooks

You can manipulate each Query and Mutation through Hooks. The Hooks descriptions are written in db/db_gen.go. For more information, see the autogql_example repository:

A default hook implementation will also be added to db package so you did not have to implement all hook functions:

type CompanyGetHook struct {
	db.DefaultGetHook[model.Company, int]
}

func (g CompanyGetHook) BeforeCallDb(ctx context.Context, db *gorm.DB) (*gorm.DB, error) {
	// your implementation
	return db, nil 
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConstraintFieldHook

func ConstraintFieldHook(ggs *AutoGqlPlugin) func(td *ast.Definition, fd *ast.FieldDefinition, f *modelgen.Field) (*modelgen.Field, error)

func MutateHook

func MutateHook(ggs *AutoGqlPlugin) func(b *modelgen.ModelBuild) *modelgen.ModelBuild

Types

type AutoGqlPlugin

type AutoGqlPlugin struct {
	Handler structure.SqlBuilderHelper
}

func NewAutoGqlPlugin

func NewAutoGqlPlugin() (*AutoGqlPlugin, *modelgen.Plugin)

func (*AutoGqlPlugin) GenerateCode

func (ggs *AutoGqlPlugin) GenerateCode(data *codegen.Data) error

func (*AutoGqlPlugin) InjectSourceEarly

func (ggs *AutoGqlPlugin) InjectSourceEarly() *ast.Source

func (*AutoGqlPlugin) InjectSourceLate

func (ggs *AutoGqlPlugin) InjectSourceLate(schema *ast.Schema) *ast.Source

func (*AutoGqlPlugin) MutateConfig

func (ggs *AutoGqlPlugin) MutateConfig(cfg *config.Config) error

func (*AutoGqlPlugin) Name

func (ggs *AutoGqlPlugin) Name() string

type ForeignNameResult added in v0.1.0

type ForeignNameResult struct {
	Key   string
	Table structure.Object
}

type GenerateData

type GenerateData struct {
	Data    *codegen.Data
	Handler structure.SqlBuilderHelper
}

func (*GenerateData) ForeignName added in v0.0.22

func (db *GenerateData) ForeignName(object structure.Object, entity structure.Entity) ForeignNameResult

func (*GenerateData) GenPointerStrIfNeeded

func (db *GenerateData) GenPointerStrIfNeeded(typeName string, v structure.Entity, revert bool) string

func (*GenerateData) GeneratedPackage

func (db *GenerateData) GeneratedPackage() string

func (*GenerateData) GetGoField added in v0.1.5

func (db *GenerateData) GetGoField(typeName string, v structure.Entity) *codegen.Field

func (*GenerateData) GetGoFieldName

func (db *GenerateData) GetGoFieldName(typeName string, v structure.Entity) string

func (*GenerateData) GetGoFieldType

func (db *GenerateData) GetGoFieldType(typeName string, v structure.Entity, rootType bool) string

func (*GenerateData) GetGoFieldTypeName

func (db *GenerateData) GetGoFieldTypeName(typeName string, v structure.Entity) string

func (*GenerateData) GetMaxMatchGoFieldType added in v0.0.21

func (db *GenerateData) GetMaxMatchGoFieldType(objectname string, entities []structure.Entity) string

func (*GenerateData) GetPackage

func (db *GenerateData) GetPackage(v structure.Object) string

func (*GenerateData) GetPointerSymbol

func (db *GenerateData) GetPointerSymbol(typeName string, entity structure.Entity) string

func (*GenerateData) GetValueOfInput

func (db *GenerateData) GetValueOfInput(objectname string, builder structure.Object, v structure.Entity) string

func (*GenerateData) HookList

func (db *GenerateData) HookList(suffix, prefix string) []string

func (*GenerateData) HookListMany2Many added in v0.0.27

func (db *GenerateData) HookListMany2Many(suffix string) []string

func (*GenerateData) Imports

func (db *GenerateData) Imports() []string

func (*GenerateData) ModelsMigrations

func (db *GenerateData) ModelsMigrations() string

func (*GenerateData) PointerStrIfNeeded

func (db *GenerateData) PointerStrIfNeeded(typeName string, v structure.Entity, revert bool) string

func (*GenerateData) PrimaryKeyEntityOfObject

func (db *GenerateData) PrimaryKeyEntityOfObject(o string) *structure.Entity

func (*GenerateData) PrimaryKeyOfObject

func (db *GenerateData) PrimaryKeyOfObject(o string) string

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL