tachyon 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7882de4f67436fff7b522c0be26a0b49689bcd5e
4
- data.tar.gz: 92c62b8cebbff5a64a1debed2c43297536fd5890
3
+ metadata.gz: 7e508417f45cc19402918a4a554f8928cd43919d
4
+ data.tar.gz: 0f97c7354af65aebbd184ee4f85eb735eb841a01
5
5
  SHA512:
6
- metadata.gz: 4c634d8836430187401b0e4ccf895c907169f7928a75e55fddf781a82fc9d4a14cc08fd2f113a791eb4d0babd1ed40942c93d6df054fb6e465d168ec688c80b3
7
- data.tar.gz: 7e4fa020dc44fb6e4a0259000220c95712b6c6dd8c5a34717b380a7508dca82cf2a5fef06ed147a4e3ad39403ef47f63c8c8cee750f286ebd88eb44a48717d44
6
+ metadata.gz: 4e1a77ae53773d6c6e7d0aaa81765bf8ede459dfca2cd06120402c8314cade4e7f73e33c4e85149913c5e7304a41bc7a630f6f2ce51a69d74a28287686f0f8dc
7
+ data.tar.gz: 177c88d41f2809cfd356d4ada6acd192101c28943425d5431d1d337dce1d688c6338a9862ac9ab318a53af9d66bb02d7d7d8dbc63f43fc45c4284ef501386465
data/README.md CHANGED
@@ -1,41 +1,43 @@
1
1
  # Tachyon
2
2
 
3
- Tachyon is a simple library designed to insert rows into any DB managed by ActiveRecord as fast as possible. Tachyon does not do validations. Tachyon does not throw errors on duplicate keys. Tachyon simply gets records into the DB as fast as possible. This is very useful in the case when you need to bulk-insert data for some reason, but it really shouldn't be used to replace your normal ActiveRecord DB operations.
4
-
5
- Tachyon is roughly as fast as executing raw SQL statements, but with a much more readable syntax. Tachyon uses Arel to geneate the SQL statements and to manage type-casting, this helps to avoid the fragility that can come with manually generating SQL.
3
+ Tachyon is a simple library designed to insert rows into any DB managed by ActiveRecord as fast as possible. Tachyon does not do validations, and only does minimal typescasting. Tachyon simply gets records into the DB as fast as possible. This is very useful in the case when you need to bulk-insert data for some reason, but it really shouldn't be used to replace your normal ActiveRecord DB operations.
6
4
 
7
5
  ## How fast is it?
8
6
 
9
- The goal is to be roughly as fast as executing raw SQL via `ActiveRecord::Base.connection`. Tachyon still falls a little short of this mark, but future optimizations will close the gap.
7
+ Tachyon is as fast (or faster) than executing raw SQL via `ActiveRecord::Base.connection`:
10
8
 
11
9
  ```
12
- Benchmark Results (inserting 5,000 rows):
13
- -------------------------------------------
14
- User.create() : 4.461711 secs
15
- Raw SQL : 0.597918 secs
16
- Tachyon.insert(User, Hash) : 1.127233 secs
17
- Tachyon.insert(User, Array) : 1.078880 secs
10
+ Benchmark Results (Inserting 10,000 rows):
11
+ ------------------------------------------------
12
+ User.create(Hash) : 7.72 seconds
13
+ Raw SQL (w/ string interpolation) : 1.01 seconds
14
+ Tachyon.insert(User, Hash) : 1.00 seconds
18
15
  ```
19
16
 
20
- ## Usage
17
+ ## Features
21
18
 
22
- To insert a single row, simply supply the model class along with a hash of attributes:
19
+ * As fast (or faster!) than generating SQL via string interpolation, but with a much nicer syntax!
20
+ * Suppresses duplicate key errors, which makes life easier when doing bulk data imports
21
+ * Allows you to dump records from the database in a useful format via `Tachyon.dump_record`
22
+ * Compatible with MySQL, PostgreSQL and SQLite3
23
23
 
24
- ```ruby
25
- Tachyon.insert(Article, id: 13, title: "Brand new article")
26
- ```
24
+ ## Caveats
25
+
26
+ * Tachyon does not perform validations
27
+ * Tachyon only does minimal typecasting
28
+
29
+ ## Typecasting
27
30
 
28
- To do a bulk insert, supply the model class and an array of attribute hashes. Tachyon will wrap multiple inserts in a transaction for an extra speed boost:
31
+ Tachyon does extremely minimal typecasting. Integers and Floats are passed through as literals, nils are converted to NULLs, pretty much all other types should be supplied as strings where appropriate.
32
+
33
+ ## Usage
34
+
35
+ Simply supply the model class along with a hash of attributes:
29
36
 
