# Hasura

This is a main class. All queries/mutations/subscription you will run using it's instance.

# Instance Methods

# new Hasura( parameters )

Currently ORM works only on backend and uses admin access to Hasura

  • Arguments:
    • {object} parameters
      • {string} graphqlUrl - Hasura's graphql endpoint
      • {string} adminSecret - admin secret to access endpoint
      • {string} [queryUrl] - Hasura's query API endpoint (autogenerated from graphqlUrl by default)
      • {string} [wsUrl] - Hasura's Websocket endpoint (autogenerated from graphqlUrl by default)
      • {object} [query] - Query method specific settings
        • {boolean} [flatOne = true] - Response manipulation. Please read flatOne method
      • {object} [subscription] - Subscribe method specific settings
        • {boolean} [flatOne = true] - Response manipulation. Please read flatOne method
      • {object} [mutation] - Mutate method specific settings
        • {boolean} [flatOne = true] - Response manipulation. Please read flatOne method
      • {object} [gqlConnectionSettings] - Hasura's graphql API endpoint settings (currenlty blank)
      • {object} [sqlConnectionSettings] - Hasura's query API endpoint settings (currenlty blank)
      • {object} [wsConnectionSettings] - Hasura's Websocket API endpoint settings
        • {boolean} [lazy = true] - WS lazy connection. If true - connection will be established only on first subscripe method call
        • {boolean} [reconnect = true] - WS reconnect connection.
  • Example:
const {Hasura} = require('hasura-om')
const orm = new Hasura({
    graphqlUrl: '',
    adminSecret: ''
})

# async this.generateTablesFromAPI()

  • Usage: This method gets information about tables from Hasura's query API and generates the whole schema
  • Example:
await orm.generateTablesFromAPI()

# this.createTable( parameters )

This a Table constructor

  • Arguments:
    • {object} parameters
      • {string} name
      • {string} [type]
  • Returns: {Table} Instance
  • Example:
orm.createTable({
    name: 'user'
})

# this.table( name )

  • Arguments:
    • {string} name
  • Returns: {Table} Instance
  • Example:
console.log(orm.table('user').field('id').isPrimary)

# async this.query( parameters, settings )

  • Arguments:
    • {object} parameters
      • {object} tablename* - here you should put exact table name
        • {object} select - select query. You can skip this key and define its options if you query select only
          • {object} [where] - where object { age :{ _gt: 18 } }
          • {integer} [limit] - limit
          • {integer} [offset] - offset
          • {object} [order_by] - order_by object { last_seen: 'desc' }
          • {string} [distinct_on] - distinct_on type
          • {string | array | object} [fields] - you can define fields just like in {Fragment} Instance
          • {string | Fragment} [fragment] - name of Fragment or a Fragment instance
        • {object} aggregate - aggregate query
          • {object} [where] - where object { age :{ _gt: 18 } }
          • {integer} [limit] - limit
          • {integer} [offset] - offset
          • {object} [order_by] - order_by object { last_seen: 'desc' }
          • {string} [distinct_on] - distinct_on type
          • {string | array | object} [fields] - you can define aggregate by yourself just like in {Fragment} Instance
          • {object} count - can leave empty if you need just count all the fields
            • {string} columns
            • {boolean} distinct
          • {string} avg
          • {string} max
          • {string} min
          • {string} stddev
          • {string} stddev_pop
          • {string} stddev_samp
          • {string} sum
          • {string} var_pop
          • {string} var_samp
          • {string} variance
    • {object} [settings]
      • {boolean} [flatOne] - Response manipulation. Please read flatOne method
  • Returns:
    • {array} - reponse in format [err, response]
      • {object} error
      • {object | array} response
  • Example
let [err, response] = await orm.query({
    user: { 
        where: { isOnline: { _eq: true } },
        fields: ['id', 'name', 'userpic']
    }
})
console.log(response)
/* 
    [
        {id: 2, name: 'Peter', userpic: 'https://....'},
        ...
    ]
*/

