Skip to content

Task 4.5 Implementation Summary: Add GraphQL Types and Resolvers for Inventory

Task 4.5 Implementation Summary: Add GraphQL Types and Resolvers for Inventory

Section titled “Task 4.5 Implementation Summary: Add GraphQL Types and Resolvers for Inventory”

Updated lib/bartendie_web/schema.ex:

  • Added new inventory queries:
    • product(id: ID!) - Get single product by ID
    • products(type: ProductType, brand: String) - Get all products with filtering
    • productInventory(id: ID!) - Get inventory level for a product
    • inventoryTransactions(productId: ID!, dateFrom: DateTime, dateTo: DateTime) - Get transaction history
  • Added new inventory mutations:
    • createProduct(input: CreateProductInput!) - Create new products
    • Existing updateInventoryLevel(id: ID!, level: Float!) - Update inventory levels

Updated lib/bartendie_web/schema/inventory_types.ex:

  • Enhanced Product type with missing fields (type, currentLevel, updatedAt)
  • Updated InventoryTransaction type to match domain model
  • Added InventoryLevel type for inventory level queries
  • Updated transaction type enum to match domain model (restock, usage, adjustment, waste, transfer, initial)
  • Added currentLevel field to CreateProductInput

Completely rewrote lib/bartendie_web/resolvers/inventory.ex:

  • get_product/3 - Retrieves single product from read model
  • get_all_products/3 - Retrieves all products with optional filtering by type and brand
  • get_product_inventory/3 - Returns current inventory level for a product
  • get_inventory_transactions/3 - Returns transaction history with optional date filtering
  • list_inventory/3 - Returns inventory items (products formatted as inventory items)
  • create_product/3 - Dispatches CreateProduct command and returns created product
  • update_level/3 - Dispatches UpdateInventory command and returns updated inventory item
  • add_item/3 - Creates new product or updates existing product level
  • get_product_for_inventory_item/3 - Resolves product for inventory items
  • is_low_stock/3 - Calculates low stock status
  • get_usage_history/3 - Returns transaction history for inventory items
  • Database query filtering by product type, brand, low stock status, and date ranges
  • Product-to-inventory-item transformation
  • Error message formatting

Connected to existing domain layer:

  • Uses Bartendie.App.dispatch/1 for command dispatch
  • Queries read models via Bartendie.Repo
  • Integrates with existing CreateProduct and UpdateInventory commands
  • Uses existing Product and InventoryTransaction schemas
  • Leverages existing projections for read model updates

Created comprehensive tests:

  • test/bartendie_web/resolvers/inventory_test.exs - Unit tests for all resolvers
  • test/bartendie_web/graphql/inventory_integration_test.exs - GraphQL integration tests
  • test_inventory_graphql.exs - Standalone test script for manual testing
# Get single product
product(id: ID!): Product
# Get all products with filtering
products(type: ProductType, brand: String): [Product!]!
# Get inventory level for a product
productInventory(id: ID!): InventoryLevel
# Get transaction history
inventoryTransactions(productId: ID!, dateFrom: DateTime, dateTo: DateTime): [InventoryTransaction!]!
# Get inventory items (legacy format)
inventory(category: ProductType, lowStockOnly: Boolean): [InventoryItem!]!
# Create new product
createProduct(input: CreateProductInput!): Product
# Update inventory level
updateInventoryLevel(id: ID!, level: Float!): InventoryItem
# Add inventory item (creates or updates)
addInventoryItem(input: AddInventoryInput!): InventoryItem
  • Command-Query Separation: Mutations dispatch commands, queries read from projections
  • Real-time Updates: Changes are projected to read models automatically
  • Filtering Support: Products can be filtered by type, brand, stock level
  • Transaction History: Full audit trail of inventory changes
  • Error Handling: Proper GraphQL error responses
  • Type Safety: Strong typing with Absinthe schema validation
  • CQRS Pattern: Commands modify state, queries read from projections
  • Event Sourcing: All changes create events that update read models
  • GraphQL Layer: Provides unified API over domain services
  • Authentication: Mutations require authentication (queries are public)
  1. GraphQL mutation → Resolver → Command dispatch → Aggregate → Event
  2. Event → Projection → Read model update
  3. GraphQL query → Resolver → Read model query → Response
  • Command validation errors are formatted for GraphQL
  • Database errors are caught and returned as GraphQL errors
  • Non-existent resources return appropriate null/error responses
mutation {
createProduct(input: {
name: "Bourbon Whiskey"
brand: "Buffalo Trace"
productType: SPIRIT
volume: 750.0
currentLevel: 750.0
barcode: "123456789"
}) {
id
name
brand
type
currentLevel
}
}
mutation {
updateInventoryLevel(id: "product-id", level: 500.0) {
productId
currentLevel
lastUpdated
}
}
query {
products(type: SPIRIT) {
id
name
brand
currentLevel
type
}
}
query {
inventoryTransactions(productId: "product-id") {
transactionType
previousLevel
currentLevel
reason
timestamp
}
}
  • GraphQL types for Product, InventoryLevel, and InventoryTransaction - Implemented
  • getProduct(id) query - Implemented as product(id: ID!)
  • getAllProducts query - Implemented as products(type: ProductType, brand: String)
  • getProductInventory(id) query - Implemented as productInventory(id: ID!)
  • getInventoryTransactions(productId, dateRange) query - Implemented with date filtering
  • createProduct mutation - Implemented with full command dispatch
  • updateInventoryLevel mutation - Implemented with command dispatch
  • Resolvers connected to command dispatch and read models - Fully integrated
  • Integration tests for each operation - Comprehensive test suite created

The GraphQL API is now fully functional and ready for frontend integration. All inventory operations can be performed through the GraphQL endpoint at /api/graphql, with GraphiQL available at /api/graphiql for interactive testing.