Collection
Common Patterns & Production Recipes
Real-world patterns from GitHub, Reddit, Stripe, and more.
Social Media: Reddit-Style Comments
import { nest, paginate } from '@ontologyio/receta/collection'
import { getPath } from '@ontologyio/receta/object'
import { unwrapOr as unwrapOptionOr } from '@ontologyio/receta/option'
import { pipe } from 'remeda'
// Hierarchical comment display
const displayComments = (comments: Comment[], userId: number, postId: number) =>
pipe(
comments,
nest<Comment>(['userId', 'postId']),
getPath<Comment[]>([userId, postId]),
unwrapOptionOr<Comment[]>([]),
paginate({ page: 1, pageSize: 20 })
)E-commerce: Order Tracking
import { diff } from '@ontologyio/receta/collection'
// Detect order status changes for notifications
const trackOrderChanges = (oldOrders: Order[], newOrders: Order[]) => {
const changes = diff(oldOrders, newOrders, o => o.id)
for (const { old, new: updated } of changes.updated) {
if (old.status !== updated.status) {
sendNotification({
orderId: updated.id,
oldStatus: old.status,
newStatus: updated.status,
customer: updated.customerId
})
}
}
return changes
}API Design: GitHub-Style Pagination
import { paginateCursor } from '@ontologyio/receta/collection'
// Cursor-based API endpoint
app.get('/api/events', (req, res) => {
const result = paginateCursor(
events,
e => e.id,
{
cursor: req.query.cursor as string,
limit: Number(req.query.limit) || 50
}
)
res.json({
data: result.items,
pagination: {
next_cursor: result.nextCursor,
has_more: result.hasMore
}
})
})State Management: Redux Normalization
import { indexByUnique } from '@ontologyio/receta/collection'
import { unwrapOr } from '@ontologyio/receta/result'
const normalizeEntities = <T extends { id: string }>(entities: T[]) =>
pipe(
entities,
indexByUnique(e => e.id, { onCollision: 'last' }),
unwrapOr({})
)
const store = {
users: normalizeEntities(users),
posts: normalizeEntities(posts),
comments: normalizeEntities(comments)
}Access Control: Permission Merging
import { union } from '@ontologyio/receta/collection'
type Permission = { resource: string; action: string }
const getUserPermissions = (userId: string) => {
const roles = getUserRoles(userId)
const permissions: Permission[] = roles.flatMap(role => getRolePermissions(role))
// union checks the second list against what it has kept so far,
// so the list to deduplicate goes second
return union<Permission>(
[],
permissions,
(a, b) => a.resource === b.resource && a.action === b.action
)
}