Skip to content

Instantly share code, notes, and snippets.

@sudarshang
Forked from dabit3/SingleTableAppSync.md
Created September 4, 2020 18:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sudarshang/f803e5e06085015087abc6029db95167 to your computer and use it in GitHub Desktop.
Save sudarshang/f803e5e06085015087abc6029db95167 to your computer and use it in GitHub Desktop.
GraphQL Single Table Design with DynamoDB and AWS AppSync

GraphQL

GraphQL Schema

type Customer {
  id: ID!
  email: String!
}

type Invoice {
  id: ID!
  amount: Float!
  date: String!
}

enum Method {
  Express
  Standard
}

type Order {
  id: ID!
  amount: Float!
  date: String!
}

type OrderItem {
  id: ID!
  qty: Int!
  price: Float!
  orderId: String
}

type Query {
  getCustomerById(customerId: ID!): Customer
  getProductById(warehouseItemId: ID!): WarehouseItem
  getWarehouseById(warehouseId: ID!): Warehouse
  getInventoryByProductId(productId: ID!): [WarehouseItem]
  getOrderById(orderId: ID!): Order
  getOrderByIdFromMain(orderId: ID!): Order
  getShipmentsByOrderId(orderId: ID!): [Shipment]
  getOrderHistoryByDateRange(customerId: ID!, beginning: String!, ending: String!): [OrderItem]
}

type ShipItem {
  id: ID!
  qty: Int!
}

type Shipment {
  id: ID!
  address: AWSJSON!
  method: Method!
}

type Warehouse {
  id: ID!
  address: AWSJSON!
}

type WarehouseItem {
  id: ID!
  qty: Int!
  price: Float!
  detail: AWSJSON!
}

GraphQL Queries

query getOrderHistoryByID {
  getOrderHistoryById(orderId: "O#277") {
    date
    id
    amount
  }
}

query getOrderHistoryByDateRange {
  getOrderHistoryByDateRange(
    customerId: "C#71",
    beginning: "2020-08-22T13:30:19",
    ending: "2020-08-26T13:30:19"
  ) {
    id
    qty
    price
    orderId
  }
}

query getShipmentsbyOrderId {
  getShipmentsByOrderId(orderId: "O#135") {
    id
    method
    address
  }
}

query getOrderById {
  getOrderById(orderId: "O#277") {
    id
    amount
    date
  }
}

query getInventoryById {
  getInventoryByProductId(productId: "P#42") {
    id
    price
    qty
    detail
  }
}

query getProductById {
  getProductById(warehouseItemId: "P#42") {
    qty
    price
    detail
  }
}

query getCustomerByCustomerId {
  getCustomerById(customerId: "C#34") {
    id
    email
  }
}

Lambda

index.js

const getCustomerById = require('./getCustomerById')
const getProductById = require('./getProductById')
const getWarehouseById = require('./getWarehouseById')
const getInventoryByProductId = require('./getInventoryByProductId')
const getOrderById = require('./getOrderById')
const getShipmentsByOrderId = require('./getShipmentsByOrderId')
const getOrderHistoryById = require('./getOrderHistoryById')
const getOrderHistoryByDateRange = require('./getOrderHistoryByDateRange')

exports.handler = async (event) => {
    const { arguments, info: { fieldName } }= event
    const { customerId, warehouseItemId, warehouseId, productId, orderId, beginning, ending } = arguments

    switch(fieldName) {
        case "getCustomerById":
            return await getCustomerById(customerId)
        case "getProductById":
            return await getProductById(warehouseItemId)
        case "getWarehouseById":
            return await getWarehouseById(warehouseId)
        case "getInventoryByProductId":
            return await getInventoryByProductId(productId)
        case "getOrderById":
            return await getOrderById(orderId)
        case "getOrderByIdFromMain":
            return await getOrderById(orderId)
        case "getShipmentsByOrderId":
            return await getShipmentsByOrderId(orderId)
        case "getOrderHistoryById":
            return await getOrderHistoryById(orderId)
        case "getOrderHistoryByDateRange":
            return await getOrderHistoryByDateRange(customerId, beginning, ending)
        default:
            return null
    }
    
};

getCustomerById.js

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()

