<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Yurii Rashkovskii's Blog - Home</title>
  <id>tag:rashkovskii.com,2008:mephisto/</id>
  <generator uri="http://mephistoblog.com" version="0.7.3">Mephisto Noh-Varr</generator>
  <link href="http://rashkovskii.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://rashkovskii.com/" rel="alternate" type="text/html"/>
  <updated>2008-05-20T10:10:53Z</updated>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-05-20:4875</id>
    <published>2008-05-20T10:05:00Z</published>
    <updated>2008-05-20T10:10:53Z</updated>
    <link href="http://rashkovskii.com/articles/2008/5/20/rbxmodexcl" rel="alternate" type="text/html"/>
    <title>RbxModExcl</title>
<content type="html">
            &lt;p&gt;I&#8217;ve managed to port &lt;a href=&quot;http://rashkovskii.com/articles/2008/4/22/ruby-module-exclusion&quot;&gt;ruby module exclusion&lt;/a&gt; library, &lt;a href=&quot;http://github.com/yrashk/rbmodexcl/tree/master&quot;&gt;rbmodexcl&lt;/a&gt; to &lt;a href=&quot;http://rubini.us&quot;&gt;Rubinius&lt;/a&gt;. It is included into rbmodexcl now. The most important thing is that it was written in Ruby, no C hacking was involved (as it was for &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt;)&lt;/p&gt;


	&lt;p&gt;I am not sure it is bug-free, but at least those specs I had work. Enjoy! :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-05-16:4777</id>
    <published>2008-05-16T05:22:00Z</published>
    <updated>2008-05-16T05:35:21Z</updated>
    <link href="http://rashkovskii.com/articles/2008/5/16/we-don-t-need-a-database" rel="alternate" type="text/html"/>
    <title>We Don't Need a "Database"</title>
<content type="html">
            &lt;p&gt;I&#8217;ve been trying to formulate what &lt;a href=&quot;http://strokedb.com/&quot;&gt;StrokeDB&lt;/a&gt; is recently. And here is my summary: StrokeDB is not a database; it is a programming environment on top of Ruby (until we&#8217;ll have it ported to other languages). And here are my thoughts about &#8220;database&#8221; concept.&lt;/p&gt;


	&lt;p&gt;Do we &lt;strong&gt;really&lt;/strong&gt; need &#8220;databases&#8221;? Well, I mean, we surely need some toolset to be able to store and retrieve data, but who said we need it in a form of pure datasets to be stored and retrieved? Who said that there should be a database server to interact with? Who said we might need special domain languages designed to manipulate arbitrary data?&lt;/p&gt;


	&lt;p&gt;What we &lt;strong&gt;really&lt;/strong&gt; need is a persistence-aware programming environment, aren&#8217;t we? We just need to be able to store and retrieve data no matter how its persistence handled internally. There is nothing new about it, actually — &lt;span class=&quot;caps&quot;&gt;MUMPS&lt;/span&gt; and GemStone/S (or even PL/SQL) were around for decades. What we &lt;strong&gt;really&lt;/strong&gt; might need is to be able to create your-application-data-domain specific languages without any hassles — since we need to manipulate application&#8217;s data, not just &lt;strong&gt;any&lt;/strong&gt; data (like you basically do with &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;).&lt;/p&gt;


	&lt;p&gt;It is quite popular in Rails world to say that we need a &lt;em&gt;stupid&lt;/em&gt; database, just a kind of storage and let Ruby do the rest. Basically, they have a point. They use &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; as a data storage layer and their database is actually &lt;em&gt;smart&lt;/em&gt;, because what is really important for data handling is actually implemented in Ruby. It is still usually limited by &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; design constraints, though.&lt;/p&gt;


	&lt;p&gt;My point is that your data should be as close to your main programming environment as it is possible. Your structures should be as &lt;em&gt;native&lt;/em&gt; as it is possible — and they should be handled within the same environment. That&#8217;s reminds things like PL/SQL. Basically, PL/SQL is not &lt;span class=&quot;caps&quot;&gt;THAT&lt;/span&gt; bad, but the thing with it is that usually you was using not &lt;span class=&quot;caps&quot;&gt;ONLY PL&lt;/span&gt;/SQL, but, say, some Java code to interoperate with Oracle database.&lt;/p&gt;


&lt;blockquote&gt;
 Your application itself &lt;strong&gt;IS&lt;/strong&gt; a &lt;em&gt;smart&lt;/em&gt; database.
&lt;/blockquote&gt;

	&lt;p&gt;So, I&#8217;d say we&#8217;re in the beginning of the long way &#8220;back to the future&#8221; — persistence-aware programming environments, not just &lt;em&gt;databases&lt;/em&gt;.&lt;/p&gt;


	&lt;p&gt;Viva &lt;strong&gt;smart&lt;/strong&gt; databases!&lt;/p&gt;


	&lt;p&gt;P.S. I am going to blog about data organization concepts within such environments soon — that&#8217;s an interesting topic to talk about and it is surely more concrete than this one :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-05-02:4724</id>
    <published>2008-05-02T06:04:00Z</published>
    <updated>2008-05-02T06:08:35Z</updated>
    <link href="http://rashkovskii.com/articles/2008/5/2/strokedb-is-a-global-database" rel="alternate" type="text/html"/>
    <title>StrokeDB is a Global Database</title>
<content type="html">
            &lt;p&gt;&lt;a href=&quot;http://oleganza.wordpress.com/&quot;&gt;Oleg Andreev&lt;/a&gt; has published a &lt;a href=&quot;http://oleganza.wordpress.com/2008/05/01/strokedb-is-a-global-database/&quot;&gt;nice writeup&lt;/a&gt; about networking/collaboration aspect of StrokeDB vision.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-04-26:4711</id>
    <published>2008-04-26T04:54:00Z</published>
    <updated>2008-04-26T04:54:14Z</updated>
    <link href="http://rashkovskii.com/articles/2008/4/26/top-10-reasons-to-avoid-document-databases-fud" rel="alternate" type="text/html"/>
    <title>Top 10 Reasons to Avoid Document Databases FUD</title>
