Skip to content

Commit

Permalink
Add inspect_pk plugin to make it easier to retrieve model instance ba…
Browse files Browse the repository at this point in the history
…sed on inspect output
  • Loading branch information
jeremyevans committed Nov 8, 2024
1 parent d20c40d commit 0bda470
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Add inspect_pk plugin to make it easier to retrieve model instance based on inspect output (jeremyevans)

* Treat all Trilogy errors with error code 1205 as Sequel::DatabaseLockTimeout in the trilogy adapter (jeremyevans)

* Allow Data{base,set}#extension to not require files if the extension is already registered (jeremyevans) (#2246)
Expand Down
9 changes: 7 additions & 2 deletions lib/sequel/model/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1311,7 +1311,7 @@ def id
# Returns a string representation of the model instance including
# the class name and values.
def inspect
"#<#{model.name} @values=#{inspect_values}>"
"#<#{inspect_prefix} @values=#{inspect_values}>"
end

# Returns the keys in +values+. May not include all column names.
Expand Down Expand Up @@ -1994,7 +1994,12 @@ def initialize_set(h)
set(h) unless h.empty?
end

# Default inspection output for the values hash, overwrite to change what #inspect displays.
# Default inspect output for the inspect, by default, just showing the class.
def inspect_prefix
model.name
end

# Default inspect output for the values hash, overwrite to change what #inspect displays.
def inspect_values
@values.inspect
end
Expand Down
44 changes: 44 additions & 0 deletions lib/sequel/plugins/inspect_pk.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen-string-literal: true

module Sequel
module Plugins
# The inspect_pk plugin includes the pk right next to the
# model name in inspect, allowing for easily copying and
# pasting to retrieve a copy of the object:
#
# Album.with_pk(1).inspect
# # default: #<Album @values={...}>
# # with inspect_pk: #<Album[1] @values={...}>
#
# Usage:
#
# # Make all model instances include pk in inspect output
# Sequel::Model.plugin :inspect_pk
#
# # Make Album instances include pk in inspect output
# Album.plugin :inspect_pk
module InspectPk
module InstanceMethods
private

# The primary key value to include in the inspect output, if any.
# For composite primary keys, this only includes a value if all
# fields are present.
def inspect_pk
if primary_key && (pk = self.pk) && (!(Array === pk) || pk.all?)
pk
end
end

# Include the instance's primary key in the output.
def inspect_prefix
if v = inspect_pk
"#{super}[#{v.inspect}]"
else
super
end
end
end
end
end
end
45 changes: 45 additions & 0 deletions spec/extensions/inspect_pk_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require_relative "spec_helper"

describe "inspect_pk plugin" do
def inspect(vals={}, &block)
Class.new(Sequel::Model) do
def self.name; 'M' end
plugin :inspect_pk
set_dataset DB.dataset
class_exec(&block) if block
columns(*vals.keys)
unrestrict_primary_key
end.new(vals).inspect
end

it "should not include primary key value if model does not have primary key" do
inspect(id: 1){no_primary_key}.must_equal "#<M @values=#{{:id=>1}.inspect}>"
end

it "should not include primary key value if model has scalar primary key and instance does not have primary key value" do
inspect{set_primary_key :id}.must_equal "#<M @values={}>"
end

it "should not include primary key value if model instance has composite primary key and instance does not have values for all primary key components" do
[{id1: 1, id2: nil}, {id1: nil, id2: 2}, {id1: nil, id2: nil}].each do |vals|
inspect(vals){set_primary_key [:id1, :id2]}.must_equal "#<M @values=#{vals.inspect}>"
end
end

it "should include primary value for scalar primary key if present" do
inspect(id: 1){set_primary_key :id}.must_equal "#<M[1] @values=#{{id: 1}.inspect}>"
end

it "should include primary value for composite primary key if all fields present" do
vals = {id1: 1, id2: 2}
inspect(vals){set_primary_key [:id1, :id2]}.must_equal "#<M[[1, 2]] @values=#{vals.inspect}>"
end

it "should use inspect value of primary key" do
inspect(id: "1"){}.must_equal "#<M[\"1\"] @values=#{{id: "1"}.inspect}>"
end

it "should use inspect_pk method to get inspect pk value" do
inspect{def inspect_pk; "2" end}.must_equal "#<M[\"2\"] @values={}>"
end
end
4 changes: 4 additions & 0 deletions www/pages/plugins.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,10 @@
<span class="ul__span">Adds Model.finder and Model.prepared_finder methods for defining optimized lookup methods.</span>
</li>
<li class="ul__li ul__li--grid">
<a class="a" href="rdoc-plugins/classes/Sequel/Plugins/InspectPk.html">inspect_pk </a>
<span class="ul__span">Makes it easier to retrieve model instance based on inspect output.</span>
</li>
<li class="ul__li ul__li--grid">
<a class="a" href="rdoc-plugins/classes/Sequel/Plugins/List.html">list </a>
<span class="ul__span">Allows you to treat model objects as being part of a list, so you can move them up/down and get next/previous entries.</span>
</li>
Expand Down

0 comments on commit 0bda470

Please sign in to comment.