DAO → Sink Architecture: The FOAM Pipeline

Key Concept: Just like Unix pipes chain commands to process data, FOAM chains DAOs and streams results to a Sink. Data flows from left to right through decorators, then into the output Sink.

Unix Pipe Analogy

cat users.txt Read file (data source) | grep "active" Filter rows | sort Order results | head -n 20 Limit results > output.txt Destination (Sink) Data flows through pipeline →

FOAM DAO → Sink Pipeline

userDAO Storage layer (data source) . .where(EQ(...)) Filter predicate . .orderBy(...) Sort comparator . .limit(20) Limit count → .select(sink) Result processor (Sink) Data streams through decorated DAOs →

Code Examples

// Unix-style thinking cat users.txt | grep "active" | sort | head -n 20 > output.txt // FOAM equivalent - fluent DAO chaining userDAO .where(this.EQ(User.STATUS, 'active')) .orderBy(User.NAME) .limit(20) .select(ArraySink.create()) // ← The "output" (Sink) .then((sink) => { console.log(sink.array); // Access collected results });

Sink Delegation (Multi-Stage Processing)

userDAO.where(...) Decorated DAO (query spec) .select() PredicatedSink Filter in Sink delegates to → Map Transform results delegates to → ArraySink Collect final results into array DAO Composition (Decorators stack) Sink Delegation (Processing chain) Complete data flow: Source → Processing → Output
// Sink delegation example var sink = PredicatedSink.create({ predicate: someCondition, // Filter in the sink delegate: Map.create({ arg1: User.NAME, // Transform (extract name) delegate: ArraySink.create() // Final output }) }); userDAO.select(sink); // Start the flow
Key Difference:
• DAO Composition (left side): Query specification - describes WHAT data to retrieve and HOW to filter/sort it
• Sink Delegation (right side): Result processing - describes HOW to process the results once retrieved

Think of it as: where/limit/orderBy build the query, select(sink) executes it and streams to the output processor.