Nested Containers
Create bags that can contain other bags. Nested containers let you organize inventory hierarchically—a backpack containing pouches, each with their own contents.
Prerequisites
Before starting, you should:
Overview
We'll create nested containers by:
- Creating parent and child containers
- Adding the child container as an item in the parent
- Using
{ deep: true }for queries that traverse the hierarchy - Understanding cycle prevention
Step 1: Create Parent and Child Containers
Both are regular containers. The "nesting" happens when you add one as an item in another.
import { createInventoryManager } from '@motioneffector/inventory'
const inventory = createInventoryManager()
// Parent container
inventory.createContainer('backpack', { mode: 'unlimited' })
// Child container (a pouch that goes inside the backpack)
inventory.createContainer('gem-pouch', { mode: 'count', maxCount: 10 })
Step 2: Add Child Container as Item
Add the child container's ID as an item in the parent.
// Put the gem pouch in the backpack
inventory.addItem('backpack', 'gem-pouch', 1)
// Add items to the pouch directly
inventory.addItem('gem-pouch', 'ruby', 3)
inventory.addItem('gem-pouch', 'emerald', 2)
// Add other items to the backpack
inventory.addItem('backpack', 'sword', 1)
inventory.addItem('backpack', 'potion', 5)
Now the backpack contains: sword, potions, and a gem-pouch. The gem-pouch contains rubies and emeralds.
Step 3: Query with Deep Option
Use { deep: true } to search or list contents across the entire hierarchy.
// Shallow: only direct contents
const shallow = inventory.getContents('backpack')
// [{ itemId: 'gem-pouch', quantity: 1 }, { itemId: 'sword', quantity: 1 }, { itemId: 'potion', quantity: 5 }]
// Deep: includes nested container contents
const deep = inventory.getContents('backpack', { deep: true })
// [{ itemId: 'gem-pouch', quantity: 1 }, { itemId: 'sword', quantity: 1 }, { itemId: 'potion', quantity: 5 },
// { itemId: 'ruby', quantity: 3 }, { itemId: 'emerald', quantity: 2 }]
// Find item across all containers
const found = inventory.findItem('ruby', { deep: true })
// [{ containerId: 'gem-pouch', quantity: 3 }]
Step 4: Deep Weight Calculation
Calculate total weight including nested contents.
const inventory = createInventoryManager({
getItemWeight: (id) => {
if (id === 'gem-pouch') return 0.5 // Empty pouch weight
if (id === 'ruby') return 0.1
if (id === 'sword') return 5
return 1
},
})
inventory.createContainer('backpack', { mode: 'weight', maxWeight: 50 })
inventory.createContainer('gem-pouch', { mode: 'unlimited' })
inventory.addItem('gem-pouch', 'ruby', 10) // 1.0 weight in gems
inventory.addItem('backpack', 'gem-pouch', 1)
inventory.addItem('backpack', 'sword', 1)
// Shallow weight: pouch (0.5) + sword (5) = 5.5
const shallow = inventory.getTotalWeight('backpack')
console.log(shallow) // 5.5
// Deep weight: pouch (0.5) + gems (1.0) + sword (5) = 6.5
const deep = inventory.getTotalWeight('backpack', { deep: true })
console.log(deep) // 6.5
Cycle Prevention
The library prevents circular nesting, which would cause infinite loops.
inventory.createContainer('bag-a', { mode: 'unlimited' })
inventory.createContainer('bag-b', { mode: 'unlimited' })
inventory.addItem('bag-a', 'bag-b', 1) // OK: bag-b is inside bag-a
// This would create a cycle: bag-a → bag-b → bag-a
inventory.addItem('bag-b', 'bag-a', 1) // Throws: "Cannot create circular nesting"
// Self-nesting is also prevented
inventory.addItem('bag-a', 'bag-a', 1) // Throws: "Cannot nest container in itself"
Complete Example
import { createInventoryManager } from '@motioneffector/inventory'
const inventory = createInventoryManager({
getItemWeight: (id) => {
const weights: Record<string, number> = {
'backpack': 2,
'coin-purse': 0.2,
'gem-pouch': 0.3,
'gold': 0.01,
'ruby': 0.1,
'sword': 5,
'potion': 0.5,
}
return weights[id] ?? 1
},
})
// Main inventory
inventory.createContainer('backpack', { mode: 'weight', maxWeight: 30 })
// Specialized sub-containers
inventory.createContainer('coin-purse', { mode: 'unlimited' })
inventory.createContainer('gem-pouch', { mode: 'count', maxCount: 20 })
// Nest them in the backpack
inventory.addItem('backpack', 'coin-purse', 1)
inventory.addItem('backpack', 'gem-pouch', 1)
// Fill the sub-containers
inventory.addItem('coin-purse', 'gold', 500)
inventory.addItem('gem-pouch', 'ruby', 15)
// Add regular items
inventory.addItem('backpack', 'sword', 1)
inventory.addItem('backpack', 'potion', 4)
// Query everything
console.log('Backpack contents (shallow):')
console.log(inventory.getContents('backpack'))
console.log('Backpack contents (deep):')
console.log(inventory.getContents('backpack', { deep: true }))
console.log('Total weight (shallow):', inventory.getTotalWeight('backpack'))
console.log('Total weight (deep):', inventory.getTotalWeight('backpack', { deep: true }))
// Find all gold
const goldLocations = inventory.findItem('gold', { deep: true })
console.log('Gold found:', goldLocations)
Variations
Multiple Nesting Levels
inventory.createContainer('vault', { mode: 'unlimited' })
inventory.createContainer('chest', { mode: 'unlimited' })
inventory.createContainer('box', { mode: 'unlimited' })
// Vault contains chest, chest contains box
inventory.addItem('vault', 'chest', 1)
inventory.addItem('chest', 'box', 1)
inventory.addItem('box', 'treasure', 1)
// Deep query finds treasure
const found = inventory.findItem('treasure', { deep: true })
// [{ containerId: 'box', quantity: 1 }]
Checking If Container Is Nested
function isNested(containerId: string): boolean {
const locations = inventory.findItem(containerId)
return locations.length > 0
}
Troubleshooting
Deep Query Returns Duplicates
Symptom: Items appear multiple times in deep query results.
Cause: This shouldn't happen—the library tracks visited containers. If you see duplicates, check if you have multiple containers with similar IDs.
Solution: Ensure container IDs are unique.
Circular Nesting Error Unexpected
Symptom: Adding a container throws "Cannot create circular nesting" when you don't expect it.
Cause: There's an existing path from the target container back to the source.
Solution: Use findItem to trace where containers are located and identify the cycle.
See Also
- Containers - Container basics
- Querying API - Reference for
getContents,findItem,getTotalWeightwith deep option