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

Add retrieving list of versions support #238

Merged
merged 4 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## master (unreleased)

- Add retrieving list of versions support. ([@tagirahmad][])

- Add `--after-trigger` option to generate _after_ triggers for partitioned tables in older PostgreSQL versions. ([@SparLaimor][], [@prog-supdex][], [@palkan][])

- **Breaking**. Ruby 2.7, Rails 6.0, PostgreSQL 10.0+ are required.
Expand Down Expand Up @@ -383,3 +385,4 @@ This is a quick fix for a more general problem (see [#59](https://github.com/pal
[@miharekar]: https://github.com/miharekar
[@prog-supdex]: https://github.com/prog-supdex
[@SparLaimor]: https://github.com/SparLaimor
[@tagirahmad]: https://github.com/tagirahmad
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,25 @@ Post.where(created_at: Time.zone.today.all_day).diff_from(time: 1.hour.ago)

**NOTE:** If `log_data` is nil, `#diff_from` returns an empty Hash as `"changes"`.

Also, it is possible to retrieve list of model's `versions`:

```ruby
post.versions # => Enumerator

# you can use Enumerator's #take to return all
post.versions.take

# or you take a few or call any Enumerable method
post.versions.take(2)
post.versions.find do
_1.title == "old title"
end

# we can also add options
post.versions(reverse: true) # from older to newer
post.versions(include_self: true) # returns self as the first one (default) or the last one record (if reverse: true)
```

There are also `#undo!` and `#redo!` options (and more general `#switch_to!`):

```ruby
Expand Down
14 changes: 14 additions & 0 deletions lib/logidze/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ def at(time: nil, version: nil)

build_dup(log_entry, time)
end

def logidze_versions(reverse: false, include_self: false)
versions_meta = log_data.versions.dup

if reverse
versions_meta.reverse!
versions_meta.shift unless include_self
else
versions_meta.pop unless include_self
end

Enumerator.new { |yielder| versions_meta.each { yielder << at(version: _1.version) } }
end

# rubocop: enable Metrics/MethodLength

# Revert record to the version at specified time (without saving to DB)
Expand Down
43 changes: 43 additions & 0 deletions spec/logidze/model_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,49 @@
end
end

describe "#logidze_versions" do
it "returns enumerator of versions" do
expect(user.logidze_versions).to be_a Enumerator
end

it "can take few versions" do
expect(user.logidze_versions.take(2)).to be_a Array
expect(user.logidze_versions.take(2).size).to eq 2
expect(user.logidze_versions.take(3).size).to eq 3
end

it "can find by attribute" do
expect(user.logidze_versions.find { _1.name == "test" }.log_version).to eq 3
expect(user.logidze_versions(include_self: true).find { _1.age == 10 }.log_version).to eq 5
end

context "when options are provided" do
it "returns versions except current version if include_self is false and reverse is true" do
expect(user.logidze_versions(reverse: true, include_self: false).to_a.size).to eq user.log_data.versions.size - 1
expect(user.logidze_versions(reverse: true, include_self: false).first)
.to eq user.at(version: user.log_data.versions[-2].version)
end

it "returns versions except current version if include_self is false and reverse is false" do
expect(user.logidze_versions(reverse: false, include_self: false).to_a.size).to eq user.log_data.versions.size - 1
expect(user.logidze_versions(reverse: false, include_self: false).first)
.to eq user.at(version: user.log_data.versions.first.version)
end

it "returns all the versions if include_self is true and current version is first if reverse is true" do
expect(user.logidze_versions(reverse: true, include_self: true).to_a.size).to eq user.log_data.versions.size
expect(user.logidze_versions(reverse: true, include_self: true).first)
.to eq user.at(version: user.log_data.versions.last.version)
end

it "returns all the versions if include_self is true and current version is last if reverse is false" do
expect(user.logidze_versions(reverse: false, include_self: true).to_a.size).to eq user.log_data.versions.size
expect(user.logidze_versions(reverse: false, include_self: true).to_a.last)
.to eq user.at(version: user.log_data.versions.last.version)
end
end
end

describe "#at!" do
it "update object in-place", :aggregate_failures do
user.at!(time: time(350))
Expand Down
Loading