Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GlobalID support #111

Open
halostatue opened this issue May 18, 2016 · 2 comments
Open

GlobalID support #111

halostatue opened this issue May 18, 2016 · 2 comments

Comments

@halostatue
Copy link

Sequel doesn’t follow the same protocol as ActiveRecord, even when ActiveModel compliant (or so it seems). I’ve come up with what looks like the right level of monkey-patching for this, and can turn this into a real patch (with tests) for GlobalID if there is interest. The changes are only necessary in GlobalID::Locator::BaseLocator for #locate and #find_records.

The only other change is including GlobalID::Identification into Sequel::Model, but in my basic testing, these changes create the same result as AR-backed GlobalID, mod the appropriate exceptions. If we want to make a real patch out of this, then we should probably make a plugin so that we can do Sequel::Model.plugin :globalid for explicit opt-in.

This has also been opened as rails/globalid#87.

module SequelBaseLocator
  def locate(gid)
    if defined?(::Sequel::Model) && gid.model_class < Sequel::Model
      gid.model_class.with_pk!(gid.model_id)
    else
      super
    end
  end

  private

  def find_records(model_class, ids, options)
    if defined?(::Sequel::Model) && model_class < Sequel::Model
      model_class.where(model_class.primary_key => ids).tap do |result|
        if !options[:ignore_missing] && result.count < ids.size
          fail Sequel::NoMatchingRow
        end
      end.all
    else
      super
    end
  end
end

GlobalID::Locator::BaseLocator.prepend SequelBaseLocator
Sequel::Model.send(:include, ::GlobalID::Identification)
@Aryk
Copy link

Aryk commented Apr 17, 2020

Nice work!

I packaged it into a plugin for anyone interested:

module Sequel
  module Plugins
    module GlobalId

      # Add Global ID support for Sequel::Models
      # Code comes @halostatue from https://github.com/TalentBox/sequel-rails/issues/111
      def self.apply(base, *)
        base.send(:include, ::GlobalID::Identification)
        GlobalID::Locator::BaseLocator.prepend SequelBaseLocator
      end

      module SequelBaseLocator
        def locate(gid)
          if defined?(::Sequel::Model) && gid.model_class < Sequel::Model
            gid.model_class.with_pk!(gid.model_id)
          else
            super
          end
        end

        private

        def find_records(model_class, ids, options)
          if defined?(::Sequel::Model) && model_class < Sequel::Model
            model_class.where(model_class.primary_key => ids).tap do |result|
              if !options[:ignore_missing] && result.count < ids.size
                fail Sequel::NoMatchingRow
              end
            end.all
          else
            super
          end
        end
      end

    end
  end
end

@qnm
Copy link

qnm commented Oct 31, 2023

For anyone else finding this, the API for locate has changed a little: https://github.com/rails/globalid#custom-app-locator

The new plugin would be something like:

module Sequel
  module Plugins
    module GlobalId

      # Add Global ID support for Sequel::Models
      # Code comes @halostatue from https://github.com/TalentBox/sequel-rails/issues/111
      def self.apply(base, *)
        base.send(:include, ::GlobalID::Identification)
        GlobalID::Locator::BaseLocator.prepend SequelBaseLocator
      end

      module SequelBaseLocator
        def locate(gid, options = {})
          if defined?(::Sequel::Model) && gid.model_class < Sequel::Model
            gid.model_class.with_pk!(gid.model_id)
          else
            super
          end
        end

        private

        def find_records(model_class, ids, options)
          if defined?(::Sequel::Model) && model_class < Sequel::Model
            model_class.where(model_class.primary_key => ids).tap do |result|
              if !options[:ignore_missing] && result.count < ids.size
                fail Sequel::NoMatchingRow
              end
            end.all
          else
            super
          end
        end
      end

    end
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants