tachyon 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -6
- data/lib/tachyon.rb +51 -48
- data/lib/tachyon/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 020224e8c886048d69c0c929aa937d2bb6939dff
|
4
|
+
data.tar.gz: bc97180405d1c796355ab0d4fcec8bcefdd43d6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ab76163499e5b2407e07a6f71d4cc2630bb46fcdaa9b4cae843f4480068cdfbcd526ccb4b79946726d1150a08f42674270b9f02753d0a16fc511dc516fca4ac
|
7
|
+
data.tar.gz: d34249d947078919f4c76b74ac0cda7bf7ab0d5005fb3b1bd47be35643d8b7c99a1e142c6976808ad70ecf1dde5378e95e08ec285bef00cfa3251181e0677dba
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
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.
|
4
4
|
|
5
|
+
An ideal use-case for Tachyon (and the reason it was developed) is to dump/insert data from the DB as part of the setup step for large test cases.
|
6
|
+
|
5
7
|
## How fast is it?
|
6
8
|
|
7
9
|
Tachyon is as fast (or faster) than executing raw SQL via `ActiveRecord::Base.connection`:
|
@@ -9,22 +11,22 @@ Tachyon is as fast (or faster) than executing raw SQL via `ActiveRecord::Base.co
|
|
9
11
|
```
|
10
12
|
Benchmark Results (Inserting 10,000 rows):
|
11
13
|
------------------------------------------------
|
12
|
-
User.create(Hash) :
|
13
|
-
Raw SQL (w/ string interpolation) : 1.
|
14
|
-
Tachyon.insert(User, Hash) : 1.
|
14
|
+
User.create(Hash) : 8.14 seconds
|
15
|
+
Raw SQL (w/ string interpolation) : 1.17 seconds
|
16
|
+
Tachyon.insert(User, Hash) : 1.03 seconds
|
15
17
|
```
|
16
18
|
|
17
19
|
## Features
|
18
20
|
|
19
21
|
* As fast (or faster!) than generating SQL via string interpolation, but with a much nicer syntax!
|
20
22
|
* 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.
|
23
|
+
* Allows you to dump records from the database in a useful format via `Tachyon.dump`
|
22
24
|
* Compatible with MySQL, PostgreSQL and SQLite3
|
23
25
|
|
24
26
|
## Caveats
|
25
27
|
|
26
28
|
* Tachyon does not perform validations
|
27
|
-
* Tachyon only does minimal typecasting
|
29
|
+
* Tachyon only does minimal typecasting (ie: inserting a `Time` object does not work, use `Time.to_s(:db)` instead)
|
28
30
|
|
29
31
|
## Typecasting
|
30
32
|
|
@@ -32,12 +34,22 @@ Tachyon does extremely minimal typecasting. Integers and Floats are passed throu
|
|
32
34
|
|
33
35
|
## Usage
|
34
36
|
|
35
|
-
|
37
|
+
To insert simply supply the model class along with a hash of attributes. It's important to note that the keys of the hash must be symbols, not strings:
|
36
38
|
|
37
39
|
```ruby
|
38
40
|
Tachyon.insert(Article, id: 13, title: "Brand new article")
|
39
41
|
```
|
40
42
|
|
43
|
+
And to dump a record simply call `Tachyon.dump`:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
article = Article.find(13)
|
47
|
+
Tachyon.dump(article)
|
48
|
+
=> { id: 13, title: "Brand new article", created_at: "2016-06-30 03:32:49", updated_at: "2016-06-30 03:32:49" }
|
49
|
+
```
|
50
|
+
|
51
|
+
Note that Tachyon is dumping the data in a way that is directly compatible with the DB, the data won't require much in the way of typecasting to insert it back into the DB.
|
52
|
+
|
41
53
|
## Installation
|
42
54
|
|
43
55
|
Add this line to your application's Gemfile:
|
data/lib/tachyon.rb
CHANGED
@@ -1,67 +1,70 @@
|
|
1
1
|
require "tachyon/version"
|
2
2
|
|
3
3
|
class Tachyon
|
4
|
+
class << self
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
@@sql_cache = {}
|
7
|
+
@@connection_cache = {}
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def insert(klass, data)
|
10
|
+
connection_for(klass).execute(sql_for(klass, data))
|
11
|
+
rescue ActiveRecord::RecordNotUnique
|
12
|
+
# NO OP
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
def connection_for(klass)
|
16
|
+
return @@connection_cache[klass] if @@connection_cache.has_key?(klass)
|
17
|
+
@@connection_cache[klass] = klass.connection
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
def sql_for(klass, data)
|
21
|
+
sql_template_for(klass) % quote_data(data)
|
22
|
+
rescue KeyError => e
|
23
|
+
raise "Data was not supplied for all columns - " + e.to_s
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
def sql_template_for(klass)
|
27
|
+
return @@sql_cache[klass] if @@sql_cache.has_key?(klass)
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
columns = klass.columns.map(&:name)
|
30
|
+
table_name = klass.table_name
|
31
|
+
columns_string = columns.map {|x| "`#{x}`" }.join(", ")
|
32
|
+
values_string = columns.map {|x| "%{#{x}}" }.join(", ")
|
32
33
|
|
33
|
-
|
34
|
+
sql = "INSERT INTO `#{table_name}` (#{columns_string}) VALUES (#{values_string})"
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
@@sql_cache[klass] = sql
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
def quote_data(data)
|
40
|
+
data.map do |key, value|
|
41
|
+
[key, quote_value(value)]
|
42
|
+
end.to_h
|
43
|
+
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
def quote_value(value)
|
46
|
+
case value
|
47
|
+
when String then "'#{value.gsub("'", "''")}'"
|
48
|
+
when NilClass then "NULL"
|
49
|
+
else value
|
50
|
+
end
|
49
51
|
end
|
50
|
-
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
def dump(record)
|
54
|
+
record.attributes_before_type_cast.map do |key, value|
|
55
|
+
[key.to_sym, dump_attribute(value)]
|
56
|
+
end.to_h
|
57
|
+
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
def dump_attribute(attribute)
|
60
|
+
case attribute
|
61
|
+
when Time then attribute.to_s(:db)
|
62
|
+
when Date then attribute.to_s(:db)
|
63
|
+
when TrueClass then 1
|
64
|
+
when FalseClass then 0
|
65
|
+
else attribute
|
66
|
+
end
|
65
67
|
end
|
68
|
+
|
66
69
|
end
|
67
70
|
end
|
data/lib/tachyon/version.rb
CHANGED