bbkr/mongo-perl6-driver — Issue #1: Object-to-Wire model discussion
Author: bbkr
Created: 2011-11-23 22:40:07+00:00
State: open

At the early stage of development of Mongo DB Perl 6 driver I stepped into the same problem that every language solved differently - how to separate Wire document(s) from Wire options.

For example

1. Python flattens everything in huge messy list of params

insert(doc_or_docs[, manipulate=True[, safe=False[, check_keys=True[, **kwargs]]]])

find([spec=None[, fields=None[, skip=0[, limit=0[, timeout=True[, snapshot=False[, tailable=False[, sort=None[, max_scan=None[, as_class=None[, slave_okay=False[, await_data=False[, partial=False[, manipulate=True[, **kwargs]]]]]]]]]]]]]]])

2. Perl 5 is inconsistent, because it sometimes flattens

$coll->insert({ name => 'mongo', type => 'database' }, {safe => 1});

and sometimes chains

$cursor = $coll->query->limit($per_page)->skip($page_num * $per_page);

making it hard to understand type of object returned and when actual query to database takes place.

3. Perl 6 gives tons of new capabilities when it comes to method signatures, overloading and dispatching. Logic behind my idea of interface is that I want to keep simple things simple.

For example $collection.insert( %document1, %document2 ) is the most natural way of inserting multiple documents (note that Perl 6 does not flatten it the same way as Perl 5).

However slurpy parameters must appear last, and that would require placing options before them
$collection.insert(:continue_on_error, %document1, %document2) # note the bool flags in Perl 6
or giving up on them
$collection.insert( [%document1, %document2], :continue_on_error)
and this array wrapping I personally dislike.

In my humble opinion closures are the way to go. Some examples:

$collection.insert(:continue_on_error).(%document1, %document2)
or without options
$collection.insert.(%document1, %document2)
or reuse closure
my $feeder = $collection.insert(:continue_on_error);
$feeder.(%document1, %document2)
$feeder.(%document3)

my $cursor = $collection.find(limit=>20, fields=>['name', 'age'] ).()
yes, this is correct, many problems are solved if cursor object instance is returned from closure, not directly from collection
$collection.find.(nick=>'bbkr')
throwing options to closure removes nasty hash wrapping here, this is my nice-to-have

Benefits:
- closures are fast, whole Perl 6 is closure based
- closures allow to "BSONize" some parts of Wire protocol fields and reuse them changing only %document(s)
- your query is executed when closure is executed, clear rules on that

Problems:
- many users will forget to call closure, but since we have awesome where{} blocks in subroutine signatures we can detect $collection.insert( %document1, %document2 ) case and assume one wants $collection.insert.( %document1, %document2 ) with very small performance impact, beginners will be happy, hackers can still use Wire options.

Please share your thoughts.