<content type="html">
            &lt;p&gt;This article is written in response to &lt;a href=&quot;http://www.ryanpark.org/2008/04/top-10-avoid-the-simpledb-hype.html&quot;&gt;Top 10 Reasons to Avoid the SimpleDB Hype&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;First of all I&#8217;d like to note that the below answers are not about SimpleDB but rather to prevent &lt;span class=&quot;caps&quot;&gt;FUD&lt;/span&gt; about document-based databases.&lt;/p&gt;


	&lt;h1&gt;1. Data integrity is not guaranteed.&lt;/h1&gt;


	&lt;p&gt;This could be the case with SimpleDB, but overall nothing prevents document databases from managing data integrity very well.&lt;/p&gt;


	&lt;p&gt;Regarding the constraints, there is nothing that prevents defining validations in a document or its related &#8220;meta&#8221; document (this is pretty much how &lt;a href=&quot;http://strokedb.com/&quot;&gt;StrokeDB&lt;/a&gt; works — you can define your validations within meta document and they will let your document stay validated)&lt;/p&gt;


	&lt;p&gt;More interesting are the concerns about the conflicts. I&#8217;d say that this problem is hardly addressed in a common &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; approach. All you usually get is either user&#8217;s A or user&#8217;s B most recent update — there seems to be no easy way graceful conflict resulution. On the contrary, since document databases approach is rather novel there is certainly enough room to adopt ways to deal with conflicts. For example, with different and configurable algorithms — like merging them slot-by-slot 3-ways, or even some special programmer-defined algorithms. I can hardly imagine how to do this sort of stuff with traditional &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; in a relatively easy manner.&lt;/p&gt;


	&lt;h1&gt;2. Inconsistency will provide a terrible user experience.&lt;/h1&gt;


	&lt;p&gt;First of all, it should noted that described inconsistencies are also quite possible with distributed &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; setups — they too are constrained by a certain lag before the data is going to be propagated through replicas.&lt;/p&gt;


	&lt;p&gt;The actual problem is not with lag — it is more about leaving documents in a consistent state.&lt;/p&gt;


	&lt;p&gt;This problem could be easily addressed in any kind of database, either relational or document-based.&lt;/p&gt;


	&lt;h1&gt;3. Aggregate operations will require more coding.&lt;/h1&gt;


	&lt;p&gt;Again, while this seems to be true for SimpleDB, other document-based databases address this problem pretty well with Views approach (&lt;a href=&quot;http://incubator.apache.org/couchdb/&quot;&gt;CouchDB&lt;/a&gt;, StrokeDB [Views is &lt;span class=&quot;caps&quot;&gt;WIP&lt;/span&gt;]) — so you can define any kind of aggregation, even such that are simply not supported by &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt;.&lt;/p&gt;


	&lt;h1&gt;4. Complicated reports, and ad hoc queries, will require a lot more coding.&lt;/h1&gt;


	&lt;p&gt;I&#8217;d refer to Views approach once again — it is quite a nice way to produce complicated reports as quickly as well-known &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; indexes do.&lt;/p&gt;


	&lt;p&gt;&#8220;Views&#8221; could be viewed as subroutines with a special well-defined &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; — and we can use these subroutines to index specific &#8220;queries&#8221; even in runtime. That&#8217;s pretty interesting.&lt;/p&gt;


	&lt;h1&gt;5. Aggregate operations will be much slower if you don’t use an &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt;.&lt;/h1&gt;


	&lt;p&gt;This is a dubious statement. First, for the majority of the queries speed is defined by the speed of the index (all that B+ trees stuff). Document-oriented database views are indexed the very same way.&lt;/p&gt;


	&lt;p&gt;Speaking of those &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; &#8220;rows&#8221; and objects I wouldn&#8217;t say they are much different. An Object with key/value pairs slots is definitely a &#8220;row&#8221; in that sense. So what&#8217;s so different about them?&lt;/p&gt;


	&lt;p&gt;On the other hand, &#8220;real&#8221; relational database should actually use aggregating operations (joins) far more frequently than typical document database. Relational database is basically about storing short &#8220;facts&#8221; with relations between them and using lots of join operations to aggregate synthetic data. That wouldn&#8217;t be efficient/easy enough to program though — that is why most of relational database in the &#8220;real world&#8221; are organized in the form of fairly wide tables.&lt;/p&gt;


	&lt;p&gt;And, finally, for the well-done DODBs it is possible to use nice Map-Reduce &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; to build and incrementally update very complex aggregations.&lt;/p&gt;


	&lt;h1&gt;6. Data import, export, and backup will be slow and difficult.&lt;/h1&gt;


	&lt;p&gt;&#8220;There are no such tools for key-value data stores, because these products are so new.&#8221;&lt;/p&gt;


	&lt;p&gt;Is lack of maturity a good reason to blame new technologies?&lt;/p&gt;


	&lt;p&gt;SimpleDB implementation in particular might have its own flaws in this area — but nothing prevents it from improving things in theory and practice.&lt;/p&gt;


	&lt;h1&gt;7. SimpleDB isn’t that fast.&lt;/h1&gt;


	&lt;p&gt;Since this this post I am talking about document databases in general, I&#8217;d skip those &#8220;internet latency&#8221; issues. It&#8217;s kinda irrelevant.&lt;/p&gt;


	&lt;h1&gt;8. Relational databases are scalable, even with massive data sets.&lt;/h1&gt;


	&lt;p&gt;The main argument here is that &#8220;those guys do scale relational database, so they are scalable&#8221;. True. They are scalable. But at what cost?
&#8220;Those guys&#8221; were able to do a lot of great stuff utilizing manpower before letting machinery do this back tens years ago. But is it a good excuse to manufacture goods without machinery these days just because it is possible? I doubt it. Throwing man power at a problem is not always the best approach.&lt;/p&gt;


	&lt;p&gt;And&#8230; you said &#8220;relational&#8221;? Facebook and others do a lot of denormalization, they don&#8217;t &lt;strong&gt;ever&lt;/strong&gt; use &lt;span class=&quot;caps&quot;&gt;JOIN&lt;/span&gt;, they&#8217;d rather do several consequent requests and build intermediate results on a webserver (when you have 20 times more webservers than DBs it&#8217;s obviously good to move some load there). They treat good old MySQL as object storage with very fast B+ tree indexes. Finally, the resulting database is &lt;strong&gt;not&lt;/strong&gt; a relational one. One thousand of MySQLs  is just a distributed object storage with simple fast indexes and a bunch of hand-written code in php/ruby/python/whatever around it.&lt;/p&gt;


	&lt;h1&gt;9. Super-scalability is overrated. Slowing the pace of your product development is even worse.&lt;/h1&gt;


	&lt;p&gt;Super-scalability issue is not really overrated. The problem with the approach of &#8220;why not wait and address super-scalability once you’ve created a super product&#8221; is that once you will address super-scalability, it will be quite a different product.&lt;/p&gt;


	&lt;p&gt;The issue with scalability these days is that less scalable applications are quite different from the the ones that are hugely scalable — and that is why writing a scalable application from the scratch is definitely a waste of time and money.&lt;/p&gt;


	&lt;p&gt;But what if scaling from SQLite-like backend to 2 datacenters will be quite painless and will not require you to rethink database interactions in your application? With the right database &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; design it is quite possible. BigTable, Amazon Dynamo, CouchDB, StrokeDB approaches are all about addressing this need.&lt;/p&gt;


	&lt;h1&gt;10. SimpleDB is useful, but only in certain contexts.&lt;/h1&gt;


	&lt;p&gt;Same can be said for relational databases. In the real world, data is not really well structured — it is rather versatile and it&#8217;s repsentation depends on point of view. This problem is very well addressed by document databases (and StrokeDB in particular was created in attempts to solve this problem).&lt;/p&gt;


	&lt;p&gt;&#8220;Amazon SimpleDB, Apache CouchDB, and the Google Datastore &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; aren’t bad products. But we do them a disservice when we construe them to be replacements for general-purpose databases. Used carefully, they can help your organization. But used indiscriminately, you’ll create a lot more work for your programmers and you’ll make your application perform even worse&#8221;&lt;/p&gt;


	&lt;p&gt;Relational databases are not bad products either. Used carefully, they can help your organization. But used indiscriminately, you&#8217;ll create a lot more work for your programmers and you&#8217;ll make your application development even more complex.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-04-22:4705</id>
    <published>2008-04-22T20:43:00Z</published>
    <updated>2008-04-22T20:44:26Z</updated>
    <link href="http://rashkovskii.com/articles/2008/4/22/ruby-module-exclusion" rel="alternate" type="text/html"/>
    <title>Ruby module exclusion</title>
<content type="html">
            &lt;p&gt;May be I am missing something (since I am not &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; hacker), but why there is no module exclusion functionality — i.e. you can extend 
object with module, but can&#8217;t reverse this operation? Any specific reason for this decision, do you know?&lt;/p&gt;


	&lt;p&gt;I&#8217;ve just sketched &lt;a href=&quot;http://github.com/yrashk/rbmodexcl/tree/master&quot;&gt;simplistic implementation&lt;/a&gt; for this kind of functionality and really wondering why there is no such stuff in &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Again, am I missing something?&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-03-24:4681</id>
    <published>2008-03-24T20:02:00Z</published>
    <updated>2008-03-24T22:26:42Z</updated>
    <link href="http://rashkovskii.com/articles/2008/3/24/we-ve-launched-strokedb-com" rel="alternate" type="text/html"/>
    <title>We've launched strokedb.com</title>
<content type="html">
            &lt;p&gt;First version of StrokeDB&#8217;s site has been launched: &lt;a href=&quot;http://strokedb.com/&quot;&gt;http://strokedb.com/&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-03-09:4645</id>
    <published>2008-03-09T12:45:00Z</published>
    <updated>2008-03-09T12:47:56Z</updated>
    <link href="http://rashkovskii.com/articles/2008/3/9/strokedb-s-experimental-composite-metas-syntax" rel="alternate" type="text/html"/>
    <title>StrokeDB's experimental composite metas syntax</title>
<content type="html">
            &lt;p&gt;I was playing with this idea in my mind for a week or so and finally  
decided to put it into the code. The basic idea is that since any  
document can have multiple metas, why not improving &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for this?  
Before latest commits, you needed to do things like:&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
u = User.new :name =&amp;gt; &quot;Yurii&quot; 
u.metas &amp;lt;&amp;lt; Buyer
u.metas &amp;lt;&amp;lt; Seller
u.save!
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;It isn&#8217;t really nice. So what I have done just a couple of minutes ago  
is a special syntax for composite metas. You can simply use Meta#+ to  
add meta to meta:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
User = Meta.new
    # ==&amp;gt; User
Buyer = Meta.new
    # ==&amp;gt; Buyer
Seller = Meta.new
    # ==&amp;gt; Seller
(User+Buyer+Seller).create! :name =&amp;gt; &quot;Yurii&quot; 
    # ==&amp;gt; #&amp;lt;User,Buyer,Seller __version__: 5bf2..., name: &quot;Yurii&quot;,  uuid: &quot;32ae72c8-a1da-4ead-8bfb-d2aa65e727f3&quot;&amp;gt;
&lt;/code&gt;
&lt;/pre&gt;
where created document will have actually three metas:

&lt;pre&gt;
&lt;code&gt;
_[:__meta__]
    # ==&amp;gt; [#&amp;lt;StrokeDB::Meta __version__: b6a0..., name: &quot;User&quot;, uuid:  &quot;292b3226-8c69-4d21-bb2c-d4d8cd924bf2&quot;&amp;gt;, #&amp;lt;StrokeDB::Meta __version__:  d223..., name: &quot;Buyer&quot;, uuid: &quot;89d4c62a-b935-42c6-b680-78e1de0b7d9e&quot;&amp;gt;,  #&amp;lt;StrokeDB::Meta __version__: 2291..., name: &quot;Seller&quot;, uuid: &quot;52babc48-5bda-4ea1-a4c3-1c931185c290&quot;&amp;gt;]
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Also (User+Buyer+Seller).find will work just as expected:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
    # ==&amp;gt; [#&amp;lt;User,Buyer,Seller __version__: 5bf2..., name: &quot;Yurii&quot;,  uuid: &quot;32ae72c8-a1da-4ead-8bfb-d2aa65e727f3&quot;&amp;gt;]
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;(please note that composition order is important, not only in #find but it also defines a way how combined meta document will look like [Document#meta]).&lt;/p&gt;


	&lt;p&gt;Please note that this stuff is not fully complete yet, but as always,  it is already funny to play with it.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-03-09:4644</id>
    <published>2008-03-09T12:40:00Z</published>
    <updated>2008-03-09T12:47:00Z</updated>
    <link href="http://rashkovskii.com/articles/2008/3/9/strokedb-s-early-implementation-of-inter-store-sync" rel="alternate" type="text/html"/>
    <title>StrokeDB's early implementation of inter-store sync</title>
<content type="html">
            &lt;p&gt;This morning I&#8217;ve finalized an early implementation of inter-store  
synchronization. Please not that it is definitely not mature, &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; and  
details might change over time.&lt;/p&gt;


	&lt;p&gt;So, what is this for? Synchronization is a way to replicate document  
between stores back and forth, while preserving whole history of  
document changes.&lt;/p&gt;


	&lt;p&gt;Here you are an example:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
# Main store is default store
store = StrokeDB.default_store
# Let's create another store
another_store = StrokeDB::Config.build(:base_path =&amp;gt;  'tmp_db').stores[:default]

# Here we're creating some document in another_store
doc = Document.create!(another_store, :hello =&amp;gt; 'world')
# Updating it
doc.test = 'passed'
doc.save!

# Syncing it to store
# doc.__versions__.all.reverse is basically pass all versions of doc in reverse order (after this reversion latest version will be at the  end of list). Order is important
store.sync!(doc.__versions__.all.reverse,another_store.timestamp)

# updating document at store
doc_at_store = store.find(doc.uuid)
doc_at_store.ok = true
doc_at_store.save!

# Syncing it back to another_store
another_store.sync! 
(doc_at_store.__versions__.all.reverse,store.timestamp)

# Now, let's reload document at another store:
doc.reload
# ==&amp;gt; #&amp;lt;Doc __previous_version__: fe9e..., __version__: bdf6...,  hello: &quot;world&quot;, ok: true, test: &quot;passed&quot;, uuid:  &quot;e70aca78-69d3-4e2c-920c-813f2c17be75&quot;&amp;gt;
# as you can see, it got 'ok' slot with value of true
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Voila!&lt;/p&gt;


	&lt;p&gt;Synchronization will work just fine if you have a fast-forward  
situation and will raise ConflictCondition if you have a conflict.
Oleg is working on merge3 algorithm to let it be one of the scenarios  
to resolve ConflictConditions; I am also thinking about 1-2 simple  
scenarios for conflict resolving.&lt;/p&gt;


	&lt;p&gt;Anyway, as I&#8217;ve said above, its &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;/way to work isn&#8217;t mature yet, so  
things might change.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-03-08:4637</id>
    <published>2008-03-08T05:40:00Z</published>
    <updated>2008-03-08T05:56:41Z</updated>
    <link href="http://rashkovskii.com/articles/2008/3/8/poor-man-s-web-application-with-strokedb-and-merb" rel="alternate" type="text/html"/>
    <title>Poor man's web application with StrokeDB and Merb</title>
<content type="html">
            &lt;p&gt;Yesterday I&#8217;ve finally got to playing with StrokeDB as a database &#8220;server&#8221; for a web application (currently using Merb, but basically the following scenario should work for any Ruby-based framework)&lt;/p&gt;


	&lt;p&gt;So, while we&#8217;re going to create a nice realtime replication subsystem that will allow to build really largely scalable applications with StrokeDB, there is definitely a need to play with StrokeDB-powered web applications right away, even if it will not be that scalable and fast as we want it to be. That&#8217;s why I&#8217;ve tried to create something like simplistic way to use StrokeDB from few Merb application instances.&lt;/p&gt;


	&lt;p&gt;The basic idea is that all processes that want to access StrokeDB database need to access the only one &#8220;server&#8221; store over network connection. That&#8217;s why I&#8217;ve created RemoteStore concept that allows to access stores over DRb (more protocols could be added later). Since stores (SkiplistStore to be specific) aren&#8217;t really thread-safe, RemoteStore server is actually serving one client at a time. Unless you&#8217;re going to invoke long-running operations, it should be fast enough to &lt;em&gt;play&lt;/em&gt; with this stuff.&lt;/p&gt;


	&lt;p&gt;So, here we go. Lets assume you have a Merb skeleton application (I am using merb-0.5.3 at the moment). All you need to do is:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Update your config/merb_init.rb to contain something like&lt;/li&gt;
	&lt;/ul&gt;


&lt;pre&gt;
 &lt;code&gt;
puts &quot;Loading StrokeDB...&quot; 
$:.unshift File.dirname(__FILE__) + '/../../strokedb-ruby/' # replace with your StrokeDB path
require 'strokedb'

StrokeDB.use_global_default_config!

print &quot;Configuring StrokeDB...&quot; 
if ARGV.include?('--strokedb-server')
  print 'configuring server store...'
  StrokeDB::Config.build :base_path =&amp;gt; File.dirname(__FILE__) + &quot;/../db&quot;, :default =&amp;gt; true
  STROKEDB_THREAD = StrokeDB.default_store.remote_server('druby://localhost:9999').start
else
  StrokeDB.default_store = StrokeDB::RemoteStore::DRb::Client.new('druby://localhost:9999')
end
puts &quot;done.&quot; 
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;ul&gt;
	&lt;li&gt;define some metas in app/models, like app/models/user.rb:&lt;/li&gt;
	&lt;/ul&gt;


&lt;pre&gt;
&lt;code&gt;
User = Meta.new
&lt;/code&gt;
&lt;/pre&gt;

	&lt;ul&gt;
	&lt;li&gt;run StrokeDB server:&lt;/li&gt;
	&lt;/ul&gt;


&lt;pre&gt;
&lt;code&gt;
$ merb -r &quot;STROKEDB_THREAD.join&quot; --strokedb-server
&lt;/code&gt;
&lt;/pre&gt;

	&lt;ul&gt;
	&lt;li&gt;enjoy StrokeDB-powered application!&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;For example, you can use it in your controllers, or simply play within merb console (merb -i)&lt;/p&gt;


	&lt;p&gt;Of course, this method is definitely poor man&#8217;s one and we&#8217;re working on a better ways to build StrokeDB-powered applications, but something is more than nothing :)&lt;/p&gt;


	&lt;p&gt;If you&#8217;ll have any problems with the above scenario, let me know.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-03-05:4625</id>
    <published>2008-03-05T06:54:00Z</published>
    <updated>2008-03-05T06:56:55Z</updated>
    <link href="http://rashkovskii.com/articles/2008/3/5/strokedb-s-first-validation" rel="alternate" type="text/html"/>
    <title>StrokeDB's first validation</title>
<content type="html">
            &lt;p&gt;Folks,&lt;/p&gt;


	&lt;p&gt;this morning I&#8217;ve crafted first validation primitive for StrokeDB&#8212; 
validates_presence_of&lt;/p&gt;


	&lt;p&gt;Here you are few examples of it:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
User = StrokeDB::Meta.new do
        validates_presence_of :login
end
    # ==&amp;gt; User
User.create! rescue $!.message
    # ==&amp;gt; &quot;User's login should be present on save&quot; 
&lt;/code&gt;
&lt;/pre&gt;

&lt;pre&gt;
&lt;code&gt;
User = StrokeDB::Meta.new do
    validates_presence_of :login, :on =&amp;gt; :create # or :save or :update
end
&lt;/code&gt;
&lt;/pre&gt;

&lt;pre&gt;
&lt;code&gt;
User = StrokeDB::Meta.new do
        validates_presence_of :login, :message =&amp;gt; '#{meta} should always have #{slotname} to be able to log in'
end
    # ==&amp;gt; User
User.create! rescue $!.message
    # ==&amp;gt; &quot;User should always have login to be able to log in&quot; 
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;More validations to appear soon.&lt;/p&gt;


	&lt;p&gt;Enjoy!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-02-29:4604</id>
    <published>2008-02-29T09:40:00Z</published>
    <updated>2008-02-29T09:44:38Z</updated>
    <link href="http://rashkovskii.com/articles/2008/2/29/experimental-has_many-support" rel="alternate" type="text/html"/>
    <title>Experimental has_many support</title>
<content type="html">
            &lt;p&gt;I am happy to announce that StrokeDB got an experimental has_many support recently.&lt;/p&gt;


	&lt;p&gt;Now you can easily collect documents that refer to your document by defining has_many for your meta:&lt;/p&gt;


	&lt;p&gt;(All examples shown are done in test/console)&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
Playlist = Meta.new do
  has_many :songs
end
    ==&amp;gt;Playlist
Song = Meta.new
    ==&amp;gt;Song
playlist = Playlist.create!(:name =&amp;gt; &quot;My playlist&quot;)
    ==&amp;gt;#&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 330f...&amp;gt;
song = Song.create!(:name =&amp;gt; &quot;My song&quot;, :playlist =&amp;gt; playlist)
    ==&amp;gt;#&amp;lt;Song name: &quot;My song&quot;, __version__: 530f..., playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 330f...&amp;gt;&amp;gt;
playlist.songs
    ==&amp;gt;[#&amp;lt;Song name: &quot;My song&quot;, __version__: 530f..., playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 330f...&amp;gt;&amp;gt;]
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;So, here we define has_many :songs, which inflates :songs to Song meta and uses Song&#8217;s :playlist slot as a reference to Playlist. Like in ActiveRecord, this definition uses configuration by convention. And again, like in ActiveRecord, you can tweak it:&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
Playlist = Meta.new do
  has_many :all_songs, :through =&amp;gt; :songs, :foreign_reference =&amp;gt; :belongs_to_playlist
end
    ==&amp;gt;Playlist
Song = Meta.new
    ==&amp;gt;Song
playlist = Playlist.create!(:name =&amp;gt; &quot;My playlist&quot;)
    ==&amp;gt;#&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3245...&amp;gt;
song = Song.create!(:name =&amp;gt; &quot;My song&quot;, :belongs_to_playlist =&amp;gt; playlist)
    ==&amp;gt;#&amp;lt;Song name: &quot;My song&quot;, __version__: 5245..., belongs_to_playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3245...&amp;gt;&amp;gt;
playlist.all_songs
    ==&amp;gt;[#&amp;lt;Song name: &quot;My song&quot;, __version__: 5245..., belongs_to_playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3245...&amp;gt;&amp;gt;]
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Here we use :through option which tells StrokeDB to use Song meta to find documents, and :foreign_reference specifies Song&#8217;s slot name for the reference to Playlist. You can also add some conditions to has_many:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
Playlist = Meta.new do
  has_many :rock_songs, :through =&amp;gt; :songs, :foreign_reference =&amp;gt; :belongs_to_playlist, :conditions =&amp;gt; {:genre =&amp;gt; &quot;Rock&quot;}
end
    ==&amp;gt;Playlist
Song = Meta.new
    ==&amp;gt;Song
playlist = Playlist.create!(:name =&amp;gt; &quot;My playlist&quot;)
    ==&amp;gt;#&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3cd6...&amp;gt;
rock_song = Song.create!(:name =&amp;gt; &quot;My song&quot;, :belongs_to_playlist =&amp;gt; playlist, :genre =&amp;gt; &quot;Rock&quot;)
    ==&amp;gt;#&amp;lt;Song name: &quot;My song&quot;, __version__: 5cd6..., belongs_to_playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3cd6...&amp;gt;, genre: &quot;Rock&quot;&amp;gt;
pop_song = Song.create!(:name =&amp;gt; &quot;My song 2&quot;, :belongs_to_playlist =&amp;gt; playlist, :genre =&amp;gt; &quot;Pop&quot;)
    ==&amp;gt;#&amp;lt;Song name: &quot;My song 2&quot;, __version__: 6cd6..., belongs_to_playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3cd6...&amp;gt;, genre: &quot;Pop&quot;&amp;gt;
playlist.rock_songs
    ==&amp;gt;[#&amp;lt;Song name: &quot;My song&quot;, __version__: 5cd6..., belongs_to_playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3cd6...&amp;gt;, genre: &quot;Rock&quot;&amp;gt;]
&lt;/pre&gt;
&lt;/code&gt;

	&lt;p&gt;Isn&#8217;t it nice? But lets go further. What if you want to know all authors of music in your playlist? That&#8217;s quite simple!&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
Playlist = Meta.new do
  has_many :authors, :through =&amp;gt; [:songs, :author]
end
    ==&amp;gt;Playlist
Song = Meta.new
    ==&amp;gt;Song
playlist = Playlist.create!(:name =&amp;gt; &quot;My playlist&quot;)
    ==&amp;gt;#&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3903...&amp;gt;
song = Song.create!(:name =&amp;gt; &quot;My song&quot;, :playlist =&amp;gt; playlist, :author =&amp;gt; &quot;John Doe&quot;)
    ==&amp;gt;#&amp;lt;Song name: &quot;My song&quot;, __version__: 5903..., author: &quot;John Doe&quot;, playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3903...&amp;gt;&amp;gt;
playlist.authors
    ==&amp;gt;[&quot;John Doe&quot;]
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;or&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
Playlist = Meta.new do
  has_many :authors, :through =&amp;gt; [:songs, :author]
end
    ==&amp;gt;Playlist
Song = Meta.new
    ==&amp;gt;Song
Author = Meta.new
    ==&amp;gt;Author
playlist = Playlist.create!(:name =&amp;gt; &quot;My playlist&quot;)
    ==&amp;gt;#&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3b19...&amp;gt;
author = Author.create!(:name =&amp;gt; &quot;John Doe&quot;)
    ==&amp;gt;#&amp;lt;Author name: &quot;John Doe&quot;, __version__: 5b19...&amp;gt;
song = Song.create!(:name =&amp;gt; &quot;My song&quot;, :playlist =&amp;gt; playlist, :author =&amp;gt; author)
    ==&amp;gt;#&amp;lt;Song name: &quot;My song&quot;, __version__: 7b19..., author: #&amp;lt;Author name: &quot;John Doe&quot;, __version__: 5b19...&amp;gt;, playlist: #&amp;lt;Playlist name: &quot;My playlist&quot;, __version__: 3b19...&amp;gt;&amp;gt;
playlist.authors
    ==&amp;gt;[#&amp;lt;Author name: &quot;John Doe&quot;, __version__: 5b19...&amp;gt;]
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;So here in these examples has_meta fetches all Songs and gets all their :author slots.&lt;/p&gt;


	&lt;p&gt;So here it is. Current has_many implementation is quite experimental and might change later (for example, we&#8217;re still thinking about improving :conditions stuff for :through =&amp;gt; [...] case, since :conditions are currently applying only to Songs). And most probably it has some bugs :)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-02-15:4511</id>
    <published>2008-02-15T08:55:00Z</published>
    <updated>2008-02-15T09:12:59Z</updated>
    <link href="http://rashkovskii.com/articles/2008/2/15/how-to-play-with-strokedb-easily" rel="alternate" type="text/html"/>
    <title>How to play with StrokeDB easily</title>
<content type="html">
            &lt;p&gt;As I&#8217;ve told in the previous post about StrokeDB, we&#8217;ve &lt;a href=&quot;http://groups.google.com/group/strokedb/browse_thread/thread/e4b22c6f6889f91c&quot;&gt;added a simplistic test console&lt;/a&gt; to StrokeDB recently.&lt;/p&gt;


	&lt;p&gt;Here is an instruction how to use it.&lt;/p&gt;


	&lt;p&gt;First, you&#8217;ll need StrokeDB :) You can get it easily with &lt;a href=&quot;http://git.or.cz&quot;&gt;Git&lt;/a&gt;:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
$ git clone git://gitorious.org/strokedb/mainline.git strokedb
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Then, change your work directory and start console:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
$ cd strokedb/strokedb-ruby
$ ./test/console --prompt xmp
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;(&#8212;prompt xmp isn&#8217;t obligatory)&lt;/p&gt;


	&lt;p&gt;Now you can play with it:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
$ ./test/console --prompt xmp
StrokeDB 0.0.1 Console
Type 'h' for help
User = Meta.new  # here we define User
    ==&amp;gt;{User meta module}
User.create! :login =&amp;gt; &quot;test&quot;, :email =&amp;gt; &quot;test@foobar.com&quot; 
    ==&amp;gt;#&amp;lt;{User} __version__: 3c3c..., login: &quot;test&quot;, email: &quot;test@foobar.com&quot;&amp;gt;
save!
    ==&amp;gt;true
quit
$ ./test/console --prompt xmp
StrokeDB 0.0.1 Console
Type 'h' for help
User = Meta.new  # here we define User
    ==&amp;gt;{User meta module}
User.find(:login =&amp;gt; &quot;test&quot;) # let's fine Users by login
    ==&amp;gt;[#&amp;lt;{User} __version__: 3c3c..., login: &quot;test&quot;, email: &quot;test@foobar.com&quot;&amp;gt;]
u = _.first
    ==&amp;gt;#&amp;lt;{User} __version__: 3c3c..., login: &quot;test&quot;, email: &quot;test@foobar.com&quot;&amp;gt;
u.name = &quot;John Doe&quot; # update user's name
    ==&amp;gt;&quot;John Doe&quot; 
u.save! # save user
    ==&amp;gt;#&amp;lt;{User} name: &quot;John Doe&quot;, __version__: 1e50..., __previous_version__: 3c3c..., login: &quot;test&quot;, email: &quot;test@foobar.com&quot;&amp;gt;
u.name = &quot;John Doe&quot; # get name
    ==&amp;gt;&quot;John Doe&quot; 
u.email
    ==&amp;gt;&quot;test@foobar.com&quot; # get email
clear! # wipe out database
    ==&amp;gt;true
User.find(:login =&amp;gt; &quot;test&quot;)
    ==&amp;gt;[] # nobody found!
quit
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;You can also type &#8216;h&#8217; to get some help.&lt;/p&gt;


	&lt;p&gt;Hope you&#8217;ll enjoy.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-02-14:4484</id>
    <published>2008-02-14T22:23:00Z</published>
    <updated>2008-02-15T10:02:55Z</updated>
    <link href="http://rashkovskii.com/articles/2008/2/14/strokedb-short-intro" rel="alternate" type="text/html"/>
    <title>StrokeDB short intro</title>
<content type="html">
            &lt;p&gt;I&#8217;ve decided to write a short introductory material about StrokeDB usage.&lt;/p&gt;


	&lt;p&gt;&lt;em&gt;Disclaimer: StrokeDB is still pretty young (still less than one month of development), so I can&#8217;t promise that &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; shown will remain the same forever. In fact, some portions of it will &lt;strong&gt;definitely&lt;/strong&gt; change&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;First, lets load StrokeDB and initialize it:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
require &quot;strokedb&quot; 
StrokeDB::Config.build :default =&amp;gt; true, :base_path =&amp;gt; 'some_test'
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;I willn&#8217;t go into guts of config builder (that&#8217;s a bit complicated for those who are new to StrokeDB, but I&#8217;ll probably post some materials about it later).&lt;/p&gt;


	&lt;p&gt;So effectively, now we have a database initialized and it&#8217;s base path for file storages is some_test/&lt;/p&gt;


	&lt;p&gt;Now, we&#8217;re going to get into some fun. I&#8217;ll define several metas.&lt;/p&gt;


	&lt;p&gt;User:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
User = StrokeDB::Meta.new do
  def to_s
    self[:name]
  end
end
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Unlike ActiveRecord, StrokeDB uses a kind of mixin model. Each document can have any number of metadocuments it refer to. As I &lt;a href=&quot;http://rashkovskii.com/articles/2008/2/3/strokedb-goes-public&quot;&gt;described previously&lt;/a&gt; metadocuments are documents that describe document&#8217;s essense &lt;strong&gt;and&lt;/strong&gt; Ruby modules to extend Document&#8217;s behavior.&lt;/p&gt;


	&lt;p&gt;In the above code, I am defining User meta, which have only one method #to_s, which will render slot &#8216;name&#8217;.&lt;/p&gt;


	&lt;p&gt;Now, a little bit more complex example:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
Buyer = StrokeDB::Meta.new do

  on_initialization do |buyer|
    unless buyer[:balance]
      puts &quot;Providing $100 to #{buyer}, since he is a new buyer&quot; 
      buyer.balance = 100 
    end
    unless buyer[:products_bought]
      buyer.products_bought = []
    end
  end

  after_save do |buyer|
    puts &quot;Now #{buyer} has #{buyer.products_bought.empty? ? 'nothing' : buyer.products_bought.map(&#38;:name).to_sentence} (and his balance is $#{buyer.balance})&quot; 
  end

  def buy!(product)
    puts &quot;#{self} is buying #{product}&quot; 
    product.checkout!
    self.products_bought &amp;lt;&amp;lt; product
    self.balance -= product.price
    save!
  end
end
&lt;/pre&gt;
&lt;/code&gt;

	&lt;p&gt;Buyer is another metadocument that defines Buyer-specific functionality. Besides #buy! method it defines two callbacks: on_initialization and after_save. Their names are pretty self-descriptive (I hope)&lt;/p&gt;


	&lt;p&gt;And here is a last metadocument:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
Product = StrokeDB::Meta.new do
  after_save do |product|
    puts &quot;#{product.quantity} items of #{product} left&quot; 
  end

  def to_s
    &quot;'#{name}' for $#{price}&quot; 
  end

  def checkout!
    self.quantity -= 1
    save!
  end
end
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Nothing really new comparing to Buyer. So lets go further.&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
u = User.new(:name =&amp;gt; &quot;Yurii&quot;)
u.metas &amp;lt;&amp;lt; Buyer
u.save!
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Here I create a document with meta &#8216;User&#8217; &lt;strong&gt;and&lt;/strong&gt; add &#8216;Buyer&#8217; meta to it, so it is both User and Buyer at the same time!&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
apple = Product.create!(:name =&amp;gt; &quot;green apple&quot;, :price =&amp;gt; 2,:quantity =&amp;gt; 100)
pizza = Product.create!(:name =&amp;gt; &quot;big pizza&quot;, :price =&amp;gt; 15,:quantity =&amp;gt; 5)
u.buy!(apple)
u.buy!(pizza)
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;In the above lines I create two products, apple and pizza and use Buyer&#8217;s #buy! method to purchase them.&lt;/p&gt;


	&lt;p&gt;Here is an output of this test code:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
Providing $100 to Yurii, since he is a new buyer
Now Yurii has nothing (and his balance is $100)
100 items of 'green apple' for $2 left
5 items of 'big pizza' for $15 left
Yurii is buying 'green apple' for $2
99 items of 'green apple' for $2 left
Now Yurii has green apple (and his balance is $98)
Yurii is buying 'big pizza' for $15
4 items of 'big pizza' for $15 left
Now Yurii has green apple and big pizza (and his balance is $83)
&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Here we are, everything works!&lt;/p&gt;


	&lt;p&gt;Also, if you&#8217;ll inspect user&#8217;s document, you&#8217;ll see the following:&lt;/p&gt;


&lt;pre&gt;
&lt;code&gt;
#&amp;lt;{User,Buyer} name: &quot;Yurii&quot;, __version__: c33e..., products_bought: [#&amp;lt;{Product} name: &quot;green apple&quot;, __version__: 933e..., price: 2, quantity: 99, __previous_version__: 733e...&amp;gt;, #&amp;lt;{Product} name: &quot;big pizza&quot;, __version__: b33e..., price: 15, quantity: 4, __previous_version__: 833e...&amp;gt;], __previous_version__: a33e..., balance: 83&amp;gt;

&lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Notice that in the beginning, it is defined as {User,Buyer} — both metas are displayed. This way you can easily understand what this document is actually.&lt;/p&gt;


	&lt;p&gt;Ok, I hope that&#8217;s enough for the beginning. You can see complete test source code at &lt;a href=&quot;http://gitorious.org/projects/strokedb/repos/mainline/blob/8ce8edb9846ca52a7bacc84420ef23afc3cf5cd7/strokedb-ruby/test/playing3.rb&quot;&gt;Gitorious&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Also I would like to mention that we&#8217;ve &lt;a href=&quot;http://groups.google.com/group/strokedb/browse_thread/thread/e4b22c6f6889f91c&quot;&gt;added test console recently&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://groups.google.com/group/strokedb&quot;&gt;Join our mailing list&lt;/a&gt;
&lt;a href=&quot;http://gitorious.org/projects/strokedb/repos/mainline&quot;&gt;or get source code&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;P.S. I need to warn you: StrokeDB is quite immature, definitely has bugs and definitely will evolve. Period.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-02-11:4473</id>
    <published>2008-02-11T12:50:00Z</published>
    <updated>2008-02-11T15:53:17Z</updated>
    <link href="http://rashkovskii.com/articles/2008/2/11/strokedb-persistable-incremental-views" rel="alternate" type="text/html"/>
    <title>StrokeDB persistable incremental views</title>
<content type="html">
            &lt;p&gt;This weekend StrokeDB got so called &#8220;persistable incremental views&#8221;. What is this?&lt;/p&gt;


	&lt;p&gt;Well, lets start from View concept. It is basically a map-reduce filter with map and reduce functions defined in Ruby.&lt;/p&gt;


	&lt;p&gt;By default, it maps all documents and lets you reduce them (lets say we want to find users with age &amp;gt; 21):&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
   my_view = View.create!(:name =&amp;gt; &quot;my view&quot;).reduce_with {|doc| doc.is_a?(User) &#38;&#38; doc.age &amp;gt; 21 }
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Or, you can specify your own map block (if you need to create new documents set to be reduced):&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
   my_view = View.create!(:name =&amp;gt; &quot;my view&quot;).map_with do |doc|
                     new_doc = Document.create!(:doc =&amp;gt; doc)
   end.reduce_with {|doc| doc.doc.is_a?(User) &#38;&#38; doc.doc.age &amp;gt; 21 }
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;To get results, simply use&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
  my_view.emit.to_a # or my_view.emit.documents, that's the same
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;Okay, that&#8217;s simple. We map documents to documents and then reducing them using some criteria. Also I would like to mention that Views could be argument-polymorphic. If you&#8217;ll define your map and reduce blocks having more than one argument, you can emit results using some parameters:&lt;/p&gt;


&lt;pre&gt;
 &lt;code&gt;
   my_view = View.create!(:name =&amp;gt; &quot;my view&quot;).reduce_with {|doc,age| doc.is_a?(User) &#38;&#38; doc.age &amp;gt; age }
   my_view.emit(21).to_a
 &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;I think that&#8217;s simple and nice :)&lt;/p&gt;


Now incremental views come in. When you call &lt;code&gt;my_view.emit&lt;/code&gt; View emits first &#8220;view cut&#8221; which is a set of documents map/reduced for the whole database. Now, you can use this view cut to get new view updates:

 &lt;pre&gt;
   &lt;code&gt;
     first_cut = my_view.emit 
     # ... work with database, add some new documents, update old documents
     next_cut = first_cut.emit
   &lt;/code&gt;
&lt;/pre&gt;

	&lt;p&gt;next_cut view cut will contain only newly created/updated documents — so, you get updates incrementally.&lt;/p&gt;


	&lt;p&gt;Now, what about persistency declared above? That&#8217;s really simple — View and ViewCut are documents themselves — so you can easily save them and reuse later!&lt;/p&gt;


	&lt;p&gt;P.S. Currently Views are pretty slow — but things will change hopefully&lt;/p&gt;


	&lt;p&gt;P.P.S. Incremental views are really, really young in StrokeDB so I can&#8217;t promise that they are bug-free. Also &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; isn&#8217;t stable by any means (yet!).&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://gitorious.org/projects/strokedb&quot;&gt;Get StrokeDB&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://rashkovskii.com/">
    <author>
      <name>yrashk</name>
    </author>
    <id>tag:rashkovskii.com,2008-02-08:4446</id>
    <published>2008-02-08T09:25:00Z</published>
    <updated>2008-02-08T09:32:02Z</updated>
    <link href="http://rashkovskii.com/articles/2008/2/8/nyc-yrashk" rel="alternate" type="text/html"/>
    <title>nyc &lt;&lt; yrashk</title>
<content type="html">
            &lt;p&gt;By the way, I will be in New York City (and may be some other cities) on Feb 17-26. I&#8217;d be happy to talk about funny things (document databases, Ruby on Rails, etc.), drink some tea, etc. with somebody who enjoy this stuff too!&lt;/p&gt;
          </content>  </entry>
</feed>
