1+ <!DOCTYPE html>
2+ < html lang ="en ">
3+ < head >
4+ < meta charset ="UTF-8 ">
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6+ < title > DAO to Sink Flow</ title >
7+ < style >
8+ body {
9+ font-family : 'Segoe UI' , Tahoma, Geneva, Verdana, sans-serif;
10+ max-width : 1200px ;
11+ margin : 40px auto;
12+ padding : 20px ;
13+ background : # f5f5f5 ;
14+ }
15+
16+ .container {
17+ background : white;
18+ border-radius : 12px ;
19+ padding : 30px ;
20+ box-shadow : 0 2px 8px rgba (0 , 0 , 0 , 0.1 );
21+ margin-bottom : 30px ;
22+ }
23+
24+ h1 {
25+ color : # 2c3e50 ;
26+ margin-top : 0 ;
27+ border-bottom : 3px solid # 3498db ;
28+ padding-bottom : 10px ;
29+ }
30+
31+ h2 {
32+ color : # 34495e ;
33+ margin-top : 30px ;
34+ font-size : 1.3em ;
35+ }
36+
37+ .diagram {
38+ margin : 30px 0 ;
39+ overflow-x : auto;
40+ }
41+
42+ svg {
43+ display : block;
44+ margin : 0 auto;
45+ }
46+
47+ .box {
48+ cursor : pointer;
49+ transition : all 0.3s ;
50+ }
51+
52+ .box : hover rect {
53+ filter : brightness (0.9 );
54+ }
55+
56+ .arrow {
57+ fill : none;
58+ stroke : # 34495e ;
59+ stroke-width : 2 ;
60+ marker-end : url (# arrowhead);
61+ }
62+
63+ .flow-arrow {
64+ fill : none;
65+ stroke : # 3498db ;
66+ stroke-width : 3 ;
67+ marker-end : url (# arrowhead- blue);
68+ }
69+
70+ .label {
71+ font-family : 'Courier New' , monospace;
72+ font-size : 13px ;
73+ }
74+
75+ .title-text {
76+ font-weight : bold;
77+ font-size : 14px ;
78+ }
79+
80+ .description {
81+ font-size : 12px ;
82+ fill : # 7f8c8d ;
83+ }
84+
85+ .pipe-symbol {
86+ font-family : 'Courier New' , monospace;
87+ font-size : 24px ;
88+ font-weight : bold;
89+ fill : # e74c3c ;
90+ }
91+
92+ .code-example {
93+ background : # 2c3e50 ;
94+ color : # ecf0f1 ;
95+ padding : 20px ;
96+ border-radius : 8px ;
97+ font-family : 'Courier New' , monospace;
98+ font-size : 14px ;
99+ line-height : 1.8 ;
100+ overflow-x : auto;
101+ margin : 20px 0 ;
102+ }
103+
104+ .code-comment {
105+ color : # 95a5a6 ;
106+ }
107+
108+ .code-keyword {
109+ color : # e74c3c ;
110+ }
111+
112+ .code-method {
113+ color : # 3498db ;
114+ }
115+
116+ .code-string {
117+ color : # 2ecc71 ;
118+ }
119+
120+ .highlight {
121+ animation : pulse 2s infinite;
122+ }
123+
124+ @keyframes pulse {
125+ 0% , 100% { opacity : 1 ; }
126+ 50% { opacity : 0.6 ; }
127+ }
128+
129+ .note {
130+ background : # e8f4f8 ;
131+ border-left : 4px solid # 3498db ;
132+ padding : 15px ;
133+ margin : 20px 0 ;
134+ border-radius : 4px ;
135+ }
136+
137+ .note strong {
138+ color : # 2980b9 ;
139+ }
140+ </ style >
141+ </ head >
142+ < body >
143+ < div class ="container ">
144+ < h1 > DAO → Sink Architecture: The FOAM Pipeline</ h1 >
145+
146+ < div class ="note ">
147+ < strong > Key Concept:</ strong > 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.
148+ </ div >
149+
150+ < h2 > Unix Pipe Analogy</ h2 >
151+ < div class ="diagram ">
152+ < svg width ="1100 " height ="180 " xmlns ="http://www.w3.org/2000/svg ">
153+ < defs >
154+ < marker id ="arrowhead " markerWidth ="10 " markerHeight ="10 " refX ="9 " refY ="3 " orient ="auto ">
155+ < polygon points ="0 0, 10 3, 0 6 " fill ="#34495e " />
156+ </ marker >
157+ < marker id ="arrowhead-blue " markerWidth ="10 " markerHeight ="10 " refX ="9 " refY ="3 " orient ="auto ">
158+ < polygon points ="0 0, 10 3, 0 6 " fill ="#3498db " />
159+ </ marker >
160+ </ defs >
161+
162+ <!-- Unix command boxes -->
163+ < g class ="box ">
164+ < rect x ="20 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
165+ < text x ="90 " y ="65 " text-anchor ="middle " class ="title-text "> cat users.txt</ text >
166+ < text x ="90 " y ="85 " text-anchor ="middle " class ="description "> Read file</ text >
167+ < text x ="90 " y ="100 " text-anchor ="middle " class ="description "> (data source)</ text >
168+ </ g >
169+
170+ < text x ="175 " y ="80 " class ="pipe-symbol "> |</ text >
171+
172+ < g class ="box ">
173+ < rect x ="200 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
174+ < text x ="270 " y ="65 " text-anchor ="middle " class ="title-text "> grep "active"</ text >
175+ < text x ="270 " y ="85 " text-anchor ="middle " class ="description "> Filter rows</ text >
176+ </ g >
177+
178+ < text x ="355 " y ="80 " class ="pipe-symbol "> |</ text >
179+
180+ < g class ="box ">
181+ < rect x ="380 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
182+ < text x ="450 " y ="65 " text-anchor ="middle " class ="title-text "> sort</ text >
183+ < text x ="450 " y ="85 " text-anchor ="middle " class ="description "> Order results</ text >
184+ </ g >
185+
186+ < text x ="535 " y ="80 " class ="pipe-symbol "> |</ text >
187+
188+ < g class ="box ">
189+ < rect x ="560 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
190+ < text x ="630 " y ="65 " text-anchor ="middle " class ="title-text "> head -n 20</ text >
191+ < text x ="630 " y ="85 " text-anchor ="middle " class ="description "> Limit results</ text >
192+ </ g >
193+
194+ < text x ="715 " y ="80 " class ="pipe-symbol "> > </ text >
195+
196+ < g class ="box ">
197+ < rect x ="740 " y ="40 " width ="140 " height ="70 " fill ="#2ecc71 " stroke ="#27ae60 " stroke-width ="2 " rx ="5 "/>
198+ < text x ="810 " y ="65 " text-anchor ="middle " class ="title-text " fill ="white "> output.txt</ text >
199+ < text x ="810 " y ="85 " text-anchor ="middle " class ="description " fill ="white "> Destination</ text >
200+ < text x ="810 " y ="100 " text-anchor ="middle " class ="description " fill ="white "> (Sink)</ text >
201+ </ g >
202+
203+ <!-- Flow arrow -->
204+ < path d ="M 90 130 L 270 130 L 450 130 L 630 130 L 810 130 "
205+ class ="flow-arrow " stroke-dasharray ="5,5 ">
206+ < animate attributeName ="stroke-dashoffset " from ="10 " to ="0 " dur ="1s " repeatCount ="indefinite "/>
207+ </ path >
208+ < text x ="450 " y ="155 " text-anchor ="middle " fill ="#3498db " font-weight ="bold "> Data flows through pipeline →</ text >
209+ </ svg >
210+ </ div >
211+
212+ < h2 > FOAM DAO → Sink Pipeline</ h2 >
213+ < div class ="diagram ">
214+ < svg width ="1100 " height ="180 " xmlns ="http://www.w3.org/2000/svg ">
215+ <!-- FOAM DAO boxes -->
216+ < g class ="box ">
217+ < rect x ="20 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
218+ < text x ="90 " y ="65 " text-anchor ="middle " class ="title-text "> userDAO</ text >
219+ < text x ="90 " y ="85 " text-anchor ="middle " class ="description "> Storage layer</ text >
220+ < text x ="90 " y ="100 " text-anchor ="middle " class ="description "> (data source)</ text >
221+ </ g >
222+
223+ < text x ="175 " y ="80 " class ="pipe-symbol "> .</ text >
224+
225+ < g class ="box ">
226+ < rect x ="200 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
227+ < text x ="270 " y ="65 " text-anchor ="middle " class ="title-text "> .where(EQ(...))</ text >
228+ < text x ="270 " y ="85 " text-anchor ="middle " class ="description "> Filter predicate</ text >
229+ </ g >
230+
231+ < text x ="355 " y ="80 " class ="pipe-symbol "> .</ text >
232+
233+ < g class ="box ">
234+ < rect x ="380 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
235+ < text x ="450 " y ="65 " text-anchor ="middle " class ="title-text "> .orderBy(...)</ text >
236+ < text x ="450 " y ="85 " text-anchor ="middle " class ="description "> Sort comparator</ text >
237+ </ g >
238+
239+ < text x ="535 " y ="80 " class ="pipe-symbol "> .</ text >
240+
241+ < g class ="box ">
242+ < rect x ="560 " y ="40 " width ="140 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
243+ < text x ="630 " y ="65 " text-anchor ="middle " class ="title-text "> .limit(20)</ text >
244+ < text x ="630 " y ="85 " text-anchor ="middle " class ="description "> Limit count</ text >
245+ </ g >
246+
247+ < text x ="715 " y ="80 " class ="pipe-symbol "> →</ text >
248+
249+ < g class ="box ">
250+ < rect x ="740 " y ="40 " width ="140 " height ="70 " fill ="#2ecc71 " stroke ="#27ae60 " stroke-width ="2 " rx ="5 "/>
251+ < text x ="810 " y ="65 " text-anchor ="middle " class ="title-text " fill ="white "> .select(sink)</ text >
252+ < text x ="810 " y ="85 " text-anchor ="middle " class ="description " fill ="white "> Result processor</ text >
253+ < text x ="810 " y ="100 " text-anchor ="middle " class ="description " fill ="white "> (Sink)</ text >
254+ </ g >
255+
256+ <!-- Flow arrow -->
257+ < path d ="M 90 130 L 270 130 L 450 130 L 630 130 L 810 130 "
258+ class ="flow-arrow " stroke-dasharray ="5,5 ">
259+ < animate attributeName ="stroke-dashoffset " from ="10 " to ="0 " dur ="1s " repeatCount ="indefinite "/>
260+ </ path >
261+ < text x ="450 " y ="155 " text-anchor ="middle " fill ="#3498db " font-weight ="bold "> Data streams through decorated DAOs →</ text >
262+ </ svg >
263+ </ div >
264+
265+ < h2 > Code Examples</ h2 >
266+
267+ < div class ="code-example ">
268+ < span class ="code-comment "> // Unix-style thinking</ span >
269+ cat users.txt | grep "active" | sort | head -n 20 > output.txt
270+
271+ < span class ="code-comment "> // FOAM equivalent - fluent DAO chaining</ span >
272+ userDAO
273+ .< span class ="code-method "> where</ span > (< span class ="code-keyword "> this</ span > .EQ(User.STATUS, < span class ="code-string "> 'active'</ span > ))
274+ .< span class ="code-method "> orderBy</ span > (User.NAME)
275+ .< span class ="code-method "> limit</ span > (20)
276+ .< span class ="code-method "> select</ span > (ArraySink.create()) < span class ="code-comment "> // ← The "output" (Sink)</ span >
277+ .< span class ="code-method "> then</ span > ((sink) => {
278+ console.log(sink.array); < span class ="code-comment "> // Access collected results</ span >
279+ });
280+ </ div >
281+
282+ < h2 > Sink Delegation (Multi-Stage Processing)</ h2 >
283+ < div class ="diagram ">
284+ < svg width ="1100 " height ="220 " xmlns ="http://www.w3.org/2000/svg ">
285+ <!-- Decorated DAO chain -->
286+ < g class ="box ">
287+ < rect x ="20 " y ="40 " width ="180 " height ="70 " fill ="#ecf0f1 " stroke ="#34495e " stroke-width ="2 " rx ="5 "/>
288+ < text x ="110 " y ="65 " text-anchor ="middle " class ="title-text "> userDAO.where(...)</ text >
289+ < text x ="110 " y ="85 " text-anchor ="middle " class ="description "> Decorated DAO</ text >
290+ < text x ="110 " y ="100 " text-anchor ="middle " class ="description "> (query spec)</ text >
291+ </ g >
292+
293+ < path d ="M 200 75 L 240 75 " class ="flow-arrow "/>
294+ < text x ="220 " y ="65 " text-anchor ="middle " fill ="#3498db " font-size ="12px "> .select()</ text >
295+
296+ <!-- Sink chain with delegation -->
297+ < g class ="box ">
298+ < rect x ="240 " y ="30 " width ="180 " height ="90 " fill ="#e8f4f8 " stroke ="#3498db " stroke-width ="2 " rx ="5 "/>
299+ < text x ="330 " y ="55 " text-anchor ="middle " class ="title-text "> PredicatedSink</ text >
300+ < text x ="330 " y ="75 " text-anchor ="middle " class ="description "> Filter in Sink</ text >
301+ < text x ="330 " y ="105 " text-anchor ="middle " class ="description " font-style ="italic "> delegates to →</ text >
302+ </ g >
303+
304+ < path d ="M 420 75 L 460 75 " class ="flow-arrow "/>
305+
306+ < g class ="box ">
307+ < rect x ="460 " y ="30 " width ="180 " height ="90 " fill ="#e8f4f8 " stroke ="#3498db " stroke-width ="2 " rx ="5 "/>
308+ < text x ="550 " y ="55 " text-anchor ="middle " class ="title-text "> Map</ text >
309+ < text x ="550 " y ="75 " text-anchor ="middle " class ="description "> Transform results</ text >
310+ < text x ="550 " y ="105 " text-anchor ="middle " class ="description " font-style ="italic "> delegates to →</ text >
311+ </ g >
312+
313+ < path d ="M 640 75 L 680 75 " class ="flow-arrow "/>
314+
315+ < g class ="box ">
316+ < rect x ="680 " y ="30 " width ="180 " height ="90 " fill ="#2ecc71 " stroke ="#27ae60 " stroke-width ="2 " rx ="5 "/>
317+ < text x ="770 " y ="55 " text-anchor ="middle " class ="title-text " fill ="white "> ArraySink</ text >
318+ < text x ="770 " y ="75 " text-anchor ="middle " class ="description " fill ="white "> Collect final</ text >
319+ < text x ="770 " y ="95 " text-anchor ="middle " class ="description " fill ="white "> results into</ text >
320+ < text x ="770 " y ="110 " text-anchor ="middle " class ="description " fill ="white "> array</ text >
321+ </ g >
322+
323+ <!-- Labels -->
324+ < text x ="110 " y ="150 " text-anchor ="middle " fill ="#34495e " font-weight ="bold "> DAO Composition</ text >
325+ < text x ="110 " y ="170 " text-anchor ="middle " fill ="#7f8c8d " font-size ="12px "> (Decorators stack)</ text >
326+
327+ < text x ="550 " y ="150 " text-anchor ="middle " fill ="#34495e " font-weight ="bold "> Sink Delegation</ text >
328+ < text x ="550 " y ="170 " text-anchor ="middle " fill ="#7f8c8d " font-size ="12px "> (Processing chain)</ text >
329+
330+ <!-- Overall flow -->
331+ < path d ="M 110 190 L 770 190 " class ="flow-arrow " stroke-width ="2 "/>
332+ < text x ="440 " y ="210 " text-anchor ="middle " fill ="#3498db " font-weight ="bold "> Complete data flow: Source → Processing → Output</ text >
333+ </ svg >
334+ </ div >
335+
336+ < div class ="code-example ">
337+ < span class ="code-comment "> // Sink delegation example</ span >
338+ < span class ="code-keyword "> var</ span > sink = PredicatedSink.create({
339+ predicate: someCondition, < span class ="code-comment "> // Filter in the sink</ span >
340+ < span class ="code-keyword "> delegate</ span > : Map.create({
341+ arg1: User.NAME, < span class ="code-comment "> // Transform (extract name)</ span >
342+ < span class ="code-keyword "> delegate</ span > : ArraySink.create() < span class ="code-comment "> // Final output</ span >
343+ })
344+ });
345+
346+ userDAO.< span class ="code-method "> select</ span > (sink); < span class ="code-comment "> // Start the flow</ span >
347+ </ div >
348+
349+ < div class ="note ">
350+ < strong > Key Difference:</ strong > < br >
351+ • < strong > DAO Composition</ strong > (left side): Query specification - describes WHAT data to retrieve and HOW to filter/sort it< br >
352+ • < strong > Sink Delegation</ strong > (right side): Result processing - describes HOW to process the results once retrieved< br > < br >
353+ Think of it as: < code > where/limit/orderBy</ code > build the query, < code > select(sink)</ code > executes it and streams to the output processor.
354+ </ div >
355+ </ div >
356+ </ body >
357+ </ html >
0 commit comments