Code Monkey home page Code Monkey logo

Comments (26)

jodosha avatar jodosha commented on May 26, 2024

@joneslee85 πŸ‘

By looking at that module, I'm not sure if it can be reused for the purpose. It uses low level Sequel knowledge to update those timestamps. However, I guess we can easily code our own.

Your proposed API is per collection basis, which is great. At the low level Sql::Query and Sql::Collection instances don't have specific Ruby types. The design is different at the higher level where we have a concrete repository (Ruby type) per mapped collection.

In code:

Sql::Query.new(users_sql_collection).class # =>  always a Sql::Query instance
Sql::Query.new(books_sql_collection).class # => always a Sql::Query instance

vs

UserRepository # => concrete Ruby type
BookRepository # => concrete Ruby type

If we need a Ruby module to include somewhere, probably the candidate is a repository.

from model.

jodosha avatar jodosha commented on May 26, 2024

@joneslee85 Another candidate can be a coercer. We instantiate it one for each database table, when we load the mapped collection. We could inject the functionality there.

The advantage is to keep this functionality at the level of the Mapping::Collection. Because the proposed #timestamps API is local to that object.

If we expand #attribute with a :default option, we can easily implement this feature:

attribute :city, String, default: 'Rome'
attribute :delivered_at, Time, default: ->{ Time.now }
def timestamps
  attribute :updated_at, Time, default: -> { Time.now }
  attribute :created_at, Time, default: -> { Time.now }
end

What do you think?

from model.

runlevel5 avatar runlevel5 commented on May 26, 2024

@jodosha brilliant idea on the coercer. +1 for the latter suggestion

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

πŸ‘

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

should default option saved in database or if the value is null return the default option?

from model.

jodosha avatar jodosha commented on May 26, 2024

@AlfonsoUceda Can you please expand your question, not sure to have understood it well. Sorry.

from model.

jodosha avatar jodosha commented on May 26, 2024

@joneslee85 Mr @AlfonsoUceda made me think about one thing: repository and coercer don't set the expected data on an entity 😒

For instance, if we have an age attribute as integer, when we persist an User, the repository returns an entity slightly changed. Only the id attribute is set.

u = User.new(age: '32')
u = UserRepository.persist(u)

u.id # => 1
u.age # => "32" - WRONG, we expected an integer here.

So I'm afraid that if we implement timestamps via coercer the following sync problem will happen:

u = User.new(name: 'Luca')
UserRepository.persist(u) # => this operation will persist `created_at` and `updated_at` in the database

u.created_at # => nil - WRONG, it should return that timestamp.

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

Yes, it should be available in entity too

about defualt option in mapper I think it could be another issue, expanding my question, suppose we have this mapper:

Suppose we have this mapper:

 mapper = Lotus::Model::Mapper.new do
   collection :users do
     entity User

     attribute :id,   Integer
     attribute :name, String
     attribute :admin, Boolean, default: -> { false }
   end
 end

 u = User.new(name: 'Luca', admin: true)
 UserRepository.persist(u)
 u.admin #=> true

 u = User.new(name: 'Luca')
 UserRepository.persist(u)
 u.admin #=> should be false instead nil, isn't it?

from model.

jodosha avatar jodosha commented on May 26, 2024

@AlfonsoUceda yes.

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

ok ;)

from model.

runlevel5 avatar runlevel5 commented on May 26, 2024

@jodosha you catch a very good case there. What do you think about auto-reload entity after repository persist it?

from model.

jodosha avatar jodosha commented on May 26, 2024

@joneslee85 Doing this via coercer is a bad idea :( It can work when the value is nil (created_at on a non-persisted entity). But when it comes to update an already existing timestamp (updated_at), it won't replace it with a default value.

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

I think the default option should be in the migrations and not in the coercer, but I am thinking the migrations are only available for SQL, and in the memory or file adapter this can't be achieved :S

The created_at set when before the entity is created and the updated_at before any modification but what is the correct place to do this?

from model.

angeloashmore avatar angeloashmore commented on May 26, 2024

@AlfonsoUceda Right, migration-less/schema-less databases (e.g. a JSON store) don't have default values or types. Although there are ways to coerce data to certain data types natively within some of these databases, not every database has that functionality. It would have to take place at the application level.

Is there a reason #create only updates the id versus the whole entity reference? My guess is because the database interface only returns that value upon creation?

# sql_adapter.rb
def create(collection, entity)
  entity.id = command(
                query(collection)
              ).create(entity)
  entity
end

from model.

jodosha avatar jodosha commented on May 26, 2024

@AlfonsoUceda @angeloashmore This isn't only a matter of schema(less) databases. If a column isn't mapped it's entirely ignored by the framework.

@angeloashmore RE entity: that is my fault. I'm sorry. I already discussed with @joneslee85 about this problem. You have opened a ticket for this, let's discuss over there.

from model.

angeloashmore avatar angeloashmore commented on May 26, 2024

It appears the Repository is the best place for this to happen. Maintaining timestamps should occur at #persist.

I wrote this quick module and it seems to work. I haven't written any tests for it yet, however.

https://gist.github.com/angeloashmore/05ef7f035f694cfa56d7

Required setup

  1. The database must accept created_at and updated_at.
  2. The entity must respond to #created_at= and #updated_at=.
  3. The repository must set created_at and updated_at before persisting/creating/updating. This is done by including Lotus::Repository::Timestamps.
  4. The mapper must include created_at and updated_at.
# order_repository.rb
class OrderRepository
  include Lotus::Repository
  include Lotus::Repository::Timestamps
end
# mapping.rb
mapping do
  collection :orders do
    entity Order

    attribute :id, String
    attribute :billing_info, Hash
    attribute :created_at, Time
    attribute :updated_at, Time
  end
end
# order.rb
class Order
  include Lotus::Entity
  attributes :billing_info, :created_at, :updated_at
end

Issues with this approach

Repetition

There is a lot of repetition of created_at and updated_at. Because of the way Repositories, Mappers, and Entities are separated, it seems it is necessary to declare the attributes in all places.

What do you think of having helper methods to automatically include this? You will still need to declare them everywhere, but as @joneslee85 suggested, it could turn this:

collection :orders do
  # ...
  attribute :created_at, Time
  attribute :updated_at, Time
end

…to this:

collection :orders do
  # ...
  timestamps
end

…and this:

class Order
  include Lotus::Entity
  attributes :billing_info, :created_at, :updated_at
end

…to this:

class Order
  include Lotus::Entity
  attributes :billing_info, timestamps
end

Entity equivalency

This will modify updated_at anytime #update is called even if the entity did not actually change.

For example:

order = OrderRepository.find(23)

order.billing_info #=> { address: '123 Some Street' }
order.updated_at #=> 2015-02-20 10:00:00 UTC

order.billing_info = { address: '123 Some Street' } # what it already is
OrderRepository.persist(order)

order.updated_at #=> 2015-02-20 10:20:35 UTC

How will the repository know if the entity was actually modified? One possible solution: http://stackoverflow.com/a/1964155

from model.

jodosha avatar jodosha commented on May 26, 2024

@angeloashmore Thanks for the detailed investigation. I apologize for the late reply.

I do agree that there is a lot of repetition. I suggest to make it work and then to make it DRY. Would you love to craft a PR based on that gist? Thank you very much!

from model.

dsnipe avatar dsnipe commented on May 26, 2024

Is anybody works on this feature?
I can do task based on a proposed solution and then continue implementing this feature, if not.

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

@dsnipe there isn't someone working on this, please feel free ;)

from model.

dsnipe avatar dsnipe commented on May 26, 2024

@AlfonsoUceda cool :)
so, I done with provided gist in PR #169
My plan is:

  • Implement timestamps helpers for mapper and entity
  • Equivalency for entities. We can use https://github.com/dkubb/equalizer or create our own solution to avoid dependency.

from model.

AlfonsoUceda avatar AlfonsoUceda commented on May 26, 2024

avoid new dependencies please, create a custom solution for lotus ;)

thanks!
El 01/04/2015 15:52, "Dmitry Tymchuk" [email protected] escribiΓ³:

@AlfonsoUceda https://github.com/AlfonsoUceda cool :)
so, I done with provided gist in PR
My plan is:

  • Implement timestamps helpers for mapper and entity
  • Equivalency for entities. We can use
    https://github.com/dkubb/equalizer or create our own solution to avoid
    dependency.

Reply to this email directly or view it on GitHub
#134 (comment).

from model.

dsnipe avatar dsnipe commented on May 26, 2024

After creating draft for timestamp implementation, I realised, that may be better place for defining timestamps will be in configuration.

Global defining for all entities

Lotus::Model.configure do
  timestamps :all
end

Global defining with exceptions

Lotus::Model.configure do
  timestamps :all, exclude: ['Admin', 'Moderator']
end

Defining timestamps only for specific entities

Lotus::Model.configure do
  timestamps ['User', 'Article', 'Blog']   # not sure about it
end

It gives ability to manage timestamps from one place and generate migrations already with needed columns.
What are think about it?

from model.

runlevel5 avatar runlevel5 commented on May 26, 2024

IMHO I think your suggestion is over killing for I don't find much gains in doing so. I'd rather let users self-define in their entity for sake of consistency and simplicity. Just my 5cent

from model.

dsnipe avatar dsnipe commented on May 26, 2024

@joneslee85 actually I used timestamps almost on all entities usually. Thats why I suggest using it in global scope.
but maybe you're right and simplest way is a better way :) I'll finish #169
btw, I see some duplication of functionality in #167 and this one – there are any reasons that both solutions are necessary?

from model.

runlevel5 avatar runlevel5 commented on May 26, 2024

@dsnipe much thanks, regarding #167, it is overlapping, however I'd like to ask you to wait for TeamLeo who is now working on it. πŸ‘

from model.

jodosha avatar jodosha commented on May 26, 2024

Implemented by #173 #176 #182

from model.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.