async function getCustomerById(customerId) {
  var params = {
    TableName : process.env.WH_TABLE,
    Key: { PK: customerId, SK: customerId }
  }
  try {
    const { Item } = await docClient.get(params).promise()
    return { email: Item.email, id: Item.PK }
  } catch (err) {
    return err
  }
}

module.exports = getCustomerById

getInventoryByProductId.js

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()

async function getInventoryByProductId(productId) {
  const params = {
    TableName : process.env.WH_TABLE,
    KeyConditionExpression: `PK = :productId and begins_with(SK, :sk)`,
    ExpressionAttributeValues: {
      ':productId': productId,
      ':sk': "W#"
    }
  }

  try {
    const data = await docClient.query(params).promise()
    const items = data.Items.map(d => {
        d.id = d.PK
        return d
    })
    return items
  } catch (err) {
    console.log('error from getInventoryByProductId: ', err)
    return err
  }
}

module.exports = getInventoryByProductId

getOrderById.js

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()

async function getOrderById(orderId) {
  const params = {
    TableName : process.env.WH_TABLE,
    KeyConditionExpression: `PK = :orderId and begins_with(SK, :sk)`,
    ExpressionAttributeValues: {
      ':orderId': orderId,
      ':sk': "C"
    }
  }

  try {
    const data = await docClient.query(params).promise()
    const order = data.Items[0]
    order.id = order.PK
    return order
  } catch (err) {
    console.log('error from getInventoryByProductId: ', err)
    return err
  }
}

module.exports = getOrderById

getProductById.js

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()

async function getProductById(warehouseItemId) {
  var params = {
    TableName : process.env.WH_TABLE,
    KeyConditionExpression: `PK = :warehouseItemId and begins_with(SK, :sk)`,
    ExpressionAttributeValues: {
      ':warehouseItemId': warehouseItemId,
      ':sk': "W#"
    }
  }
  
  try {
    const { Items } = await docClient.query(params).promise()
    return Items[0]
  } catch (err) {
    console.log('error fetching from DDB: ', err)
    return err
  }
}

module.exports = getProductById

getShipmentsByOrderID.js

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()

async function getShipmentsByOrderId(orderId) {
  const params = {
    TableName : process.env.WH_TABLE,
    KeyConditionExpression: `PK = :orderId and begins_with(SK, :sk)`,
    ExpressionAttributeValues: {
      ':orderId': orderId,
      ':sk': "S#"
    }
  }

  try {
    const data = await docClient.query(params).promise()
    const items = data.Items.map(d => {
        d.id = d.PK
        return d
    })
    return items
  } catch (err) {
    return err
  }
}

module.exports = getShipmentsByOrderId

getWarehouseByID.js

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()

async function getWarehouseById(warehouseId) {
  var params = {
    TableName : process.env.WH_TABLE,
    Key: { PK: warehouseId, SK: warehouseId }
  }
  try {
    const { Item } = await docClient.get(params).promise()
    return { address: Item.address, id: Item.PK }
  } catch (err) {
    return err
  }
}

module.exports = getWarehouseById

getOrderHistoryByDateRange.js

const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()

async function getOrderHistoryByDateRange(customerId, beginning, ending) {
  console.log('beginning: ', beginning)
  console.log('ending: ', ending)
  const params = {
    IndexName: "GSI2",
    TableName : process.env.WH_TABLE,
    ExpressionAttributeNames:{
        "#GSI2PK": "GSI2PK",
        "#GSI2SK": "GSI2SK"
    },
    KeyConditionExpression: `#GSI2PK = :customerId and #GSI2SK BETWEEN :beginningValue AND :endingValue`,
    ExpressionAttributeValues: {
      ':customerId': customerId,
      ':beginningValue': beginning,
      ':endingValue': ending
    }
  }

  try {
    const data = await docClient.query(params).promise()
    const Items = data.Items.map(d => {
      d.id = `${d.GSI2PK}_${d.GSI2SK}`
      d.orderId = d.PK
      return d
    }) 
    console.log("ITEMS:::", Items)
    return Items
  } catch (err) {
    console.log('error from getOrderHistoryById: ', err)
    return err
  }
}

module.exports = getOrderHistoryByDateRange

Table

Table view

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment