On Thursday, March 2, 2017 at 2:26:20 PM UTC-8, Mike Pastore wrote:
>
> On Monday, February 27, 2017 at 4:25:15 PM UTC-6, Jeremy Evans wrote:
>>
>> On Monday, February 27, 2017 at 1:05:34 PM UTC-8, Mike Pastore wrote:
>>>
>>>
>>>    - Do you have any thoughts on the best way to freeze/thaw a 
>>>    Sequel::Dataset instance? Is capturing the emitted SQL good enough?
>>>
>>> There can be state other than the emitted SQL, at least in some cases. 
>>
>
> Can you elaborate at all? Is there a way to capture the state in most 
> cases and ship it to another Ruby process with its own Sequel connection?
>

Sequel makes heavy use of extended modules/singleton classes in datasets, 
and some of those effect the results, even with the same SQL used.  For 
example, see the graph_each extension.  It's not possible to serialize all 
datasets as they can contain unmarshallable state.

I think capturing the SQL and using it will probably work for "most cases". 
 However, I don't think it will work for all cases.
 

>  
>
>>
>>>    - Any other implementation thoughts? Can you recommend a 
>>>    plugin/extension I can crib from as an example?
>>>
>>> Sequel wasn't really designed for this.  Instead of modifying Sequel to 
>> support this, you may want to consider building something on top of Sequel 
>> that does this instead.  Alternatively, you may want to implement a custom 
>> adapter that does this.  It is possible to implement what you want via an 
>> extension, at least in simple cases, but while the API may be nicer, it 
>> seems more likely to lead to implementation issues.
>>
>
> I can understand that. At the same time, event-sourcing and CQRS are 
> growing in popularity, for good reason, and the easier it is for people to 
> adapt their Sequel-based applications to that pattern, the more people will 
> be able and willing to use (or keep using) Sequel. A simple way to stream 
> "events" generated using the same-or-similar syntax as normal database 
> calls—whether those are serialized datasets or something else 
> entirely—would go a long way towards addressing this need. 
>
> I think a separate adapter (for 0MQ or what have you) makes sense since 
> what you're really doing is "executing" queries by serializing them and 
> sending them off. What you would need is a way to specify which queries use 
> which connection, similar to Sequel::Dataset#server, but with the ability 
> for the different servers to be using different adapters. For example:
>
> user1, user2 = User.first(2) # uses DB (sync)
> user1.update(:foo=>'bar') # uses DB (sync)
> user2.server(:cqrs).update(:foo=>'qux') # uses MQ (async)
>
> Or I suppose you could just set up sharding to use DB as :read_only and MQ 
> as :default.
>
> Anyway, I appreciate your time and thought on this, and will take whatever 
> other feedback you have to offer, if any, and try to cook something up. 
> Thanks Jeremy.
>

Unfortunately, I'm probably not the best person to comment on this.  I 
don't use event-sourcing or CQRS in the applications I work on, as I don't 
think the benefits are worth the added complexity.

I can say that Sequel was not designed with CQRS in mind.  Core Sequel is a 
generic database access layer in which datasets allow both querying and 
insert/update/delete methods, and Sequel::Model uses the ActiveRecord 
pattern that combines querying and insert/update/delete methods on the same 
object. I think the main way Sequel would fit into a CQRS system is using 
core Sequel as the database backend that both the Query Model and Command 
Model parts of CQRS would use to communicate with the database.  I think 
ROM may operate like that looking at its documentation, and it uses Sequel 
as the backend for SQL databases.

In terms of event sourcing, it's basically just an append-only approach to 
database structure (events being append only).  Both core Sequel and 
Sequel::Model can be used with an event sourcing approach. I will admit 
that I do not fully understand how event-sourcing implies the use of a 
queuing library like 0MQ, or why you wouldn't want to do:

user1, user2 = User.first(2) # uses DB (sync)
user1.update(:foo=>'bar') # uses DB (sync)
CqrsAsyncFactoryFactory.new.new.new(:model=>:User, :id=>user2.id, 
:action=>:update, :atttributes=>{:foo=>'qux'}).call # uses MQ (async), just 
kidding about FactoryFactory.new.new

And then have Sequel (or a library written in another language) handle the 
event after getting the data from 0MQ.  I guess in other words, what's the 
benefit of queuing just the SQL, as opposed to queuing the abstract change 
you want to make?

If you really did want to just want to ship the SQL for a query, maybe 
overriding the Dataset#execute* methods to do something like:

def execute(sql, opts={})
  if @opts[:server] == :cqrs
    CqrsAyncSql.new(sql).call
    nil
  else
    super
  end
end

That may work as long as you don't care about the results of the method. 
 Something like that would work with the API you proposed.

Thanks,
Jeremy

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.

Reply via email to