UNPKG

leopold

Version:
225 lines (212 loc) 7.86 kB
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" charset="utf-8"> <title>leopold</title> <link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/cayman.min.css"> <link rel="stylesheet" href="css/prism.min.css"> <link rel="stylesheet" href="css/index.min.css"> <link rel="stylesheet" href="css/docs.min.css"> <link rel="stylesheet" href="css/bootstrap-responsive.min.css"> </head> <body data-spy="scroll" data-target=".scrollspy"> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inner"> <div class="container"><a class="brand">Mr. Doc</a> <div class="nav-collapse collapse"> <ul class="nav pull-right sponsored"></ul> </div> </div> </div> </div> <header id="overview" class="jumbotron subhead"> <div class="container"> <h1>leopold</h1> <p class="lead"></p> </div> </header> <div class="container"> <div class="row"> <div class="span3 bs-docs-sidebar"> <ul class="nav nav-list bs-docs-sidenav affix-top"> <li class="active"><a href="index.html">Main</a></li> <li><a href="leopold.js.html">leopold.js</a></li> </ul> <div class="scrollspy"> <ul class="nav nav-list bs-docs-sidenav affix-top"> </ul> </div> </div> <div class="span9"> <section id="Main" class="readme"><h1>leopold</h1> <pre><code> __^___ [(0¿0)] ~- </code></pre> <h2>Event-sourced models for nodejs or browser</h2> <p><a href="https://github.com/mnichols/leopold/stargazers"><img src="https://img.shields.io/github/stars/mnichols/leopold.svg" alt="GitHub stars"></a> <a href="https://travis-ci.org/mnichols/leopold"><img src="https://travis-ci.org/mnichols/leopold.svg?branch=master" alt="Build Status"></a></p> <h3>Install</h3> <p><code>npm install --save leopold</code></p> <h3>Quick Start</h3> <h4>Eventable models</h4> <pre><code class="language-js"> import leopold from 'leopold' import stampit from 'stampit' // create a leo that includes a unit of work and factory for event providers const leo = leopold() const accountSpec = stampit() .methods({ // by convention, event handlers are named '$' + '${event.name}' // async handlers are supported $initialized: function(e) { this.id(e.id) this.name = e.name this.balance = e.balance } , $deposited: function(e) { this.balance = e.balance } , initialize: function(name) { //returns a promise return this.raise({ event: 'initialized' , id: 'checking' , balance: 0 , name: name }) } , deposit: function(amount) { return this.raise({ event: 'deposited' , balance: (this.balance + amount) }) } }) .compose(leo.eventable()) const customerSpec = stampit() .methods({ $initialized: function(e) { this.id(e.id) this.name = e.name this.accounts = {} } , $accountApproved: function(e) { //use special _id attribute to initialize new account return account() .initialize(e.accountId, e.accountName) .bind(this) .then(function(newAccount) { this.accounts[e.accountName] = newAccount }) } , initialize: function(name) { return this.raise({ event: 'initialized' , name: name , id: 42 }) } , approveAccount: function(accountName) { let acctId = cuid() return this.raise({ event: 'accountApproved' , accountName: accountName , accountId: acctId }) .bind(this) .then(function(){ return this.accounts[acctId].initialize() }) } , makeDeposit: function(account, amount) { return this.accounts[account].deposit(amount) } }) //use let customer = customerSpec.create() customer.approveAccount('checking') // -&gt; customer.accounts['checking'] customer.makeDeposit('checking',300.42) // -&gt; account.balance === 300.42 </code></pre> <p>Notice we have a object graph that is two deep.</p> <h4>Now let's consume a set of events to restore state to where this was</h4> <pre><code class="language-js"> let instance = customerSpec.create({_id: 1}) let events = [ { event: 'initialized', id: 1, name: 'mike' } , { event: 'accountApproved', id: 1, name: 'checking' } , { event: 'initialized', id: 'checking', name: 'checking', balance: 0 } , { event: 'deposited', id: 'checking', balance: 300.42} ] let envelope = { revision: 1 , events: events } // events are stored as envelopes return leo.mount(envelope) .then(function(){ return leo.restore(instance, 0 , Number.MAX_VALUE) }) // instance.accounts[{cuid}].balance === 300.42 </code></pre> <h3>Taking advantage of events for testing side effects</h3> <pre><code class="language-js"> import leopold from 'leopold' import stampit from 'stampit' // create a leo that includes a unit of work and factory for event providers const envelopes = [] const storage = { store(env) { envelopes.push(env )} } const leo = leopold({ //this commits events right away atomic: false , storage }) const myModel = stampit() .methods({ // by convention, event handlers are named '$' + '${event.name}' // async handlers are supported $initialized: function(e) { //do stuff } , initialize: function() { return this.raise({ event: ‘initialized’}) } }) .compose(leo.eventable()) myModel.initialize() envelopes.length === 1 // true envelopes[0].events[0].event === ‘initialized’ // true </code></pre> <h3>Dependencies</h3> <p><code>leopold</code> uses <a href="https://github.com/stampit-org/stampit">stampit</a> under the hood and the <code>eventable</code> call presumes you are composing event source behavior into an prototype ('spec').</p> <p><code>leopold</code> is also using some ES6 features that require <a href="http://babeljs.io/">babel</a>.</p> <h3>Running tests</h3> <p><code>make test</code> (nodejs) <code>make browser</code> (browser) then visit on any browser at <code>http://localhost:2222</code></p> </section> </div> </div> </div> <footer class="footer"> <div class="container"> <p>Documentation generated with <a href="https://github.com/mr-doc/mr-doc">Mr. Doc </a> created by <a href="https://twitter.com/FGRibreau" data-show-count="false" class="twitter-follow-button">Francois-Guillaume Ribreau </a></p> <p>Mr. Doc is sponsored by <a href="http://bringr.net/?btt" title="Outil d'analyse des réseaux sociaux" class="bringr">Bringr </a> and <a href="https://redsmin.com/?btt" title="Full Redis GUI" class="redsmin">Redsmin</a></p> <p>Theme borrowed from Twitter Bootstrap</p> </div> </footer> <script src="js/twitter-widget.min.js"></script> <script src="js/jquery.min.js"></script> <script src="js/bootstrap-transition.min.js"></script> <script src="js/bootstrap-scrollspy.min.js"></script> <script src="js/bootstrap-dropdown.min.js"></script> <script src="js/bootstrap-collapse.min.js"></script> <script src="js/bootstrap-affix.min.js"></script> <script src="js/prism.min.js"></script> <script src="js/index.min.js"></script> </body> </html>