# async this.mutate( parameters, settings )

  • Arguments:
    • {object} parameters
      • {object} tablename* - here you should put exact table name
        • {object} insert - Insert mutation
          • {object | array} object - object or array of object defining inserting row. Of course you can inserted nested rows too
          • {string | array | object} [fields] - you can define fields just like in {Fragment} Instance
          • {string | Fragment} [fragment] - name of Fragment or a Fragment instance
        • {object} update - Update mutation
          • {object} where - where object { age :{ _gt: 18 } }
          • {object} _set - set object { age : 21 }
          • {object} _inc - increment object { age : 2 }
          • {string | array | object} [fields] - you can define fields just like in {Fragment} Instance
          • {string | Fragment} [fragment] - name of Fragment or a Fragment instance
        • {object} delete - Delete mutation
          • {object} where - where object { age :{ _gt: 18 } }
          • {string | array | object} [fields] - you can define fields just like in {Fragment} Instance
          • {string | Fragment} [fragment] - name of Fragment or a Fragment instance
    • {object} [settings]
      • {boolean} [flatOne] - Response manipulation. Please read flatOne method
  • Returns:
    • {array} - reponse in format [err, response]
      • {object} error
      • {object | array} response
  • Example
let [err, response] = await orm.mutate({
    user: {
        insert: {
            objects: {
                name: 'Peter',
                userpic: 'https://...',
                points: 300
            }
        }
        update: {
            where: { id: { _eq: 3 } },
            _inc: { points: 50 },
            fields: ['id', 'name', 'points']
        }
    }
})
console.log(response)
/* 
    {
        insert: [
            {id: 3, name: 'Peter', points: 300, ...allUserFields},
        ],
        update: [
            {id: 3, name: 'Peter', points: 350},
        ]
    }
*/

# async this.subscribe( parameters, callback, settings )

  • Arguments:
    • {object} parameters - just like in a query method
    • {function} callback([err, response]) - function to be called on changes
    • {object} [settings]
      • {boolean} [flatOne] - Response manipulation. Please read flatOne method
  • Returns:
    • {function} unsubscribe - call this function if you want to stop subscription
  • Example
let unsubscribe = orm.subscribe({
    user: { where: { isOnline: { _eq: true } } }
}, ([err, users] => {
    console.log(users)
}))

# this.flatGqlResponse( { flatSettings, settings, parameters } )

This method can migrate to a different place, cause it is utitilitary

  • Arguments:
    • {object} parameters
      • {array} [flatSettings] - an array of objects key: value - path_from: path_to [ { 'user.returning': 'user.select' } ]
      • {array} settings
        • {booleant} [flatOne = true] - see an explanation below
        • {booleant} [getFirst = false] - see an explanation below
      • {array} parameters - input parameters
  • Returns:
    • {function} - function that will change response output
      • Arguments:
        • {object | array} response graphql response
      • Returns:
        • {object | array} response response after manipulation
  • Example
let gqlResponse = {
  "data": {
    "teams": [
      {
        "id": 7,
        "team_name": "test"
      }
    ]
  }
}

console.log(flatGqlResponse({
    flatSettings: [{
        'teams.select': 'teams'
    }, {
        flatOne: true,
        getFirst: true
    }, ...]
}))
/* 
1. data key is a default path, so no need to change it somehow, so base response is:
let gqlResponse = {
  teams: [
    {
      id: 7,
      team_name: "test"
    }
  ]
}

2. flatSettings - {'teams.select': 'teams'} will change path 'teams' to 'teams.select'
This is needed to make every request looks the same tableName.select, tableName.aggregate, tableName.insert etc...
let gqlResponse = {
  teams: {
    select: [
      {
        id: 7,
        team_name: "test"
      }
    ]
  }
}

3. flatOne is a tricky one. It also changes a path, deleting sinle object keys. 
In our example teams and select are both singe keys, so it will transform path 'teams.select' to ''
let gqlResponse = [
  {
    id: 7,
    team_name: "test"
  }
]

4. getFirst just return first entry of an array. Very useful if you want to get one user for example and you will get just user object
let gqlResponse = {
  id: 7,
  team_name: "test"
}
*/

WARNING

This methods used to generate query/mutation from parameters This section could be useful if you want to generate queries by yourself, but I think they need to be refactored, so I'll skip documentation for now

# this.buildQuery( parameters, queryType )

# this.buildMutation( parameters )

# Usage

const {Hasura} = require('hasura-om')

let orm = new Hasura({
    graphqlUrl: 'url',
    adminSecret: 'secret'
})
await orm.generateTablesFromAPI()

let [err, user] = await orm.query({
    user: { where: { id: { _eq: 3 } } }
})
console.log(user[0])
/* 
    {
        id: 3,
        ...userFields
    }
*/

let [err, user] = await orm.query({
    user: { 
        where: { id: { _eq: 3 } },
        fields: ['id', 'name']
    }
})
console.log(user[0])
/* 
    {
        id: 3,
        name: 'Peter'
    }
*/
This framework is not affiliated with the Hasura team.

MIT Licensed | 2020-present by Spartak