-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheventdenormalizer.html
84 lines (64 loc) · 81.4 KB
/
eventdenormalizer.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="keywords" content="i18n, internationalization, translation, javascript, nodejs, js"><title>cqrs - eventdenormalizer</title><link href="../public/css/index.css" rel="stylesheet"><script src="../public/js/jquery-1.7.2.min.js"></script><script src="../public/js/bootstrap-2.0.2.min.js"></script><!-- HTML5 shim, for IE6-8 support of HTML5 elements--><!--[if lt IE 9]><script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script><![endif]--><!--[if lt IE 8]><link href="../public/css/font-awesome-ie7-2.0.css" rel="stylesheet" type="text/css"><![endif]--></head><body><header class="header"><div class="header-inner"><div class="navbar navbar-fixed-top"><div class="navbar-inner"><div class="container"><!--.btn-navbar is used as the toggle for collapsed navbar content--><a data-toggle="collapse" data-target=".nav-collapse" class="btn btn-navbar"><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></a><!-- Be sure to leave the brand out there if you want it shown--><a href="../" class="brand">cqrs</a><!-- Everything you want hidden at 940px or less, place within here--><div class="nav-collapse"><ul class="nav"><li><a href="../index.html">Home</a></li><li><a href="../pages/domain.html">domain</a></li><li><a href="../pages/viewmodel.html">viewmodel</a></li><li><a href="../pages/eventdenormalizer.html">eventdenormalizer</a></li><li><a href="http://adrai.github.io/node-eventstore/">eventstore</a></li><li><a href="http://jamuhl.github.com/backbone.CQRS/">backbone.CQRS</a></li><li><a href="https://github.com/KABA-CCEAC/angular.CQRS/">angular.CQRS</a></li><li><a href="../pages/eventedcommand.html">evented-command</a></li><li><a href="../pages/saga.html">saga</a></li></ul></div></div></div></div></div></header><div class="main"><div class="main-inner"><div class="container"><div class="content-container"> <div class="documentation"><div class="row-fluid"><div class="span8"><div class="hero-unit"><h2>cqrs-eventdenormalizer</h2><p>cqrs-eventdenormalizer is a node.js module that implements the cqrs pattern. It can be very useful as eventdenormalizer component if you work with (d)ddd, cqrs, domain, host, etc.</p></div></div><div class="span4 downloads"><p>node.js:</p><pre><code><span class="pln">npm install cqrs</span><span class="pun">-</span><span class="pln">eventdenormalizer</span></code></pre><p>Build status:<a href="http://travis-ci.org/adrai/node-cqrs-eventdenormalizer"><img src="https://secure.travis-ci.org/adrai/node-cqrs-eventdenormalizer.png"></a></p><p>Release:<a href="https://npmjs.org/package/cqrs-eventdenormalizer"><img src="https://img.shields.io/npm/v/cqrs-eventdenormalizer.svg"></a></p><div style="margin-top: 25px;" class="alert alert-info feature-description"><a href="https://github.com/adrai/node-cqrs-eventdenormalizer"><i class="icon-github"></i> fork me on github</a><br><a href="https://github.com/adrai/node-cqrs-eventdenormalizer/issues"><i class="icon-github"></i> issues</a><br><a href="https://github.com/adrai/node-cqrs-eventdenormalizer/blob/master/releasenotes.md"><i class="icon-github"></i> release notes</a></div></div></div><div class="row-fluid"><div class="span12"><h2>Usage</h2><div class="row-fluid"><div class="span4"><h4 class="feature-title">Configure</h4></div><div class="span8"><div class="feature"><pre><code><span class="kwd">var</span><span class="pln"> denormalizer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'cqrs-eventdenormalizer'</span><span class="pun">)({</span><span class="pln"><br /> </span><span class="com">// the path to the "working directory"</span><span class="pln"><br /> </span><span class="com">// can be structured like</span><span class="pln"><br /> </span><span class="com">// [set 1](https://github.com/adrai/node-cqrs-eventdenormalizer/tree/master/test/integration/fixture/set1) or</span><span class="pln"><br /> </span><span class="com">// [set 2](https://github.com/adrai/node-cqrs-eventdenormalizer/tree/master/test/integration/fixture/set2)</span><span class="pln"><br /> denormalizerPath</span><span class="pun">:</span><span class="pln"> </span><span class="str">'/path/to/my/files'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'commandRejected'</span><span class="pln"><br /> </span><span class="com">// will be used to catch AggregateDestroyedError from cqrs-domain</span><span class="pln"><br /> commandRejectedEventName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'rejectedCommand'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 800</span><span class="pln"><br /> </span><span class="com">// if using in scaled systems, this module tries to catch the concurrency issues and</span><span class="pln"><br /> </span><span class="com">// retries to handle the event after a timeout between 0 and the defined value</span><span class="pln"><br /> retryOnConcurrencyTimeout</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is in-memory</span><span class="pln"><br /> </span><span class="com">// currently supports: mongodb, redis, tingodb, couchdb, azuretable and inmemory</span><span class="pln"><br /> </span><span class="com">// hint: [viewmodel](https://github.com/adrai/node-viewmodel#connecting-to-any-repository-mongodb-in-the-example--modewrite)</span><span class="pln"><br /> </span><span class="com">// hint settings like: [eventstore](https://github.com/adrai/node-eventstore#provide-implementation-for-storage)</span><span class="pln"><br /> repository</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'mongodb'</span><span class="pun">,</span><span class="pln"><br /> host</span><span class="pun">:</span><span class="pln"> </span><span class="str">'localhost'</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> port</span><span class="pun">:</span><span class="pln"> </span><span class="lit">27017</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> dbName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'readmodel'</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> timeout</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10000</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> </span><span class="com">// authSource: 'authedicationDatabase', // optional</span><span class="pln"><br /> </span><span class="com">// username: 'technicalDbUser', // optional</span><span class="pln"><br /> </span><span class="com">// password: 'secret' // optional</span><span class="pln"><br /> </span><span class="com">// url: 'mongodb://user:pass@host:port/db?opts // optional</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is in-memory</span><span class="pln"><br /> </span><span class="com">// currently supports: mongodb, redis, tingodb and inmemory</span><span class="pln"><br /> </span><span class="com">// hint settings like: [eventstore](https://github.com/adrai/node-eventstore#provide-implementation-for-storage)</span><span class="pln"><br /> revisionGuard</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> queueTimeout</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional, timeout for non-handled events in the internal in-memory queue</span><span class="pln"><br /> queueTimeoutMaxLoops</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional, maximal loop count for non-handled event in the internal in-memory queue</span><span class="pln"><br /> startRevisionNumber</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional, if defined the denormaizer waits for an event with that revision to be used as first event</span><span class="pln"><br /> <br /> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'redis'</span><span class="pun">,</span><span class="pln"><br /> host</span><span class="pun">:</span><span class="pln"> </span><span class="str">'localhost'</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> port</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6379</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> db</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> prefix</span><span class="pun">:</span><span class="pln"> </span><span class="str">'readmodel_revision'</span><span class="pun">,</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> timeout</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10000</span><span class="pln"> </span><span class="com">// optional</span><span class="pln"><br /> </span><span class="com">// password: 'secret' // optional</span><span class="pln"><br /> </span><span class="pun">}</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Catch connect ad disconnect events</h4></div><div class="span8"><div class="feature"><pre><code><span class="com">// repository</span><span class="pln"><br />denormalizer</span><span class="pun">.</span><span class="pln">repository</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">'connect'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'repository connected'</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /> <br />denormalizer</span><span class="pun">.</span><span class="pln">repository</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">'disconnect'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'repository disconnected'</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /> <br /></span><span class="com">// revisionGuardStore</span><span class="pln"><br />denormalizer</span><span class="pun">.</span><span class="pln">revisionGuardStore</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">'connect'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'revisionGuardStore connected'</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /> <br />denormalizer</span><span class="pun">.</span><span class="pln">revisionGuardStore</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">'disconnect'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'revisionGuardStore disconnected'</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /> <br /> <br /></span><span class="com">// anything (repository or revisionGuardStore)</span><span class="pln"><br />denormalizer</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">'connect'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'something connected'</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /> <br />denormalizer</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">'disconnect'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'something disconnected'</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre><div class="alert alert-info feature-description"><h6>Important hint:</h6><p>For example in a cloud environment the disconnect event could be used to kill the process.</p></div></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Define the event structure</h4><p>The values describes the path to that property in the event message.</p></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">defineEvent</span><span class="pun">({</span><span class="pln"><br /> </span><span class="com">// optional, default is 'correlationId'</span><span class="pln"><br /> </span><span class="com">// will use the command id as correlationId, so you can match it in the sender</span><span class="pln"><br /> </span><span class="com">// will be used to copy the correlationId to the notification</span><span class="pln"><br /> correlationId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'correlationId'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'id'</span><span class="pln"><br /> id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'name'</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'name'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'aggregate.id'</span><span class="pln"><br /> aggregateId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'aggregate.id'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="str">'context.name'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'aggregate.name'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'payload'</span><span class="pln"><br /> payload</span><span class="pun">:</span><span class="pln"> </span><span class="str">'payload'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'revision'</span><span class="pln"><br /> </span><span class="com">// will represent the aggregate revision, can be used in next command</span><span class="pln"><br /> revision</span><span class="pun">:</span><span class="pln"> </span><span class="str">'revision'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> version</span><span class="pun">:</span><span class="pln"> </span><span class="str">'version'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if defined the values of the command will be copied to the event (can be used to transport information like userId, etc..)</span><span class="pln"><br /> meta</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta'</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Define the notification structure</h4><p>The values describes the path to that property in the notification message.</p></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">defineNotification</span><span class="pun">({</span><span class="pln"><br /> </span><span class="com">// optional, default is 'correlationId'</span><span class="pln"><br /> </span><span class="com">// will use the command id as correlationId, so you can match it in the sender</span><span class="pln"><br /> </span><span class="com">// will be used to copy the correlationId from the event</span><span class="pln"><br /> correlationId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'correlationId'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'id'</span><span class="pln"><br /> id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'name'</span><span class="pln"><br /> action</span><span class="pun">:</span><span class="pln"> </span><span class="str">'name'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'collection'</span><span class="pln"><br /> collection</span><span class="pun">:</span><span class="pln"> </span><span class="str">'collection'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 'payload'</span><span class="pln"><br /> payload</span><span class="pun">:</span><span class="pln"> </span><span class="str">'payload'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, will be copied from event</span><span class="pln"><br /> aggregateId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta.aggregate.id'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, will be copied from event</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta.context.name'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, will be copied from event</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta.aggregate.name'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, will be copied from event</span><span class="pln"><br /> </span><span class="com">// will represent the aggregate revision, can be used in next command</span><span class="pln"><br /> revision</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta.aggregate.revision'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, will be copied from event</span><span class="pln"><br /> eventId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta.event.id'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, will be copied from event</span><span class="pln"><br /> </span><span class="kwd">event</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta.event.name'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if defined the values of the event will be copied to the notification (can be used to transport information like userId, etc..)</span><span class="pln"><br /> meta</span><span class="pun">:</span><span class="pln"> </span><span class="str">'meta'</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Define the id generator function [optional]</h4><p>you can define a synchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">idGenerator</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="kwd">var</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'node-uuid'</span><span class="pun">).</span><span class="pln">v4</span><span class="pun">().</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"><br /> </span><span class="kwd">return</span><span class="pln"> id</span><span class="pun">;</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><p>or you can define an asynchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">idGenerator</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> setTimeout</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="kwd">var</span><span class="pln"> id </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'node-uuid'</span><span class="pun">).</span><span class="pln">v4</span><span class="pun">().</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"><br /> callback</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> id</span><span class="pun">);</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Wire up events [optional]</h4><p>you can define a synchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="com">// pass events to bus</span><span class="pln"><br />domain</span><span class="pun">.</span><span class="pln">onEvent</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">evt</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> bus</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">'event'</span><span class="pun">,</span><span class="pln"> evt</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><p>or you can define an asynchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="com">// pass events to bus</span><span class="pln"><br />domain</span><span class="pun">.</span><span class="pln">onEvent</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">evt</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> bus</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">'event'</span><span class="pun">,</span><span class="pln"> evt</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> ack </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> callback</span><span class="pun">();</span><span class="pln"><br /> </span><span class="pun">});</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Wire up notifications [optional]</h4><p>you can define a synchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="com">// pass notifications to bus</span><span class="pln"><br />domain</span><span class="pun">.</span><span class="pln">onNotification</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">noti</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> bus</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">'notification'</span><span class="pun">,</span><span class="pln"> noti</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><p>or you can define an asynchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="com">// pass notifications to bus</span><span class="pln"><br />domain</span><span class="pun">.</span><span class="pln">onNotification</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">noti</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> bus</span><span class="pun">.</span><span class="pln">emit</span><span class="pun">(</span><span class="str">'notification'</span><span class="pun">,</span><span class="pln"> noti</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> ack </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> callback</span><span class="pun">();</span><span class="pln"><br /> </span><span class="pun">});</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Wire up event missing messages [optional]</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">domain</span><span class="pun">.</span><span class="pln">onEventMissing</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">info</span><span class="pun">,</span><span class="pln"> evt</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">info</span><span class="pun">);</span><span class="pln"><br /> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">evt</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Define default event extension [optional]</h4><p>you can define a synchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">defaultEventExtension</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">evt</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> evt</span><span class="pun">.</span><span class="pln">receiver </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">evt</span><span class="pun">.</span><span class="pln">meta</span><span class="pun">.</span><span class="pln">userId</span><span class="pun">];</span><span class="pln"><br /> </span><span class="kwd">return</span><span class="pln"> evt</span><span class="pun">;</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><p>or you can define an asynchronous function</p></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">defaultEventExtension</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">evt</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> evt</span><span class="pun">.</span><span class="pln">receiver </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">evt</span><span class="pun">.</span><span class="pln">meta</span><span class="pun">.</span><span class="pln">userId</span><span class="pun">];</span><span class="pln"><br /> callback</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> evt</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Initialization</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">init</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">,</span><span class="pln"> warnings</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="com">// this callback is called when all is ready...</span><span class="pln"><br /> </span><span class="com">// warnings: if no warnings warnings is null, else it's an array containing errors during require of files</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /></span><span class="pun">|</span><span class="pln"><br /></span><span class="com">// or</span><span class="pln"><br /></span><span class="pun">|</span><span class="pln"><br />denormalizer</span><span class="pun">.</span><span class="pln">init</span><span class="pun">();</span><span class="pln"> </span><span class="com">// callback is optional</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">Handling an event</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">handle</span><span class="pun">({</span><span class="pln"><br /> id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'b80ade36-dd05-4340-8a8b-846eea6e286f'</span><span class="pun">,</span><span class="pln"><br /> correlationId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'c80ada33-dd05-4340-8a8b-846eea6e151d'</span><span class="pun">,</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'enteredNewPerson'</span><span class="pun">,</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'3b4d44b0-34fb-4ceb-b212-68fe7a7c2f70'</span><span class="pun">,</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'person'</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'hr'</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"><br /> payload</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> firstname</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Jack'</span><span class="pun">,</span><span class="pln"><br /> lastname</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Huston'</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"><br /> revision</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"><br /> version</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"><br /> meta</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> userId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ccd65819-4da4-4df9-9f24-5b10bf89ef89'</span><span class="pln"><br /> </span><span class="pun">}</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"> </span><span class="com">// callback is optional</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><p>or</p></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">handle</span><span class="pun">({</span><span class="pln"><br /> id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'b80ade36-dd05-4340-8a8b-846eea6e286f'</span><span class="pun">,</span><span class="pln"><br /> correlationId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'c80ada33-dd05-4340-8a8b-846eea6e151d'</span><span class="pun">,</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'enteredNewPerson'</span><span class="pun">,</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'3b4d44b0-34fb-4ceb-b212-68fe7a7c2f70'</span><span class="pun">,</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'person'</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'hr'</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"><br /> payload</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> firstname</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Jack'</span><span class="pun">,</span><span class="pln"><br /> lastname</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Huston'</span><span class="pln"><br /> </span><span class="pun">},</span><span class="pln"><br /> revision</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"><br /> version</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"><br /> meta</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> userId</span><span class="pun">:</span><span class="pln"> </span><span class="str">'ccd65819-4da4-4df9-9f24-5b10bf89ef89'</span><span class="pln"><br /> </span><span class="pun">}</span><span class="pln"><br /></span><span class="pun">},</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">errs</span><span class="pun">,</span><span class="pln"> evt</span><span class="pun">,</span><span class="pln"> notifications</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="com">// this callback is called when event is handled successfully or unsuccessfully</span><span class="pln"><br /> </span><span class="com">// errs can be of type:</span><span class="pln"><br /> </span><span class="com">// - null</span><span class="pln"><br /> </span><span class="com">// - Array of Errors</span><span class="pln"><br /> </span><span class="com">//</span><span class="pln"><br /> </span><span class="com">// evt: same as passed in 'onEvent' function</span><span class="pln"><br /> </span><span class="com">//</span><span class="pln"><br /> </span><span class="com">// notifications: Array of viewmodel changes</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div></div></div><div class="row-fluid"><div class="span12"><h2>Request denormalizer information</h2><div class="row-fluid"><div class="span4"><h4 class="feature-title">After the initialization you can request the denormalizer information:</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">denorm</span><span class="pun">.</span><span class="pln">init</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> denorm</span><span class="pun">.</span><span class="pln">getInfo</span><span class="pun">();</span><span class="pln"><br /> </span><span class="com">// ==></span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "collections": [</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "person",</span><span class="pln"><br /> </span><span class="com">// "viewBuilders": [</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "enteredNewPerson",</span><span class="pln"><br /> </span><span class="com">// "aggregate": "person",</span><span class="pln"><br /> </span><span class="com">// "context": "hr",</span><span class="pln"><br /> </span><span class="com">// "version": 2,</span><span class="pln"><br /> </span><span class="com">// "priority": 223</span><span class="pln"><br /> </span><span class="com">// },</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "registeredEMailAddress",</span><span class="pln"><br /> </span><span class="com">// "aggregate": "person",</span><span class="pln"><br /> </span><span class="com">// "context": "hr",</span><span class="pln"><br /> </span><span class="com">// "version": 2,</span><span class="pln"><br /> </span><span class="com">// "priority": 312</span><span class="pln"><br /> </span><span class="com">// }</span><span class="pln"><br /> </span><span class="com">// ],</span><span class="pln"><br /> </span><span class="com">// "eventExtenders": [</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "enteredNewPerson",</span><span class="pln"><br /> </span><span class="com">// "aggregate": "person",</span><span class="pln"><br /> </span><span class="com">// "context": "hr",</span><span class="pln"><br /> </span><span class="com">// "version": 2</span><span class="pln"><br /> </span><span class="com">// }</span><span class="pln"><br /> </span><span class="com">// ],</span><span class="pln"><br /> </span><span class="com">// "preEventExtenders": [</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "enteredNewPerson",</span><span class="pln"><br /> </span><span class="com">// "aggregate": "person",</span><span class="pln"><br /> </span><span class="com">// "context": "hr",</span><span class="pln"><br /> </span><span class="com">// "version": 2</span><span class="pln"><br /> </span><span class="com">// }</span><span class="pln"><br /> </span><span class="com">// ]</span><span class="pln"><br /> </span><span class="com">// },</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "personDetail",</span><span class="pln"><br /> </span><span class="com">// "viewBuilders": [</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "enteredNewPerson",</span><span class="pln"><br /> </span><span class="com">// "aggregate": "person",</span><span class="pln"><br /> </span><span class="com">// "context": "hr",</span><span class="pln"><br /> </span><span class="com">// "version": 2,</span><span class="pln"><br /> </span><span class="com">// "priority": 110</span><span class="pln"><br /> </span><span class="com">// },</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "registeredEMailAddress",</span><span class="pln"><br /> </span><span class="com">// "aggregate": "person",</span><span class="pln"><br /> </span><span class="com">// "context": "hr",</span><span class="pln"><br /> </span><span class="com">// "version": 2,</span><span class="pln"><br /> </span><span class="com">// "priority": Infinity</span><span class="pln"><br /> </span><span class="com">// }</span><span class="pln"><br /> </span><span class="com">// ],</span><span class="pln"><br /> </span><span class="com">// "eventExtenders": [],</span><span class="pln"><br /> </span><span class="com">// "preEventExtenders": []</span><span class="pln"><br /> </span><span class="com">// }</span><span class="pln"><br /> </span><span class="com">// ],</span><span class="pln"><br /> </span><span class="com">// "generalEventExtenders": [</span><span class="pln"><br /> </span><span class="com">// {</span><span class="pln"><br /> </span><span class="com">// "name": "",</span><span class="pln"><br /> </span><span class="com">// "aggregate": null,</span><span class="pln"><br /> </span><span class="com">// "context": null,</span><span class="pln"><br /> </span><span class="com">// "version": -1</span><span class="pln"><br /> </span><span class="com">// }</span><span class="pln"><br /> </span><span class="com">// ],</span><span class="pln"><br /> </span><span class="com">// "generalPreEventExtenders": []</span><span class="pln"><br /> </span><span class="com">// }</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div></div></div><div class="row-fluid"><div class="span12"><h2>Components definition</h2><div class="row-fluid"><div class="span4"><h4 class="feature-title">Collection</h4></div><div class="span8"><div class="feature"><pre><code><span class="kwd">module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'cqrs-eventdenormalizer'</span><span class="pun">).</span><span class="pln">defineCollection</span><span class="pun">({</span><span class="pln"><br /> </span><span class="com">// optional, default is folder name</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'personDetail'</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default ''</span><span class="pln"><br /> defaultPayload</span><span class="pun">:</span><span class="pln"> </span><span class="str">'payload'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// indexes: [ // for mongodb</span><span class="pln"><br /> </span><span class="com">// 'profileId',</span><span class="pln"><br /> </span><span class="com">// // or:</span><span class="pln"><br /> </span><span class="com">// { profileId: 1 },</span><span class="pln"><br /> </span><span class="com">// // or:</span><span class="pln"><br /> </span><span class="com">// { index: {profileId: 1}, options: {} }</span><span class="pln"><br /> </span><span class="com">// ]</span><span class="pln"><br /></span><span class="pun">},</span><span class="pln"><br /> <br /></span><span class="com">// optionally, define some initialization data for new view models...</span><span class="pln"><br /></span><span class="pun">{</span><span class="pln"><br /> emails</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'[email protected]'</span><span class="pun">],</span><span class="pln"><br /> phoneNumbers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[]</span><span class="pln"><br /></span><span class="pun">});</span></code></pre><div class="alert alert-info feature-description"><h6>Important hint:</h6><p>If you need an information from an other collection while denormalizing an event, you can require such a collection and make some lookups.</p><p>for example:</p><pre><code><span class="pln">col</span><span class="pun">.</span><span class="pln">findViewModels</span><span class="pun">({</span><span class="pln"> </span><span class="kwd">my</span><span class="pun">:</span><span class="pln"> </span><span class="str">'value'</span><span class="pln"> </span><span class="pun">},</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">,</span><span class="pln"> vms</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{});</span></code></pre><p>or</p><pre><code><span class="pln">col</span><span class="pun">.</span><span class="pln">loadViewModel</span><span class="pun">(</span><span class="str">'id'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">,</span><span class="pln"> vm</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{});</span></code></pre><p>or</p><pre><code><span class="pln">col</span><span class="pun">.</span><span class="pln">loadViewModelIfExists</span><span class="pun">(</span><span class="str">'id'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">,</span><span class="pln"> vm</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{});</span></code></pre><p>But be careful with this!</p></div></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">ViewBuilder</h4></div><div class="span8"><div class="feature"><pre><code><span class="kwd">module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'cqrs-eventdenormalizer'</span><span class="pun">).</span><span class="pln">defineViewBuilder</span><span class="pun">({</span><span class="pln"><br /> </span><span class="com">// optional, default is file name without extension,</span><span class="pln"><br /> </span><span class="com">// if name is '' it will handle all events that matches</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'enteredNewPerson'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'person'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="str">'hr'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 0</span><span class="pln"><br /> version</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if not defined or not found it will generate a new viewmodel with new id</span><span class="pln"><br /> id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'aggregate.id'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, suppresses auto-creation of new view model if none matching the id can be found, default is true</span><span class="pln"><br /> autoCreate</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if not defined it will pass the whole event...</span><span class="pln"><br /> payload</span><span class="pun">:</span><span class="pln"> </span><span class="str">'payload'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default Infinity, all view-builders will be sorted by this value</span><span class="pln"><br /> priority</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"><br /></span><span class="pun">},</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> vm</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// instead of function you can define</span><span class="pln"><br /> </span><span class="com">// a string with default handling ('create', 'update', 'delete')</span><span class="pln"><br /> </span><span class="com">// or function that expects a callback (i.e. function (data, vm, callback) {})</span><span class="pln"><br /></span><span class="com">// if you have multiple concurrent events that targets the same vm, you can catch it like this:</span><span class="pln"><br /></span><span class="com">// during a replay the denormalization finishes and the retry does not happen</span><span class="pln"><br /></span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">vm</span><span class="pun">.</span><span class="pln">actionOnCommit </span><span class="pun">===</span><span class="pln"> </span><span class="str">'create'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="kwd">retry</span><span class="pun">();</span><span class="pln"><br /> </span><span class="com">// or</span><span class="pln"><br /> </span><span class="com">//return this.retry(100); // retries to denormalize again in 0-100ms</span><span class="pln"><br /> </span><span class="com">// or</span><span class="pln"><br /> </span><span class="com">//return this.retry({ from: 500, to: 8000 }); // retries to denormalize again in 500-8000ms</span><span class="pln"><br /></span><span class="pun">}</span><span class="pln"><br /> vm</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'firstname'</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">firstname</span><span class="pun">);</span><span class="pln"><br /> vm</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'lastname'</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">lastname</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">ViewBuilder for multiple viewmodels in a collection</h4><p>Be careful with the query!</p><p>A lot of viewmodels can slow down the denormalization process!</p></div><div class="span8"><div class="feature"><pre><code><span class="kwd">module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'cqrs-eventdenormalizer'</span><span class="pun">).</span><span class="pln">defineViewBuilder</span><span class="pun">({</span><span class="pln"><br /> </span><span class="com">// optional, default is file name without extension,</span><span class="pln"><br /> </span><span class="com">// if name is '' it will handle all events that matches</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'enteredNewPerson'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'person'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="str">'hr'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 0</span><span class="pln"><br /> version</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if not defined or not found it will generate a new viewmodel with new id</span><span class="pln"><br /> query</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">group</span><span class="pun">:</span><span class="pln"> </span><span class="str">'admins'</span><span class="pln"> </span><span class="pun">},</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if not defined it will pass the whole event...</span><span class="pln"><br /> payload</span><span class="pun">:</span><span class="pln"> </span><span class="str">'payload'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default Infinity, all view-builders will be sorted by this value</span><span class="pln"><br /> priority</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"><br /></span><span class="pun">},</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> vm</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// instead of function you can define</span><span class="pln"><br /> </span><span class="com">// a string with default handling ('create', 'update', 'delete')</span><span class="pln"><br /> </span><span class="com">// or function that expects a callback (i.e. function (data, vm, callback) {})</span><span class="pln"><br /> vm</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'firstname'</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">firstname</span><span class="pun">);</span><span class="pln"><br /> vm</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">'lastname'</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">lastname</span><span class="pun">);</span><span class="pln"><br /> </span><span class="com">//this.remindMe({ that: 'important value' });</span><span class="pln"><br /> </span><span class="com">//this.retry();</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /></span><span class="com">// optional define a function to that returns a query that will be used as query to find the viewmodels (but do not define the query in the options)</span><span class="pln"><br /></span><span class="com">//.useAsQuery(function (evt) {</span><span class="pln"><br /></span><span class="com">// return { my: evt.payload.my };</span><span class="pln"><br /></span><span class="com">//});</span><span class="pln"><br /></span><span class="com">// or async</span><span class="pln"><br /></span><span class="com">//.useAsQuery(function (evt, callback) {</span><span class="pln"><br /></span><span class="com">// callback(null, { my: evt.payload.my });</span><span class="pln"><br /></span><span class="com">//});</span><span class="pln"><br /></span><span class="com">// optional define a function that returns a list of items, for each the viewbuilder will run.</span><span class="pln"><br /></span><span class="com">//.executeForEach(function (evt) {</span><span class="pln"><br /></span><span class="com">// return [{ init: 'value1' }, { init: 'value2' }];</span><span class="pln"><br /></span><span class="com">//});</span><span class="pln"><br /></span><span class="com">// or async</span><span class="pln"><br /></span><span class="com">//.executeForEach(function (evt, callback) {</span><span class="pln"><br /></span><span class="com">// callback(null, [{ init: 'value1' }, { init: 'value2' }]);</span><span class="pln"><br /></span><span class="com">//});</span><span class="pln"><br /></span><span class="com">// </span><span class="pln"><br /></span><span class="com">// optional define a function that checks if an event should be handled</span><span class="pln"><br /></span><span class="com">//.defineShouldHandle(function (evt, vm) {</span><span class="pln"><br /></span><span class="com">// return true;</span><span class="pln"><br /></span><span class="com">//});</span><span class="pln"><br /></span><span class="com">// or</span><span class="pln"><br /></span><span class="com">//.defineShouldHandle(function (evt, vm, callback) {</span><span class="pln"><br /></span><span class="com">// callback(null, true');</span><span class="pln"><br /></span><span class="com">//});</span><span class="pln"><br /></span><span class="com">// </span><span class="pln"><br /></span><span class="com">// optional define a function that checks if an event should be handled</span><span class="pln"><br /></span><span class="com">//.onAfterCommit(function (evt, vm) {</span><span class="pln"><br /></span><span class="com">// //var memories = this.getReminder();</span><span class="pln"><br /></span><span class="com">// //console.log(memories.that); // 'important value'</span><span class="pln"><br /></span><span class="com">// //doSomethingStrange()</span><span class="pln"><br /></span><span class="com">//});</span><span class="pln"><br /></span><span class="com">// or</span><span class="pln"><br /></span><span class="com">//.onAfterCommit(function (evt, vm, callback) {</span><span class="pln"><br /></span><span class="com">// var memories = this.getReminder();</span><span class="pln"><br /></span><span class="com">// //console.log(memories.that); // 'important value'</span><span class="pln"><br /></span><span class="com">// // doSomethingStrange(callback)</span><span class="pln"><br /></span><span class="com">// callback(memories.that === 'important value' ? null : new Error('important value not set'));</span><span class="pln"><br /></span><span class="com">//});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">EventExtender</h4><p>for a collection (in a collection folder)</p></div><div class="span8"><div class="feature"><pre><code>module.exports = require('cqrs-eventdenormalizer').defineEventExtender({
// module.exports = require('cqrs-eventdenormalizer').definePreEventExtender({ // same api as normal EventExtenders but executed before viewBuilder so the extended event can be used
// optional, default is file name without extension,
// if name is '' it will handle all events that matches
name: 'enteredNewPerson',
// optional
aggregate: 'person',
// optional
context: 'hr',
// optional, default is 0
// if set to -1, it will ignore the version
version: 2//,
// optional, if not defined it will pass the whole event...
// payload: 'payload'
}, function (evt, col, callback) {
// col.loadViewModel()... or from somewhere else... (col.findViewModels( /* see https://github.com/adrai/node-viewmodel#find */ ))
evt.extended = true;
callback(null, evt);
});
// or
module.exports = require('cqrs-eventdenormalizer').defineEventExtender({
// optional, default is file name without extension,
// if name is '' it will handle all events that matches
name: 'enteredNewPerson',
// optional
aggregate: 'person',
// optional
context: 'hr',
// optional, default is 0
// if set to -1, it will ignore the version
version: 2,
// if defined it will load the viewmodel
id: 'payload.id'//,
// optional, if not defined it will pass the whole event...
// payload: 'payload'
},<function>(evt, vm) {</function> evt.extended = vm.get('myValue');
return evt;
});
// or
module.exports = require('cqrs-eventdenormalizer').defineEventExtender({
// optional, default is file name without extension,
// if name is '' it will handle all events that matches
name: 'enteredNewPerson',
// optional
aggregate: 'person',
// optional
context: 'hr',
// optional, default is 0
// if set to -1, it will ignore the version
version: 2,
// if defined it will load the viewmodel
id: 'payload.id'//,
// optional, if not defined it will pass the whole event...
// payload: 'payload'
},
function (evt, vm, callback) {
evt.extended = vm.get('myValue');
callback(null, evt);
});</code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">EventExtender</h4><p>not for a collection</p></div><div class="span8"><div class="feature"><pre><code><span class="kwd">module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'cqrs-eventdenormalizer'</span><span class="pun">).</span><span class="pln">defineEventExtender</span><span class="pun">({</span><span class="pln"><br /> </span><span class="com">// optional, default is file name without extension,</span><span class="pln"><br /> </span><span class="com">// if name is '' it will handle all events that matches</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'enteredNewPerson'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'person'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="str">'hr'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 0</span><span class="pln"><br /> </span><span class="com">// if set to -1, it will ignore the version</span><span class="pln"><br /> version</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="com">//,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if not defined it will pass the whole event...</span><span class="pln"><br /> </span><span class="com">// payload: 'payload'</span><span class="pln"><br /></span><span class="pun">},</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">evt</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> evt</span><span class="pun">.</span><span class="pln">extended </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"><br /> </span><span class="kwd">return</span><span class="pln"> evt</span><span class="pun">;</span><span class="pln"><br /></span><span class="pun">});</span><span class="pln"><br /> <br /></span><span class="com">// or</span><span class="pln"><br /> <br /></span><span class="kwd">module</span><span class="pun">.</span><span class="pln">exports </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">'cqrs-eventdenormalizer'</span><span class="pun">).</span><span class="pln">defineEventExtender</span><span class="pun">({</span><span class="pln"><br /> </span><span class="com">// optional, default is file name without extension,</span><span class="pln"><br /> </span><span class="com">// if name is '' it will handle all events that matches</span><span class="pln"><br /> name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'enteredNewPerson'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> aggregate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'person'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional</span><span class="pln"><br /> context</span><span class="pun">:</span><span class="pln"> </span><span class="str">'hr'</span><span class="pun">,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, default is 0</span><span class="pln"><br /> </span><span class="com">// if set to -1, it will ignore the version</span><span class="pln"><br /> version</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="com">//,</span><span class="pln"><br /> <br /> </span><span class="com">// optional, if not defined it will pass the whole event...</span><span class="pln"><br /> </span><span class="com">// payload: 'payload'</span><span class="pln"><br /></span><span class="pun">},</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">evt</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> evt</span><span class="pun">.</span><span class="pln">extended </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"><br /> callback</span><span class="pun">(</span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> evt</span><span class="pun">);</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div></div></div><div class="row-fluid"><div class="span12"><h2>Replay events</h2><div class="row-fluid"><div class="span4"><h4 class="feature-title">Replay whenever you want...</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">replay</span><span class="pun">([</span><span class="com">/* ordered array of events */</span><span class="pun">],</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">err</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">or when catching some events:</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">onEventMissing</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">info</span><span class="pun">,</span><span class="pln"> evt</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> <br /> </span><span class="com">// grab the missing events, depending from info values...</span><span class="pln"><br /> </span><span class="com">// info.aggregateId</span><span class="pln"><br /> </span><span class="com">// info.aggregateRevision</span><span class="pln"><br /> </span><span class="com">// info.aggregate</span><span class="pln"><br /> </span><span class="com">// info.context</span><span class="pln"><br /> </span><span class="com">// info.guardRevision</span><span class="pln"><br /> </span><span class="com">// and call handle...</span><span class="pln"><br /> denormalizer</span><span class="pun">.</span><span class="pln">handle</span><span class="pun">(</span><span class="pln">missingEvent</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">err</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"><br /> </span><span class="pun">});</span><span class="pln"><br /> <br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">or depending on the last guarded event:</h4></div><div class="span8"><div class="feature"><pre><code>denormalizer.getLastEvent(function (err, evt) {
if (event.occurredAt < Date.now()) {
// ...
}
});</code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">streamed</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">replayStreamed</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">replay</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">done</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> <br /> replay</span><span class="pun">(</span><span class="pln">evt1</span><span class="pun">);</span><span class="pln"><br /> replay</span><span class="pun">(</span><span class="pln">evt2</span><span class="pun">);</span><span class="pln"><br /> replay</span><span class="pun">(</span><span class="pln">evt3</span><span class="pun">);</span><span class="pln"><br /> <br /> </span><span class="kwd">done</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">err</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln"><br /> </span><span class="pun">});</span><span class="pln"><br /> <br /></span><span class="pun">});</span></code></pre></div></div></div><div class="row-fluid"><div class="span4"><h4 class="feature-title">if you want to clear the readModel before replaying...</h4></div><div class="span8"><div class="feature"><pre><code><span class="pln">denormalizer</span><span class="pun">.</span><span class="pln">clear</span><span class="pun">(</span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">err</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br /></span><span class="pun">});</span></code></pre></div></div></div></div></div></div></div></div></div></div><div class="extra"><div class="extra-inner"><div class="container"><div class="row"><div class="span4"><h4>about me</h4><ul><li><a href="https://github.com/adrai"><i class="icon-github"></i> github</a></li><li><a href="https://twitter.com/adrirai"><i class="icon-twitter"></i> twitter</a></li></ul></div><div class="span4"><h4>help</h4><ul><li><a href="https://github.com/adrai/cqrs/issues">
issues (<i class="icon-github"></i>)</a></li></ul></div><div class="span4"><h4>legal</h4><ul><li><a href="https://github.com/adrai/node-cqrs-domain/blob/master/licence">license</a></li></ul></div></div></div></div></div><footer class="footer"><div class="footer-inner"><div class="container"><div class="row"><div class="span12">the cqrs modules and libraries are freely distributable under the terms of the MIT license.</div></div></div></div></footer></body></html>