# Goldorin
Goldorin is the language that is used to generate GraphQL schema, notation, resolver, related db schema, migration and slate documentation. It is used widely inside arcblock for internal and external APIs.
## How to use
Write your schema definition using Goldorin language, and then parse and generate code with Goldorin toolkit:
```elixir
defmodule MyApp.CodeGen do
@moduledoc false
alias Goldorin.Adapter.{Checker, DbMigration, DbRepo, DbSchema, GqlNotation, GqlSchema, Slate}
alias Goldorin.Parser
app_name = :myapp
schemas = [:your_schema_1, :your_shcema_2]
cwd = Application.app_dir(app_name)
target_path = Path.join(cwd, "_gen")
path = Path.join(target_path, "priv/gen")
doc_path = Path.join(target_path, "api_docs")
data =
schemas
|> Enum.map(fn schema -> Path.join(cwd, "priv/docs/#{schema}/main.yml") end)
|> Parser.parse()
# db related
DbRepo.gen(data, app_name, [{:path, Path.join(path, "db/repo")} | opts])
DbSchema.gen(data, app_name, [{:path, Path.join(path, "db/schema")} | opts])
# Note this only generate initial migration. You shall manually create increment migrations yourself.
DbMigration.gen(data, app_name, [{:path, Path.join(path, "db/migration")} | opts])
# GraphQL related
GqlNotation.gen(data, app_name, [{:path, Path.join(path, "gql/notation")} | opts])
GqlSchema.gen(data, app_name, [{:path, Path.join(path, "gql/schema")} | opts])
# slate doc. To generate slate doc, please run "mix goldorin.gen.doc"
Slate.gen(data, app_name, path: doc_path)
Checker.gen(data, app_name, path: Path.join(path, "checker"))
end
```
Then in your application start code, add this to auto check if a specific resolver is defined properly:
```elixir
MyApp.Goldorin.ensure_resolver_defined()
```
## Goldorin Language
Goldorin uses yaml to define the schema. The main definition is usually called `main.yml`, which looks like this:
```yaml
- name: ethereum
base_apis:
- ../base/api.yml
types:
- pagination.yml
- ../base/interface.yml
- basic.yml
- complex.yml
apis:
- queries.yml
- mutations.yml
- subscriptions.yml
```
A type looks like this:
```yaml
- name: PageInfo
type: output # default
fields:
- name: total
type: integer
doc: The total number of records accross all pages.
- name: cursor
type: string!
doc: The cursor of the last record in this page.
- name: next
type: boolean!
doc: To indicate if there are more pages afwards.
meta: resolver=page_resolver
doc: The pagination information.
- name: PagingInput
type: input
fields:
- name: size
type: int!
default: 10
doc: Returns first several records specified by this parameter.
- name: cursor
type: string
doc: Returns records after the cursor specified by this parameter.
doc: The common arguments for quering data with pagination.
```
Example of base type:
```yaml
- name: Account
abstract: true
doc: The Account interface represents participants of transactions in a blockchain.
fields:
- name: address
type: api=string db=varchar(100)
meta: pk=true col=address null=false
doc: The address generated based on the public key of the account.
- name: pub_key
type: api=string db=varchar(130)
meta: null=false
doc: The public key associated with this account.
- name: balance
type: api=bigint db=bigint
meta: null=false
doc: The balance of this account.
- name: total_received
type: api=bigint db=bigint
meta: resolver=false
doc: The total amount received by this account.
- name: number_txs_received
type: api=integer db=integer
meta: null=false
doc: The number of transactions where the account is a receiver.
- name: total_sent
type: api=bigint db=bigint
meta: null=false
doc: The total amount sent by this account.
- name: number_txs_sent
type: api=integer db=integer
meta: null=false
doc: The number of transactions where the account is a sender.
```
Example of inherited type:
```yaml
- name: BitcoinAccount
base: Account
abstract: false
fields:
- name: script_type
type: api=string db=varchar(20)
meta: null=false
doc: The type of this address.
- name: sub_keys
type: api=[string]
meta: resolver=account_sub_keys
doc: The subsidiary public keys associated with this addres, normally for multi-signature addresses.
- name: txs_received
type: PagedBitcoinTransactions
doc: The transactions where the account is a receiver.
- name: txs_sent
type: PagedBitcoinTransactions
doc: The transactions where the account is a sender.
meta: table_name=bitcoin_account
doc: The BitcoinAccount object implements the Account interface for Bitcoin chain.
```
Example of custom scalar type:
```yaml
- name: EthereumBlock
base: Block
abstract: false
fields:
- name: total
type: api=custom_big_number db=decimal
meta: null=false
doc: The total amount of ether transacted in this block.
```
## Workflow of Goldorin
Interpreting main.yml
![](https://github.com/ArcBlock/goldorin/blob/master/docs/images/interpreting_main.png)
Interpreting APIs
![](https://github.com/ArcBlock/goldorin/blob/master/docs/images/interpreting_apis.png)
Interpreting Types
![](https://github.com/ArcBlock/goldorin/blob/master/docs/images/interpreting_types.png)
## Syntax
```yaml
- name: the name of api, interface or params.
e.g. name: block_by_hash, or name: block or hash.
- doc: the description of return value or params
e.g. doc: returns a block by it’s hash, or doc: he hash of the block.
- return: the return data type of the apis.
- meta: the info of the api, interface or the params
e.g. meta: null=false, resolver=false, pk=true
- fields: the set of the data type field in db or GraphQL schema.
- base: the fundamental api or interface.
e.g. - name: block_by_hash
base: block_by_hash
return: bitcoin_block
- abstract: for those base types, abstract equals to true indicates the data type will not be instantiated. Default value is false.
e.g. - name: block
abstract: true
```