DEV: clean and reorganize benchmarks (#30)

DEV: clean and reorganize benchmarks (#30)

diff --git a/bench/decorator_perf.rb b/bench/decorator_perf.rb
new file mode 100644
index 0000000..b9aa9af
--- /dev/null
+++ b/bench/decorator_perf.rb
@@ -0,0 +1,143 @@
+# frozen_string_literal: true
+
+require 'bundler/inline'
+
+gemfile do
+  source 'https://rubygems.org'
+  gem 'pg', github: 'ged/ruby-pg'
+  gem 'mini_sql', path: '../'
+  gem 'activerecord'
+  gem 'activemodel'
+  gem 'benchmark-ips'
+  gem 'sequel', github: 'jeremyevans/sequel'
+  gem 'sequel_pg', github: 'jeremyevans/sequel_pg', require: 'sequel'
+  gem 'draper'
+  gem 'pry'
+end
+
+require 'active_record'
+require 'benchmark/ips'
+require 'mini_sql'
+
+require '../mini_sql/bench/shared/generate_data'
+
+ar_connection, conn_config = GenerateData.new(count_records: 1_000).call
+MINI_SQL = MiniSql::Connection.get(ar_connection.raw_connection)
+DB = Sequel.connect(ar_connection.instance_variable_get(:@config).slice(:database, :user, :password, :host, :adapter))
+
+
+# https://github.com/drapergem/draper
+class TopicDraper < Draper::Decorator
+  delegate :id
+
+  def title_bang
+    object.title + '!!!'
+  end
+end
+
+# https://ruby-doc.org/stdlib-2.5.1/libdoc/delegate/rdoc/SimpleDelegator.html
+class TopicSimpleDelegator < SimpleDelegator
+  def title_bang
+    title + '!!!'
+  end
+end
+
+class TopicSequel < Sequel::Model(DB[:topics]); end
+class TopicDecoratorSequel < TopicSequel
+  def title_bang
+    title + '!!!'
+  end
+end
+
+class Topic < ActiveRecord::Base;end
+class TopicArModel < Topic
+  def title_bang
+    title + '!!!'
+  end
+end
+
+module TopicDecorator
+  def title_bang
+    title + '!!!'
+  end
+end
+
+Benchmark.ips do |r|
+  r.report('query_decorator') do |n|
+    while n > 0
+      MINI_SQL.query_decorator(TopicDecorator, 'select id, title from topics order by id limit 1000').each do |obj|
+        obj.title_bang
+        obj.id
+      end
+      n -= 1
+    end
+  end
+  r.report('extend') do |n|
+    while n > 0
+      MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
+        d_obj = obj.extend(TopicDecorator)
+        d_obj.title_bang
+        d_obj.id
+      end
+      n -= 1
+    end
+  end
+  r.report('draper') do |n|
+    while n > 0
+      MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
+        d_obj = TopicDraper.new(obj)
+        d_obj.title_bang
+        d_obj.id
+      end
+      n -= 1
+    end
+  end
+  r.report('simple_delegator') do |n|
+    while n > 0
+      MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
+        d_obj = TopicSimpleDelegator.new(obj)
+        d_obj.title_bang
+        d_obj.id
+      end
+      n -= 1
+    end
+  end
+  r.report('query') do |n|
+    while n > 0
+      MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
+        obj.title + '!!!'
+        obj.id
+      end
+      n -= 1
+    end
+  end
+  r.report('ar model') do |n|
+    while n > 0
+      TopicArModel.limit(1000).order(:id).select(:id, :title).each do |obj|
+        obj.title_bang
+        obj.id
+      end
+      n -= 1
+    end
+  end
+  r.report('sequel model') do |n|
+    while n > 0
+      TopicDecoratorSequel.limit(1000).order(:id).select(:id, :title).each do |obj|
+        obj.title_bang
+        obj.id
+      end
+      n -= 1
+    end
+  end
+
+  r.compare!
+end
+
+# Comparison:
+#                query:     1102.9 i/s
+#      query_decorator:     1089.0 i/s - same-ish: difference falls within error
+#         sequel model:      860.2 i/s - 1.28x  (± 0.00) slower
+#     simple_delegator:      679.8 i/s - 1.62x  (± 0.00) slower
+#               extend:      678.1 i/s - 1.63x  (± 0.00) slower
+#               draper:      587.2 i/s - 1.88x  (± 0.00) slower
+#             ar model:      172.5 i/s - 6.39x  (± 0.00) slower
diff --git a/bench/mini_sql_methods_perf.rb b/bench/mini_sql_methods_perf.rb
new file mode 100644
index 0000000..bfb0465
--- /dev/null
+++ b/bench/mini_sql_methods_perf.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'bundler/inline'
+
+gemfile do
+  source 'https://rubygems.org'
+  gem 'pg', github: 'ged/ruby-pg'
+  gem 'mini_sql', path: '../'
+  gem 'activerecord'
+  gem 'activemodel'
+  gem 'benchmark-ips'
+  gem 'draper'
+  gem 'pry'
+end
+
+require 'active_record'
+require 'benchmark/ips'
+require 'mini_sql'
+
+require '../mini_sql/bench/shared/generate_data'
+
+ar_connection, conn_config = GenerateData.new(count_records: 1_000).call
+MINI_SQL = MiniSql::Connection.get(ar_connection.raw_connection)
+
+
+Benchmark.ips do |r|
+  r.report('query_hash') do |n|
+    while n > 0
+      MINI_SQL.query_hash('select id, title from topics order by id limit 1000').each do |hash|
+        [hash['id'], hash['title']]
+      end
+      n -= 1
+    end
+  end
+  r.report('query_array') do |n|
+    while n > 0
+      MINI_SQL.query_array('select id, title from topics order by id limit 1000').each do |id, title|
+        [id, title]
+      end
+      n -= 1
+    end
+  end
+  r.report('query') do |n|
+    while n > 0
+      MINI_SQL.query('select id, title from topics order by id limit 1000').each do |obj|
+        [obj.id, obj.title]
+      end
+      n -= 1
+    end
+  end
+
+  r.compare!
+end
+
+# Comparison:
+#          query_array:     1663.3 i/s
+#                query:     1254.5 i/s - 1.33x  (± 0.00) slower
+#           query_hash:     1095.4 i/s - 1.52x  (± 0.00) slower
+
+
+Benchmark.ips do |r|
+  r.report('query_single') do |n|
+    while n > 0
+      MINI_SQL.query_single('select id from topics order by id limit 1000')
+      n -= 1
+    end
+  end
+  r.report('query_array') do |n|
+    while n > 0
+      MINI_SQL.query_array('select id from topics order by id limit 1000').flatten
+      n -= 1
+    end
+  end
+
+  r.compare!
+end
+
+# Comparison:
+#         query_single:     2445.1 i/s
+#          query_array:     1681.1 i/s - 1.45x  (± 0.00) slower
diff --git a/bench/shared/generate_data.rb b/bench/shared/generate_data.rb
new file mode 100644
index 0000000..0e446c2
--- /dev/null
+++ b/bench/shared/generate_data.rb
@@ -0,0 +1,130 @@
+# frozen_string_literal: true
+
+class GenerateData
+  class Topic < ActiveRecord::Base; end
+  class User < ActiveRecord::Base; end
+  class Category < ActiveRecord::Base; end
+
+  def initialize(count_records:)
+    @count_records = count_records
+  end
+
+  def call
+    conn_settings = {
+      password: 'postgres',
+      user: 'postgres',
+      host: 'localhost'
+    }
+    
+    db_conn = conn_settings.merge(database: "test_db", adapter: "postgresql")
+
+    pg = PG::Connection.new(conn_settings)
+    pg.exec "DROP DATABASE IF EXISTS test_db"
+    pg.exec "CREATE DATABASE test_db"
+    pg.close
+
+    ActiveRecord::Base.establish_connection(db_conn)
+    pg = ActiveRecord::Base.connection.raw_connection
+
+    pg.exec <<~SQL
+      drop table if exists topics;
+      drop table if exists users;
+      drop table if exists categories;
+      CREATE TABLE topics (
+        id integer NOT NULL PRIMARY KEY,
+        title character varying NOT NULL,
+        last_posted_at timestamp without time zone,
+        created_at timestamp without time zone NOT NULL,
+        updated_at timestamp without time zone NOT NULL,
+        views integer DEFAULT 0 NOT NULL,
+        posts_count integer DEFAULT 0 NOT NULL,
+        user_id integer,
+        last_post_user_id integer NOT NULL,
+        reply_count integer DEFAULT 0 NOT NULL,
+        featured_user1_id integer,
+        featured_user2_id integer,
+        featured_user3_id integer,
+        avg_time integer,
+        deleted_at timestamp without time zone,
+        highest_post_number integer DEFAULT 0 NOT NULL,
+        image_url character varying,
+        like_count integer DEFAULT 0 NOT NULL,
+        incoming_link_count integer DEFAULT 0 NOT NULL,
+        category_id integer,
+        visible boolean DEFAULT true NOT NULL,
+        moderator_posts_count integer DEFAULT 0 NOT NULL,

[... diff too long, it was truncated ...]

GitHub sha: 9e73c31d

This commit appears in #30 which was merged by SamSaffron.