db_memoize 0.2.3 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +7 -15
- data/.travis.yml +4 -2
- data/README.md +2 -0
- data/Rakefile +13 -4
- data/VERSION +1 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/db_memoize.gemspec +8 -14
- data/lib/db_memoize.rb +0 -1
- data/lib/db_memoize/helpers.rb +0 -12
- data/lib/db_memoize/migrations.rb +21 -1
- data/lib/db_memoize/model.rb +27 -36
- data/lib/db_memoize/value.rb +57 -2
- data/lib/db_memoize/version.rb +22 -1
- data/scripts/release +2 -0
- data/scripts/release.rb +93 -0
- metadata +36 -95
- data/lib/db_memoize/metal.rb +0 -127
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '095aec4c4352df19e1a55ee270414a18b240e6135733e5871d5f766dd6789077'
|
4
|
+
data.tar.gz: d9ee2695e76c0611f23aa3cfe7c8afa82ff09f04d5de1acf525d2570099b2428
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50af7b39e3aed56fa829b940f4c0251c0d49fef89306a38f7f6aa69ab7c6dfecb677646869eb076c155f9fbc69abc9a6bba3d37ea57d4582b0a0465433d90a11
|
7
|
+
data.tar.gz: 97e18054c9914f961c97796650f47fff3aca4e74066f6dbe53b420633719bb7ec0f3f8354c7d2e19c11e93b864192894e538204b9bf57626fbeda427734af19c
|
data/.rubocop.yml
CHANGED
@@ -3,21 +3,13 @@ AllCops:
|
|
3
3
|
Include:
|
4
4
|
- Rakefile
|
5
5
|
- config.ru
|
6
|
+
- lib/**/*.rb
|
6
7
|
Exclude:
|
7
8
|
- Rakefile
|
8
9
|
- bin/*
|
9
10
|
- config.ru
|
10
11
|
- config/**/*
|
11
|
-
- db/**/*
|
12
|
-
- doc/**/*
|
13
|
-
- gems/**/*
|
14
|
-
- gems/*/vendor/**/*
|
15
|
-
- script/**/*
|
16
|
-
- sh/**/*
|
17
|
-
- spec/rails_helper.rb
|
18
|
-
- spec/spec_helper.rb
|
19
12
|
- vendor/**/*
|
20
|
-
- spec/support/v20140601/requests_helper.rb
|
21
13
|
|
22
14
|
Style/FrozenStringLiteralComment:
|
23
15
|
Enabled: false
|
@@ -25,12 +17,6 @@ Style/FrozenStringLiteralComment:
|
|
25
17
|
Metrics/LineLength:
|
26
18
|
Max: 140
|
27
19
|
|
28
|
-
Rails:
|
29
|
-
Enabled: true
|
30
|
-
|
31
|
-
Rails/HasAndBelongsToMany:
|
32
|
-
Enabled: false
|
33
|
-
|
34
20
|
Style/Documentation:
|
35
21
|
Enabled: false
|
36
22
|
|
@@ -66,3 +52,9 @@ Metrics/MethodLength:
|
|
66
52
|
# "Prefer !expression.nil? over expression != nil." no way!
|
67
53
|
Style/NonNilCheck:
|
68
54
|
Enabled: false
|
55
|
+
|
56
|
+
Style/SymbolArray:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
Lint/MissingCopEnableDirective:
|
60
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,11 +1,20 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
1
|
require "rspec/core/rake_task"
|
3
2
|
|
4
3
|
RSpec::Core::RakeTask.new(:spec)
|
5
4
|
|
6
|
-
task
|
7
|
-
Rake.sh
|
8
|
-
Rake.sh
|
5
|
+
task 'db:test:create' do
|
6
|
+
Rake.sh 'dropdb db_memoize_test -U postgres || true'
|
7
|
+
Rake.sh 'createdb db_memoize_test -U postgres'
|
9
8
|
end
|
10
9
|
|
11
10
|
task :default => %w(db:test:create spec)
|
11
|
+
|
12
|
+
desc "release a new development gem version"
|
13
|
+
task :release do
|
14
|
+
sh "scripts/release.rb"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "release a new stable gem version"
|
18
|
+
task "release:stable" do
|
19
|
+
sh "BRANCH=stable scripts/release.rb"
|
20
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.2
|
data/bin/rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/rspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rspec-core", "rspec")
|
data/bin/rubocop
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require "pathname"
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
13
|
+
Pathname.new(__FILE__).realpath)
|
14
|
+
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
16
|
+
|
17
|
+
if File.file?(bundle_binstub)
|
18
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
19
|
+
load(bundle_binstub)
|
20
|
+
else
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require "rubygems"
|
27
|
+
require "bundler/setup"
|
28
|
+
|
29
|
+
load Gem.bin_path("rubocop", "rubocop")
|
data/db_memoize.gemspec
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'db_memoize/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
6
|
spec.name = "db_memoize"
|
8
|
-
spec.version =
|
7
|
+
spec.version = File.read("VERSION")
|
9
8
|
spec.licenses = ['MIT']
|
10
9
|
spec.authors = ["johannes-kostas goetzinger"]
|
11
10
|
spec.email = ["goetzinger@mediapeers.com"]
|
@@ -21,20 +20,15 @@ Gem::Specification.new do |spec|
|
|
21
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
21
|
spec.require_paths = ['lib']
|
23
22
|
|
23
|
+
spec.add_dependency 'simple-sql', '>= 0.4.20', '~> 0'
|
24
24
|
spec.add_development_dependency 'railties', '~> 4.2'
|
25
|
-
spec.add_development_dependency 'activerecord', '~> 4.2'
|
25
|
+
spec.add_development_dependency 'activerecord', '~> 4.2.10'
|
26
26
|
|
27
|
-
spec.add_development_dependency 'rake', '~>
|
28
|
-
spec.add_development_dependency 'pg'
|
29
|
-
spec.add_development_dependency 'rspec
|
30
|
-
spec.add_development_dependency '
|
31
|
-
spec.add_development_dependency '
|
32
|
-
spec.add_development_dependency 'yard', '~> 0'
|
33
|
-
spec.add_development_dependency 'simplecov', '~> 0.7.1'
|
34
|
-
spec.add_development_dependency 'rubocop', '~> 0.37.2'
|
27
|
+
spec.add_development_dependency 'rake', '~> 12.0'
|
28
|
+
spec.add_development_dependency 'pg', '~> 0.20'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.8'
|
30
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
31
|
+
spec.add_development_dependency 'rubocop', '~> 0.59.2'
|
35
32
|
spec.add_development_dependency 'database_cleaner', '~> 1.5.3'
|
36
33
|
spec.add_development_dependency 'factory_girl', '~> 4.7.0'
|
37
|
-
spec.add_development_dependency 'ruby-progressbar', '~> 1.7'
|
38
|
-
spec.add_development_dependency 'awesome_print'
|
39
|
-
spec.add_development_dependency 'gem-release'
|
40
34
|
end
|
data/lib/db_memoize.rb
CHANGED
data/lib/db_memoize/helpers.rb
CHANGED
@@ -16,17 +16,5 @@ module DbMemoize
|
|
16
16
|
"DbMemoize <#{model.class.name}##{model.id}>##{method_name} - #{msg}"
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
20
|
-
def calculate_arguments_hash(arguments)
|
21
|
-
arguments.empty? ? nil : ::Digest::MD5.hexdigest(Marshal.dump(arguments))
|
22
|
-
end
|
23
|
-
|
24
|
-
def marshal(value)
|
25
|
-
Marshal.dump(value)
|
26
|
-
end
|
27
|
-
|
28
|
-
def unmarshal(value)
|
29
|
-
Marshal.load(value)
|
30
|
-
end
|
31
19
|
end
|
32
20
|
end
|
@@ -13,6 +13,8 @@ module DbMemoize
|
|
13
13
|
|
14
14
|
migration.add_index :memoized_values, [:entity_table_name, :entity_id]
|
15
15
|
migrate_empty_arguments_support(migration)
|
16
|
+
drop_arguments_support(migration)
|
17
|
+
add_discrete_value_columns(migration)
|
16
18
|
end
|
17
19
|
|
18
20
|
def migrate_empty_arguments_support(migration)
|
@@ -23,7 +25,25 @@ module DbMemoize
|
|
23
25
|
|
24
26
|
# add an index to be useful to look up entries where arguments_hash is NULL.
|
25
27
|
# (which is the case for plain attributes of an object)
|
26
|
-
migration.execute 'CREATE INDEX memoized_attributes_idx ON memoized_values((arguments_hash IS NULL))'
|
28
|
+
migration.execute 'CREATE INDEX IF NOT EXISTS memoized_attributes_idx ON memoized_values((arguments_hash IS NULL))'
|
29
|
+
end
|
30
|
+
|
31
|
+
def drop_arguments_support(migration)
|
32
|
+
migration.execute 'DROP INDEX IF EXISTS memoized_attributes_idx'
|
33
|
+
migration.execute 'ALTER TABLE memoized_values DROP COLUMN IF EXISTS arguments_hash'
|
34
|
+
|
35
|
+
migration.remove_index :memoized_values, [:entity_id, :entity_table_name]
|
36
|
+
migration.add_index :memoized_values, [:entity_id, :entity_table_name, :method_name], unique: true, name: 'memoized_attributes_idx2'
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_discrete_value_columns(migration)
|
40
|
+
migration.execute 'ALTER TABLE memoized_values ADD COLUMN IF NOT EXISTS val_string varchar'
|
41
|
+
migration.execute 'ALTER TABLE memoized_values ADD COLUMN IF NOT EXISTS val_integer bigint'
|
42
|
+
migration.execute 'ALTER TABLE memoized_values ADD COLUMN IF NOT EXISTS val_float double precision'
|
43
|
+
migration.execute 'ALTER TABLE memoized_values ADD COLUMN IF NOT EXISTS val_time timestamp without time zone'
|
44
|
+
migration.execute 'ALTER TABLE memoized_values ADD COLUMN IF NOT EXISTS val_boolean boolean'
|
45
|
+
migration.execute 'ALTER TABLE memoized_values ADD COLUMN IF NOT EXISTS val_object jsonb'
|
46
|
+
migration.execute 'ALTER TABLE memoized_values ADD COLUMN IF NOT EXISTS val_nil boolean'
|
27
47
|
end
|
28
48
|
end
|
29
49
|
end
|
data/lib/db_memoize/model.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
+
require 'simple-sql'
|
2
|
+
|
1
3
|
module DbMemoize
|
2
4
|
module Model
|
3
5
|
extend ActiveSupport::Concern
|
4
6
|
|
5
|
-
def memoized_value(method_name
|
6
|
-
|
7
|
-
|
8
|
-
end
|
7
|
+
def memoized_value(method_name)
|
8
|
+
memoizable = !changed? && persisted?
|
9
|
+
return send("#{method_name}_without_memoize") unless memoizable
|
9
10
|
|
10
11
|
value = nil
|
11
|
-
|
12
|
-
cached_value = find_memoized_value(method_name, args_hash)
|
12
|
+
cached_value = find_memoized_value(method_name)
|
13
13
|
|
14
14
|
if cached_value
|
15
|
-
value =
|
15
|
+
value = cached_value.value
|
16
16
|
Helpers.log(self, method_name, 'cache hit')
|
17
17
|
else
|
18
18
|
time = ::Benchmark.realtime do
|
19
|
-
value = send("#{method_name}_without_memoize"
|
20
|
-
create_memoized_value(method_name,
|
19
|
+
value = send("#{method_name}_without_memoize")
|
20
|
+
create_memoized_value(method_name, value)
|
21
21
|
end
|
22
22
|
Helpers.log(self, method_name, "cache miss. took #{Kernel.format '%.2f msecs', time * 1_000}")
|
23
23
|
end
|
@@ -37,33 +37,28 @@ module DbMemoize
|
|
37
37
|
# product.memoize_values full_title: "my full title",
|
38
38
|
# autocomplete_info: "my autocomplete_info"
|
39
39
|
#
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
# This sets the "full_title" and "autocomplete_info" values of the product.
|
41
|
+
#
|
42
|
+
def memoize_values(values)
|
44
43
|
values.each do |name, value|
|
45
|
-
create_memoized_value(name,
|
44
|
+
create_memoized_value(name, value)
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
49
48
|
private
|
50
49
|
|
51
|
-
def create_memoized_value(method_name,
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
value: Helpers.marshal(value)
|
57
|
-
|
58
|
-
@association_cache.delete :memoized_values
|
50
|
+
def create_memoized_value(method_name, value)
|
51
|
+
self.class.transaction do
|
52
|
+
::DbMemoize::Value.fast_create self.class.table_name, id, method_name, value
|
53
|
+
@association_cache.delete :memoized_values
|
54
|
+
end
|
59
55
|
end
|
60
56
|
|
61
|
-
def find_memoized_value(method_name
|
57
|
+
def find_memoized_value(method_name)
|
62
58
|
method_name = method_name.to_s
|
63
59
|
|
64
60
|
memoized_values.detect do |rec|
|
65
|
-
rec.method_name == method_name
|
66
|
-
rec.arguments_hash == args_hash
|
61
|
+
rec.method_name == method_name
|
67
62
|
end
|
68
63
|
end
|
69
64
|
|
@@ -93,19 +88,13 @@ module DbMemoize
|
|
93
88
|
DbMemoize::Value.where(conditions).delete_all_ordered
|
94
89
|
end
|
95
90
|
|
96
|
-
def memoize_values(records_or_ids, values
|
97
|
-
# [TODO] - when creating many memoized values: should we even support arguments here?
|
91
|
+
def memoize_values(records_or_ids, values)
|
98
92
|
transaction do
|
99
|
-
ids
|
100
|
-
arguments_hash = Helpers.calculate_arguments_hash(args)
|
93
|
+
ids = Helpers.find_ids(records_or_ids)
|
101
94
|
|
102
95
|
ids.each do |id|
|
103
96
|
values.each do |method_name, value|
|
104
|
-
::DbMemoize::Value.
|
105
|
-
entity_id: id,
|
106
|
-
method_name: method_name.to_s,
|
107
|
-
arguments_hash: arguments_hash,
|
108
|
-
value: Helpers.marshal(value)
|
97
|
+
::DbMemoize::Value.fast_create table_name, id, method_name, value
|
109
98
|
end
|
110
99
|
end
|
111
100
|
end
|
@@ -113,14 +102,16 @@ module DbMemoize
|
|
113
102
|
|
114
103
|
private
|
115
104
|
|
105
|
+
# rubocop:disable Style/EmptyBlockParameter
|
116
106
|
def create_memoized_alias_method(method_name)
|
117
|
-
define_method "#{method_name}_with_memoize" do
|
118
|
-
memoized_value(method_name
|
107
|
+
define_method "#{method_name}_with_memoize" do ||
|
108
|
+
memoized_value(method_name)
|
119
109
|
end
|
120
110
|
|
121
111
|
alias_method_chain method_name, :memoize
|
122
112
|
end
|
123
113
|
|
114
|
+
# rubocop:disable Style/GuardClause
|
124
115
|
def create_memoized_values_association
|
125
116
|
unless reflect_on_association(:memoized_values)
|
126
117
|
conditions = { entity_table_name: table_name }
|
data/lib/db_memoize/value.rb
CHANGED
@@ -1,15 +1,39 @@
|
|
1
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
2
|
+
|
3
|
+
require 'simple-sql'
|
4
|
+
require 'json'
|
5
|
+
|
1
6
|
module DbMemoize
|
2
7
|
class Value < ActiveRecord::Base
|
3
8
|
self.table_name = 'memoized_values'
|
4
9
|
|
5
|
-
|
10
|
+
SQL = ::Simple::SQL
|
11
|
+
|
12
|
+
def value=(value)
|
13
|
+
self.val_integer = self.val_float = self.val_string = self.val_boolean = self.val_time = nil
|
14
|
+
|
15
|
+
case value
|
16
|
+
when String then self.val_string = value
|
17
|
+
when Integer then self.val_integer = value
|
18
|
+
when Float then self.val_float = value
|
19
|
+
when Time then self.val_time = value
|
20
|
+
when false then self.val_boolean = value
|
21
|
+
when true then self.val_boolean = value
|
22
|
+
when nil then :nop
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def value
|
27
|
+
# Note: val_boolean should come last.
|
28
|
+
val_string || val_integer || val_float || val_time || val_object || val_boolean
|
29
|
+
end
|
6
30
|
|
7
31
|
def self.delete_all_ordered
|
8
32
|
relation = self
|
9
33
|
relation = all unless is_a?(ActiveRecord::Relation)
|
10
34
|
|
11
35
|
sql = relation.select(:ctid).to_sql
|
12
|
-
|
36
|
+
SQL.ask <<-SQL
|
13
37
|
DO $$DECLARE c record;
|
14
38
|
BEGIN
|
15
39
|
FOR c IN #{sql} ORDER BY ctid LOOP
|
@@ -18,5 +42,36 @@ module DbMemoize
|
|
18
42
|
END$$;
|
19
43
|
SQL
|
20
44
|
end
|
45
|
+
|
46
|
+
def self.fast_create(entity_table_name, id, method_name, value)
|
47
|
+
method_name = method_name.to_s
|
48
|
+
|
49
|
+
# clear out old entry (if any). This makes sure that any existing value
|
50
|
+
# is cleared out properly.
|
51
|
+
SQL.ask "DELETE FROM #{table_name} WHERE(entity_table_name, entity_id, method_name) = ($1, $2, $3)",
|
52
|
+
entity_table_name, id, method_name
|
53
|
+
|
54
|
+
dest_column = case value
|
55
|
+
when String then :val_string
|
56
|
+
when Integer then :val_integer
|
57
|
+
when Float then :val_float
|
58
|
+
when Time then :val_time
|
59
|
+
when false then :val_boolean
|
60
|
+
when nil then :val_nil
|
61
|
+
when Hash then :val_object
|
62
|
+
when Array then :val_object
|
63
|
+
else
|
64
|
+
raise "Unsupported value of type #{value.class.name}: #{value.inspect}"
|
65
|
+
end
|
66
|
+
|
67
|
+
value = JSON.generate(value) if dest_column == :val_object
|
68
|
+
sql = <<~SQL.freeze
|
69
|
+
INSERT INTO #{table_name}
|
70
|
+
(entity_table_name, entity_id, method_name, #{dest_column}, created_at)
|
71
|
+
VALUES($1,$2,$3,$4,NOW())
|
72
|
+
SQL
|
73
|
+
|
74
|
+
SQL.ask sql, entity_table_name, id, method_name, value
|
75
|
+
end
|
21
76
|
end
|
22
77
|
end
|
data/lib/db_memoize/version.rb
CHANGED
@@ -1,3 +1,24 @@
|
|
1
1
|
module DbMemoize
|
2
|
-
|
2
|
+
module GemHelper
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def version(name)
|
6
|
+
spec = Gem.loaded_specs[name]
|
7
|
+
version = spec.version.to_s
|
8
|
+
version += '+unreleased' if unreleased?(spec)
|
9
|
+
version
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def unreleased?(spec)
|
15
|
+
return false unless defined?(Bundler::Source::Gemspec)
|
16
|
+
return true if spec.source.is_a?(::Bundler::Source::Gemspec)
|
17
|
+
return true if spec.source.is_a?(::Bundler::Source::Path)
|
18
|
+
|
19
|
+
false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
VERSION = GemHelper.version 'db_memoize'
|
3
24
|
end
|
data/scripts/release
ADDED
data/scripts/release.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# -- helpers ------------------------------------------------------------------
|
4
|
+
|
5
|
+
def sys(cmd)
|
6
|
+
STDERR.puts "> #{cmd}"
|
7
|
+
system cmd
|
8
|
+
return true if $?.success?
|
9
|
+
|
10
|
+
STDERR.puts "> #{cmd} returned with exitstatus #{$?.exitstatus}"
|
11
|
+
$?.success?
|
12
|
+
end
|
13
|
+
|
14
|
+
def sys!(cmd, error: nil)
|
15
|
+
return true if sys(cmd)
|
16
|
+
STDERR.puts error if error
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def die!(msg)
|
21
|
+
STDERR.puts msg
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
ROOT = File.expand_path("#{File.dirname(__FILE__)}/..")
|
26
|
+
|
27
|
+
GEMSPEC = Dir.glob("*.gemspec").first || die!("Missing gemspec file.")
|
28
|
+
|
29
|
+
# -- Version reading and bumping ----------------------------------------------
|
30
|
+
|
31
|
+
module Version
|
32
|
+
extend self
|
33
|
+
|
34
|
+
VERSION_FILE = "#{Dir.getwd}/VERSION"
|
35
|
+
|
36
|
+
def read_version
|
37
|
+
version = File.exist?(VERSION_FILE) ? File.read(VERSION_FILE) : "0.0.1"
|
38
|
+
version.chomp!
|
39
|
+
raise "Invalid version number in #{VERSION_FILE}" unless version =~ /^\d+\.\d+\.\d+$/
|
40
|
+
version
|
41
|
+
end
|
42
|
+
|
43
|
+
def auto_version_bump
|
44
|
+
old_version_number = read_version
|
45
|
+
old = old_version_number.split('.')
|
46
|
+
|
47
|
+
current = old[0..-2] << old[-1].next
|
48
|
+
current.join('.')
|
49
|
+
end
|
50
|
+
|
51
|
+
def bump_version
|
52
|
+
next_version = ENV["VERSION"] || auto_version_bump
|
53
|
+
File.open(VERSION_FILE, "w") { |io| io.write next_version }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# -- check, bump, release a new gem version -----------------------------------
|
58
|
+
|
59
|
+
Dir.chdir ROOT
|
60
|
+
$BASE_BRANCH = ENV['BRANCH'] || 'master'
|
61
|
+
|
62
|
+
# ENV["BUNDLE_GEMFILE"] = "#{Dir.getwd}/Gemfile"
|
63
|
+
# sys! "bundle install"
|
64
|
+
|
65
|
+
sys! "git diff --exit-code > /dev/null", error: 'There are unstaged changes in your working directory'
|
66
|
+
sys! "git diff --cached --exit-code > /dev/null", error: 'There are staged but uncommitted changes'
|
67
|
+
|
68
|
+
sys! "git checkout #{$BASE_BRANCH}"
|
69
|
+
sys! "git pull"
|
70
|
+
|
71
|
+
Version.bump_version
|
72
|
+
version = Version.read_version
|
73
|
+
|
74
|
+
sys! "git add VERSION"
|
75
|
+
sys! "git commit -m \"bump gem to v#{version}\""
|
76
|
+
sys! "git tag -a v#{version} -m \"Tag #{version}\""
|
77
|
+
|
78
|
+
sys! "gem build #{GEMSPEC}"
|
79
|
+
|
80
|
+
sys! "git push origin #{$BASE_BRANCH}"
|
81
|
+
sys! 'git push --tags --force'
|
82
|
+
|
83
|
+
# sys! "bundle exec fury push #{Dir.glob('*.gem').first} --as mediapeers"
|
84
|
+
sys! "gem push #{Dir.glob('*.gem').first}"
|
85
|
+
|
86
|
+
sys! "mkdir -p pkg"
|
87
|
+
sys! "mv *.gem pkg"
|
88
|
+
|
89
|
+
STDERR.puts <<-MSG
|
90
|
+
================================================================================
|
91
|
+
Thank you for releasing a new gem version. You made my day.
|
92
|
+
================================================================================
|
93
|
+
MSG
|
metadata
CHANGED
@@ -1,31 +1,37 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db_memoize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- johannes-kostas goetzinger
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: simple-sql
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.4.20
|
17
20
|
- - "~>"
|
18
21
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
type: :
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.4.20
|
24
30
|
- - "~>"
|
25
31
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
32
|
+
version: '0'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
34
|
+
name: railties
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - "~>"
|
@@ -39,117 +45,89 @@ dependencies:
|
|
39
45
|
- !ruby/object:Gem::Version
|
40
46
|
version: '4.2'
|
41
47
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '10.5'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '10.5'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: pg
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rspec-rails
|
48
|
+
name: activerecord
|
71
49
|
requirement: !ruby/object:Gem::Requirement
|
72
50
|
requirements:
|
73
51
|
- - "~>"
|
74
52
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
53
|
+
version: 4.2.10
|
76
54
|
type: :development
|
77
55
|
prerelease: false
|
78
56
|
version_requirements: !ruby/object:Gem::Requirement
|
79
57
|
requirements:
|
80
58
|
- - "~>"
|
81
59
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
60
|
+
version: 4.2.10
|
83
61
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
62
|
+
name: rake
|
85
63
|
requirement: !ruby/object:Gem::Requirement
|
86
64
|
requirements:
|
87
65
|
- - "~>"
|
88
66
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0
|
67
|
+
version: '12.0'
|
90
68
|
type: :development
|
91
69
|
prerelease: false
|
92
70
|
version_requirements: !ruby/object:Gem::Requirement
|
93
71
|
requirements:
|
94
72
|
- - "~>"
|
95
73
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0
|
74
|
+
version: '12.0'
|
97
75
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
76
|
+
name: pg
|
99
77
|
requirement: !ruby/object:Gem::Requirement
|
100
78
|
requirements:
|
101
79
|
- - "~>"
|
102
80
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
81
|
+
version: '0.20'
|
104
82
|
type: :development
|
105
83
|
prerelease: false
|
106
84
|
version_requirements: !ruby/object:Gem::Requirement
|
107
85
|
requirements:
|
108
86
|
- - "~>"
|
109
87
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
88
|
+
version: '0.20'
|
111
89
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
90
|
+
name: rspec
|
113
91
|
requirement: !ruby/object:Gem::Requirement
|
114
92
|
requirements:
|
115
93
|
- - "~>"
|
116
94
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
95
|
+
version: '3.8'
|
118
96
|
type: :development
|
119
97
|
prerelease: false
|
120
98
|
version_requirements: !ruby/object:Gem::Requirement
|
121
99
|
requirements:
|
122
100
|
- - "~>"
|
123
101
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
102
|
+
version: '3.8'
|
125
103
|
- !ruby/object:Gem::Dependency
|
126
104
|
name: simplecov
|
127
105
|
requirement: !ruby/object:Gem::Requirement
|
128
106
|
requirements:
|
129
107
|
- - "~>"
|
130
108
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
109
|
+
version: '0.16'
|
132
110
|
type: :development
|
133
111
|
prerelease: false
|
134
112
|
version_requirements: !ruby/object:Gem::Requirement
|
135
113
|
requirements:
|
136
114
|
- - "~>"
|
137
115
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.
|
116
|
+
version: '0.16'
|
139
117
|
- !ruby/object:Gem::Dependency
|
140
118
|
name: rubocop
|
141
119
|
requirement: !ruby/object:Gem::Requirement
|
142
120
|
requirements:
|
143
121
|
- - "~>"
|
144
122
|
- !ruby/object:Gem::Version
|
145
|
-
version: 0.
|
123
|
+
version: 0.59.2
|
146
124
|
type: :development
|
147
125
|
prerelease: false
|
148
126
|
version_requirements: !ruby/object:Gem::Requirement
|
149
127
|
requirements:
|
150
128
|
- - "~>"
|
151
129
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.
|
130
|
+
version: 0.59.2
|
153
131
|
- !ruby/object:Gem::Dependency
|
154
132
|
name: database_cleaner
|
155
133
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,48 +156,6 @@ dependencies:
|
|
178
156
|
- - "~>"
|
179
157
|
- !ruby/object:Gem::Version
|
180
158
|
version: 4.7.0
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: ruby-progressbar
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '1.7'
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - "~>"
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '1.7'
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
|
-
name: awesome_print
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
198
|
-
requirements:
|
199
|
-
- - ">="
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: '0'
|
202
|
-
type: :development
|
203
|
-
prerelease: false
|
204
|
-
version_requirements: !ruby/object:Gem::Requirement
|
205
|
-
requirements:
|
206
|
-
- - ">="
|
207
|
-
- !ruby/object:Gem::Version
|
208
|
-
version: '0'
|
209
|
-
- !ruby/object:Gem::Dependency
|
210
|
-
name: gem-release
|
211
|
-
requirement: !ruby/object:Gem::Requirement
|
212
|
-
requirements:
|
213
|
-
- - ">="
|
214
|
-
- !ruby/object:Gem::Version
|
215
|
-
version: '0'
|
216
|
-
type: :development
|
217
|
-
prerelease: false
|
218
|
-
version_requirements: !ruby/object:Gem::Requirement
|
219
|
-
requirements:
|
220
|
-
- - ">="
|
221
|
-
- !ruby/object:Gem::Version
|
222
|
-
version: '0'
|
223
159
|
description: library to cache (memoize) method return values in database
|
224
160
|
email:
|
225
161
|
- goetzinger@mediapeers.com
|
@@ -235,12 +171,15 @@ files:
|
|
235
171
|
- LICENSE
|
236
172
|
- README.md
|
237
173
|
- Rakefile
|
174
|
+
- VERSION
|
238
175
|
- bin/console
|
176
|
+
- bin/rake
|
177
|
+
- bin/rspec
|
178
|
+
- bin/rubocop
|
239
179
|
- bin/setup
|
240
180
|
- db_memoize.gemspec
|
241
181
|
- lib/db_memoize.rb
|
242
182
|
- lib/db_memoize/helpers.rb
|
243
|
-
- lib/db_memoize/metal.rb
|
244
183
|
- lib/db_memoize/migrations.rb
|
245
184
|
- lib/db_memoize/model.rb
|
246
185
|
- lib/db_memoize/railtie.rb
|
@@ -249,6 +188,8 @@ files:
|
|
249
188
|
- lib/tasks/clear.rake
|
250
189
|
- lib/tasks/warmup.rake
|
251
190
|
- log/.keep
|
191
|
+
- scripts/release
|
192
|
+
- scripts/release.rb
|
252
193
|
homepage: https://github.com/mediapeers/db_memoize
|
253
194
|
licenses:
|
254
195
|
- MIT
|
@@ -269,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
269
210
|
version: '0'
|
270
211
|
requirements: []
|
271
212
|
rubyforge_project:
|
272
|
-
rubygems_version: 2.
|
213
|
+
rubygems_version: 2.7.7
|
273
214
|
signing_key:
|
274
215
|
specification_version: 4
|
275
216
|
summary: library to cache (memoize) method return values in database
|
data/lib/db_memoize/metal.rb
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
module DbMemoize
|
2
|
-
module Metal
|
3
|
-
def self.included(base)
|
4
|
-
base.extend ClassMethods
|
5
|
-
# base.metal # initialize the metal adapter
|
6
|
-
end
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
def metal
|
10
|
-
@metal ||= Adapter.new(self)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class Adapter
|
15
|
-
class PkInfo
|
16
|
-
attr_reader :column, :type
|
17
|
-
|
18
|
-
def initialize(base_klass)
|
19
|
-
@column = base_klass.primary_key
|
20
|
-
@type = @column && base_klass.columns_hash.fetch(@column).type
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def initialize(base_klass)
|
25
|
-
@base_klass = base_klass
|
26
|
-
@query_cache = {}
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
# setup primary key information. This is necessary to allow the create! method
|
32
|
-
# to return the primary key of a newly created entry.
|
33
|
-
def primary_key
|
34
|
-
@primary_key ||= PkInfo.new(@base_klass)
|
35
|
-
end
|
36
|
-
|
37
|
-
def table_name
|
38
|
-
@base_klass.table_name
|
39
|
-
end
|
40
|
-
|
41
|
-
def raw_connection
|
42
|
-
@base_klass.connection.raw_connection # do not memoize me!
|
43
|
-
end
|
44
|
-
|
45
|
-
def column?(column_name)
|
46
|
-
@base_klass.columns_hash.key?(column_name)
|
47
|
-
end
|
48
|
-
|
49
|
-
class Inserter
|
50
|
-
def initialize(sql:, bytea_indices:)
|
51
|
-
@sql = sql
|
52
|
-
@bytea_indices = bytea_indices
|
53
|
-
end
|
54
|
-
|
55
|
-
def exec(raw_connection:, values:)
|
56
|
-
@bytea_indices.each do |bytea_index|
|
57
|
-
value = values[bytea_index]
|
58
|
-
values[bytea_index] = PGconn.escape_bytea(value) if value
|
59
|
-
end
|
60
|
-
|
61
|
-
raw_connection.exec_params(@sql, values)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# returns an Inserter
|
66
|
-
def inserter(field_names)
|
67
|
-
@query_cache[field_names] ||= _inserter(field_names)
|
68
|
-
end
|
69
|
-
|
70
|
-
DATABASE_IDENTIFIER_REGEX = /\A\w+\z/
|
71
|
-
|
72
|
-
def check_database_identifiers!(*strings)
|
73
|
-
strings.each do |s|
|
74
|
-
next if DATABASE_IDENTIFIER_REGEX =~ s
|
75
|
-
raise ArgumentError, "Invalid database identifier: #{s.inspect}"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def _inserter(field_names)
|
80
|
-
check_database_identifiers! table_name, *field_names
|
81
|
-
|
82
|
-
placeholders = 0.upto(field_names.count - 1).map { |idx| "$#{idx + 1}" }
|
83
|
-
|
84
|
-
if column?('created_at')
|
85
|
-
field_names << 'created_at'
|
86
|
-
placeholders << 'current_timestamp'
|
87
|
-
end
|
88
|
-
|
89
|
-
if column?('updated_at')
|
90
|
-
field_names << 'updated_at'
|
91
|
-
placeholders << 'current_timestamp'
|
92
|
-
end
|
93
|
-
|
94
|
-
sql = "INSERT INTO #{table_name} (#{field_names.join(',')}) VALUES(#{placeholders.join(',')})"
|
95
|
-
sql += " RETURNING #{primary_key.column}" if primary_key.column
|
96
|
-
|
97
|
-
columns_hash = @base_klass.columns_hash
|
98
|
-
bytea_indices = []
|
99
|
-
field_names.each_with_index { |column, idx|
|
100
|
-
next unless :binary == columns_hash.fetch(column).type
|
101
|
-
bytea_indices << idx
|
102
|
-
}
|
103
|
-
|
104
|
-
Inserter.new sql: sql, bytea_indices: bytea_indices
|
105
|
-
end
|
106
|
-
|
107
|
-
public
|
108
|
-
|
109
|
-
def create!(record)
|
110
|
-
keys, values = record.to_a.transpose
|
111
|
-
keys = keys.map(&:to_s)
|
112
|
-
|
113
|
-
result = inserter(keys).exec(raw_connection: raw_connection, values: values)
|
114
|
-
|
115
|
-
# if we don't have an ID column then the sql does not return any value. The result
|
116
|
-
# object would be this: #<PG::Result status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=1>
|
117
|
-
# we just return nil in that case; otherwise we return the first entry of the first result row
|
118
|
-
# which would be the stringified id.
|
119
|
-
first_row = result.each_row.first
|
120
|
-
return nil unless first_row
|
121
|
-
|
122
|
-
id = first_row.first
|
123
|
-
primary_key.type == :integer ? Integer(id) : id
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|