30
37
  ```ruby
31
- Tachyon.insert(Comment, [
32
- {id: 1, article_id: 34, title: "Super comment"},
33
- {id: 2, article_id: 12, title: "Another one"},
34
- {id: 3, article_id: 90, title: "Comment duex"},
35
- ])
38
+ Tachyon.insert(Article, id: 13, title: "Brand new article")
36
39
  ```
37
40
 
38
-
39
41
  ## Installation
40
42
 
41
43
  Add this line to your application's Gemfile:
@@ -52,8 +54,6 @@ Or install it yourself as:
52
54
 
53
55
  $ gem install tachyon
54
56
 
55
-
56
-
57
57
  ## License
58
58
 
59
59
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/lib/tachyon.rb CHANGED
@@ -1,29 +1,67 @@
1
1
  require "tachyon/version"
2
2
 
3
3
  class Tachyon
4
+
5
+ @@sql_cache = {}
6
+ @@connection_cache = {}
7
+
4
8
  def self.insert(klass, data)
5
- raise ArgumentError, "data must be a hash or array" unless data.is_a?(Array) || data.is_a?(Hash)
6
- raise ArgumentError, "klass must inherit from ActiveRecord::Base" unless klass < ActiveRecord::Base
9
+ self.connection_for(klass).execute(self.sql_for(klass, data))
10
+ rescue ActiveRecord::RecordNotUnique
11
+ # NO OP
12
+ end
7
13
 
8
- if data.is_a?(Array)
9
- self.insert_records(klass, data)
10
- elsif data.is_a?(Hash)
11
- self.insert_record(klass, data)
12
- end
14
+ def self.connection_for(klass)
15
+ return @@connection_cache[klass] if @@connection_cache.has_key?(klass)
16
+ @@connection_cache[klass] = klass.connection
13
17
  end
14
18
 
15
- def self.insert_record(klass, data)
16
- begin
17
- klass.new(data).save(validate: false)
18
- rescue ActiveRecord::RecordNotUnique
19
+ def self.sql_for(klass, data)
20
+ self.sql_template_for(klass) % self.quote_data(data)
21
+ rescue KeyError => e
22
+ raise "Data was not supplied for all columns - " + e.to_s
23
+ end
24
+
25
+ def self.sql_template_for(klass)
26
+ return @@sql_cache[klass] if @@sql_cache.has_key?(klass)
27
+
28
+ columns = klass.columns.map(&:name)
29
+ table_name = klass.table_name
30
+ columns_string = columns.map {|x| "`#{x}`" }.join(", ")
31
+ values_string = columns.map {|x| "%{#{x}}" }.join(", ")
32
+
33
+ sql = "INSERT INTO `#{table_name}` (#{columns_string}) VALUES (#{values_string})"
34
+
35
+ @@sql_cache[klass] = sql
36
+ end
37
+
38
+ def self.quote_data(data)
39
+ data.map do |key, value|
40
+ [key, self.quote_value(value)]
41
+ end.to_h
42
+ end
43
+
44
+ def self.quote_value(value)
45
+ case value
46
+ when String then "'#{value.gsub("'", "''")}'"
47
+ when NilClass then "NULL"
48
+ else value
19
49
  end
20
50
  end
21
51
 
22
- def self.insert_records(klass, data)
23
- klass.connection.transaction do
24
- data.each do |record|
25
- self.insert_record(klass, record)
26
- end
52
+ def self.dump_record(record)
53
+ record.attributes_before_type_cast.map do |key, value|
54
+ [key.to_sym, self.dump_attribute(value)]
55
+ end.to_h
56
+ end
57
+
58
+ def self.dump_attribute(attribute)
59
+ case attribute
60
+ when Time then attribute.to_s(:db)
61
+ when Date then attribute.to_s(:db)
62
+ when TrueClass then 1
63
+ when FalseClass then 0
64
+ else attribute
27
65
  end
28
66
  end
29
67
  end
@@ -1,3 +1,3 @@
1
1
  class Tachyon
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
data/tachyon.gemspec CHANGED
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency "activerecord", "~> 5.1.1"
28
28
  spec.add_development_dependency "activesupport", "~> 5.1.1"
29
29
  spec.add_development_dependency "sqlite3"
30
+ spec.add_development_dependency "ruby-prof"
30
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tachyon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Gough
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-15 00:00:00.000000000 Z
11
+ date: 2017-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: ruby-prof
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: Create records in a DB managed by ActiveRecord as fast as possible.
98
112
  email:
99
113
  - aaron@aarongough.com