surus 0.4.2 → 0.5.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 +15 -82
- data/bench/benchmark_helper.rb +0 -9
- data/bench/database_structure.sql +0 -18
- data/bench/hstore_find.rb +7 -7
- data/bench/json_generation.rb +1 -1
- data/lib/surus.rb +0 -6
- data/lib/surus/array/scope.rb +1 -1
- data/lib/surus/hstore/serializer.rb +23 -47
- data/lib/surus/json/belongs_to_scope_builder.rb +3 -3
- data/lib/surus/json/has_and_belongs_to_many_scope_builder.rb +4 -5
- data/lib/surus/json/has_many_scope_builder.rb +3 -4
- data/lib/surus/json/model.rb +1 -1
- data/lib/surus/version.rb +1 -1
- data/spec/array/scope_spec.rb +6 -6
- data/spec/hstore/scope_spec.rb +21 -21
- data/spec/spec_helper.rb +6 -20
- data/surus.gemspec +1 -1
- metadata +5 -24
- data/bench/array_create.rb +0 -46
- data/bench/array_find.rb +0 -79
- data/bench/array_serialize.rb +0 -34
- data/bench/hstore_create.rb +0 -57
- data/bench/hstore_serialize.rb +0 -42
- data/lib/surus/array/decimal_serializer.rb +0 -28
- data/lib/surus/array/float_serializer.rb +0 -28
- data/lib/surus/array/integer_serializer.rb +0 -28
- data/lib/surus/array/text_serializer.rb +0 -47
- data/lib/surus/hstore/connection_adapters.rb +0 -46
- data/lib/surus/json/connection_adapters.rb +0 -46
- data/spec/array/decimal_serializer_spec.rb +0 -23
- data/spec/array/float_serializer_spec.rb +0 -23
- data/spec/array/integer_serializer_spec.rb +0 -22
- data/spec/array/text_serializer_spec.rb +0 -29
data/bench/array_serialize.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
require 'benchmark_helper'
|
2
|
-
|
3
|
-
options = {}
|
4
|
-
optparse = OptionParser.new do |opts|
|
5
|
-
options[:elements] = 10
|
6
|
-
opts.on '-e NUM', '--elements NUM', Integer, 'Number of elements per array' do |n|
|
7
|
-
options[:elements] = n
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
optparse.parse!
|
12
|
-
|
13
|
-
clean_database
|
14
|
-
|
15
|
-
num_elements = options[:elements]
|
16
|
-
array = num_elements.times.map { SecureRandom.hex(4) }
|
17
|
-
|
18
|
-
SurusTextArrayRecord.create! :names => array
|
19
|
-
YamlArrayRecord.create! :names => array
|
20
|
-
|
21
|
-
num_reads = 3_000
|
22
|
-
|
23
|
-
puts
|
24
|
-
puts "Reading a single record with a #{num_elements} element array #{num_reads} times"
|
25
|
-
|
26
|
-
Benchmark.bm(8) do |x|
|
27
|
-
x.report("Surus") do
|
28
|
-
num_reads.times { SurusTextArrayRecord.first.names }
|
29
|
-
end
|
30
|
-
|
31
|
-
x.report("YAML") do
|
32
|
-
num_reads.times { YamlArrayRecord.first.names }
|
33
|
-
end
|
34
|
-
end
|
data/bench/hstore_create.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'benchmark_helper'
|
2
|
-
|
3
|
-
options = {}
|
4
|
-
optparse = OptionParser.new do |opts|
|
5
|
-
options[:records] = 200
|
6
|
-
opts.on '-r NUM', '--records NUM', Integer, 'Number of records to create' do |n|
|
7
|
-
options[:records] = n
|
8
|
-
end
|
9
|
-
|
10
|
-
options[:pairs] = 5
|
11
|
-
opts.on '-p NUM', '--pairs NUM', Integer, 'Number of key/value pairs' do |n|
|
12
|
-
options[:pairs] = n
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
optparse.parse!
|
17
|
-
|
18
|
-
clean_database
|
19
|
-
GC.disable
|
20
|
-
|
21
|
-
num_records = options[:records]
|
22
|
-
num_key_value_pairs = options[:pairs]
|
23
|
-
|
24
|
-
key_value_pairs = num_records.times.map do
|
25
|
-
num_key_value_pairs.times.each_with_object({}) do |n, hash|
|
26
|
-
hash[SecureRandom.hex(4)] = SecureRandom.hex(4)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
puts
|
31
|
-
puts "Writing #{num_records} records with #{num_key_value_pairs} string key/value pairs"
|
32
|
-
|
33
|
-
Benchmark.bm(8) do |x|
|
34
|
-
x.report("EAV") do
|
35
|
-
EavMasterRecord.transaction do
|
36
|
-
num_records.times do |i|
|
37
|
-
EavMasterRecord.create! :properties => key_value_pairs[i]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
x.report("Surus") do
|
43
|
-
SurusKeyValueRecord.transaction do
|
44
|
-
num_records.times do |i|
|
45
|
-
SurusKeyValueRecord.create! :properties => key_value_pairs[i]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
x.report("YAML") do
|
51
|
-
YamlKeyValueRecord.transaction do
|
52
|
-
num_records.times do |i|
|
53
|
-
YamlKeyValueRecord.create! :properties => key_value_pairs[i]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/bench/hstore_serialize.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'benchmark_helper'
|
2
|
-
|
3
|
-
options = {}
|
4
|
-
optparse = OptionParser.new do |opts|
|
5
|
-
options[:pairs] = 5
|
6
|
-
opts.on '-p NUM', '--pairs NUM', Integer, 'Number of key/value pairs' do |n|
|
7
|
-
options[:pairs] = n
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
optparse.parse!
|
12
|
-
|
13
|
-
clean_database
|
14
|
-
|
15
|
-
num_key_value_pairs = options[:pairs]
|
16
|
-
|
17
|
-
key_value_pair = num_key_value_pairs.times.each_with_object({}) do |n, hash|
|
18
|
-
hash[SecureRandom.hex(4)] = SecureRandom.hex(4)
|
19
|
-
end
|
20
|
-
|
21
|
-
EavMasterRecord.create! :properties => key_value_pair
|
22
|
-
SurusKeyValueRecord.create! :properties => key_value_pair
|
23
|
-
YamlKeyValueRecord.create! :properties => key_value_pair
|
24
|
-
|
25
|
-
num_reads = 3_000
|
26
|
-
|
27
|
-
puts
|
28
|
-
puts "Reading a single record with #{num_key_value_pairs} string key/value pairs #{num_reads} times"
|
29
|
-
|
30
|
-
Benchmark.bm(8) do |x|
|
31
|
-
x.report("EAV") do
|
32
|
-
num_reads.times { EavMasterRecord.first.properties }
|
33
|
-
end
|
34
|
-
|
35
|
-
x.report("Surus") do
|
36
|
-
num_reads.times { SurusKeyValueRecord.first.properties }
|
37
|
-
end
|
38
|
-
|
39
|
-
x.report("YAML") do
|
40
|
-
num_reads.times { YamlKeyValueRecord.first.properties }
|
41
|
-
end
|
42
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Surus
|
2
|
-
module Array
|
3
|
-
class DecimalSerializer
|
4
|
-
ARRAY_REGEX = %r{
|
5
|
-
(?<=[\{,]) (?# All elements are prefixed with either the opening brace or a comma)
|
6
|
-
\-?\d+\.?\d*
|
7
|
-
|
|
8
|
-
NULL
|
9
|
-
}x
|
10
|
-
|
11
|
-
def load(string)
|
12
|
-
return unless string
|
13
|
-
string.scan(ARRAY_REGEX).map do |match|
|
14
|
-
match == "NULL" ? nil : BigDecimal(match)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def dump(array)
|
19
|
-
return unless array
|
20
|
-
'{' + array.map { |s| format(s) }.join(",") + '}'
|
21
|
-
end
|
22
|
-
|
23
|
-
def format(value)
|
24
|
-
value == nil ? "NULL" : value
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Surus
|
2
|
-
module Array
|
3
|
-
class FloatSerializer
|
4
|
-
ARRAY_REGEX = %r{
|
5
|
-
(?<=[\{,]) (?# All elements are prefixed with either the opening brace or a comma)
|
6
|
-
\-?\d+(?:\.\d+)?(?:e[+-])?\d*
|
7
|
-
|
|
8
|
-
NULL
|
9
|
-
}x
|
10
|
-
|
11
|
-
def load(string)
|
12
|
-
return unless string
|
13
|
-
string.scan(ARRAY_REGEX).map do |match|
|
14
|
-
match == "NULL" ? nil : Float(match)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def dump(array)
|
19
|
-
return unless array
|
20
|
-
'{' + array.map { |s| format(s) }.join(",") + '}'
|
21
|
-
end
|
22
|
-
|
23
|
-
def format(value)
|
24
|
-
value == nil ? "NULL" : value
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
module Surus
|
2
|
-
module Array
|
3
|
-
class IntegerSerializer
|
4
|
-
ARRAY_REGEX = %r{
|
5
|
-
(?<=[\{,]) (?# All elements are prefixed with either the opening brace or a comma)
|
6
|
-
\-?\d+
|
7
|
-
|
|
8
|
-
NULL
|
9
|
-
}x
|
10
|
-
|
11
|
-
def load(string)
|
12
|
-
return unless string
|
13
|
-
string.scan(ARRAY_REGEX).map do |match|
|
14
|
-
match == "NULL" ? nil : Integer(match)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def dump(array)
|
19
|
-
return unless array
|
20
|
-
'{' + array.map { |s| format(s) }.join(",") + '}'
|
21
|
-
end
|
22
|
-
|
23
|
-
def format(value)
|
24
|
-
value == nil ? "NULL" : value
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module Surus
|
2
|
-
module Array
|
3
|
-
class TextSerializer
|
4
|
-
ARRAY_REGEX = %r{
|
5
|
-
[{,] (?# All elements are prefixed with either the opening brace or a comma)
|
6
|
-
(?:
|
7
|
-
"
|
8
|
-
(?<quoted_string>(?:[^"\\]|\\.)*)
|
9
|
-
"
|
10
|
-
|
|
11
|
-
(?<null>NULL)
|
12
|
-
|
|
13
|
-
(?<unquoted_string>[^,}]+)
|
14
|
-
)
|
15
|
-
}x
|
16
|
-
|
17
|
-
def load(string)
|
18
|
-
return unless string
|
19
|
-
string.scan(ARRAY_REGEX).map do |quoted_string, null, unquoted_string|
|
20
|
-
element = quoted_string || unquoted_string
|
21
|
-
element ? unescape(element) : nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def dump(array)
|
26
|
-
return unless array
|
27
|
-
'{' + array.map { |s| format(s) }.join(",") + '}'
|
28
|
-
end
|
29
|
-
|
30
|
-
def format(value)
|
31
|
-
value == nil ? "NULL" : '"' + escape(value) + '"'
|
32
|
-
end
|
33
|
-
|
34
|
-
def escape(value)
|
35
|
-
value
|
36
|
-
.gsub('\\', '\\\\\\')
|
37
|
-
.gsub('"', '\\"')
|
38
|
-
end
|
39
|
-
|
40
|
-
def unescape(value)
|
41
|
-
value
|
42
|
-
.gsub('\\\\', '\\')
|
43
|
-
.gsub('\\"', '"')
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'active_record/connection_adapters/postgresql_adapter'
|
2
|
-
|
3
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLColumn.class_eval do
|
4
|
-
def simplified_type_with_hstore(field_type)
|
5
|
-
field_type == 'hstore' ? :hstore : simplified_type_without_hstore(field_type)
|
6
|
-
end
|
7
|
-
|
8
|
-
alias_method_chain :simplified_type, :hstore
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
|
13
|
-
def native_database_types_with_hstore
|
14
|
-
native_database_types_without_hstore.merge({:hstore => { :name => "hstore" }})
|
15
|
-
end
|
16
|
-
|
17
|
-
alias_method_chain :native_database_types, :hstore
|
18
|
-
end
|
19
|
-
|
20
|
-
ActiveRecord::ConnectionAdapters::TableDefinition.class_eval do
|
21
|
-
# Adds hstore type for migrations. So you can add columns to a table like:
|
22
|
-
# create_table :people do |t|
|
23
|
-
# ...
|
24
|
-
# t.hstore :info
|
25
|
-
# ...
|
26
|
-
# end
|
27
|
-
def hstore(*args)
|
28
|
-
options = args.extract_options!
|
29
|
-
column_names = args
|
30
|
-
column_names.each { |name| column(name, 'hstore', options) }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
ActiveRecord::ConnectionAdapters::Table.class_eval do
|
35
|
-
# Adds hstore type for migrations. So you can add columns to a table like:
|
36
|
-
# change_table :people do |t|
|
37
|
-
# ...
|
38
|
-
# t.hstore :info
|
39
|
-
# ...
|
40
|
-
# end
|
41
|
-
def hstore(*args)
|
42
|
-
options = args.extract_options!
|
43
|
-
column_names = args
|
44
|
-
column_names.each { |name| column(name, 'hstore', options) }
|
45
|
-
end
|
46
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'active_record/connection_adapters/postgresql_adapter'
|
2
|
-
|
3
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLColumn.class_eval do
|
4
|
-
def simplified_type_with_json(field_type)
|
5
|
-
field_type == 'json' ? :json : simplified_type_without_json(field_type)
|
6
|
-
end
|
7
|
-
|
8
|
-
alias_method_chain :simplified_type, :json
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
|
13
|
-
def native_database_types_with_json
|
14
|
-
native_database_types_without_json.merge({:json => { :name => "json" }})
|
15
|
-
end
|
16
|
-
|
17
|
-
alias_method_chain :native_database_types, :json
|
18
|
-
end
|
19
|
-
|
20
|
-
ActiveRecord::ConnectionAdapters::TableDefinition.class_eval do
|
21
|
-
# Adds json type for migrations. So you can add columns to a table like:
|
22
|
-
# create_table :people do |t|
|
23
|
-
# ...
|
24
|
-
# t.json :info
|
25
|
-
# ...
|
26
|
-
# end
|
27
|
-
def json(*args)
|
28
|
-
options = args.extract_options!
|
29
|
-
column_names = args
|
30
|
-
column_names.each { |name| column(name, 'json', options) }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
ActiveRecord::ConnectionAdapters::Table.class_eval do
|
35
|
-
# Adds json type for migrations. So you can add columns to a table like:
|
36
|
-
# change_table :people do |t|
|
37
|
-
# ...
|
38
|
-
# t.json :info
|
39
|
-
# ...
|
40
|
-
# end
|
41
|
-
def json(*args)
|
42
|
-
options = args.extract_options!
|
43
|
-
column_names = args
|
44
|
-
column_names.each { |name| column(name, 'json', options) }
|
45
|
-
end
|
46
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Surus::Array::DecimalSerializer do
|
4
|
-
round_trip_examples = [
|
5
|
-
[nil, "nil"],
|
6
|
-
[[], "empty array"],
|
7
|
-
[[BigDecimal("0.0")], "single element"],
|
8
|
-
[[BigDecimal("1.0"), BigDecimal("2.0")], "multiple elements"],
|
9
|
-
[[BigDecimal("-1.0"), BigDecimal("-2.0")], "negative element"],
|
10
|
-
[[BigDecimal("1232493289348929843.323422349274382923")], "high magnitude element"],
|
11
|
-
[[BigDecimal("1.0"), BigDecimal("2.0"), BigDecimal("2.0")], "duplicated elements"],
|
12
|
-
[[BigDecimal("1.0"), nil], "an element is nil"],
|
13
|
-
[(10_000.times.map { |n| n * BigDecimal("1.13312") }).to_a, "huge array"]
|
14
|
-
]
|
15
|
-
|
16
|
-
round_trip_examples.each do |value, description|
|
17
|
-
it "round trips when #{description}" do
|
18
|
-
r = DecimalArrayRecord.create! :decimals => value
|
19
|
-
r.reload
|
20
|
-
expect(r.decimals).to eq(value)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Surus::Array::FloatSerializer do
|
4
|
-
round_trip_examples = [
|
5
|
-
[nil, "nil"],
|
6
|
-
[[], "empty array"],
|
7
|
-
[[0.0], "single element"],
|
8
|
-
[[1.0, 2.0], "multiple elements"],
|
9
|
-
[[-1.0, -2.0], "negative element"],
|
10
|
-
[[4.4325349e+45, 1.2324323e+77, 1.1242342e-57, 3e99], "high magnitude elements"],
|
11
|
-
[[1.0, 2.0, 2.0, 2.0], "duplicated elements"],
|
12
|
-
[[1.0, nil], "an element is nil"],
|
13
|
-
[(10_000.times.map { |n| n * 1.0 }).to_a, "huge array"]
|
14
|
-
]
|
15
|
-
|
16
|
-
round_trip_examples.each do |value, description|
|
17
|
-
it "round trips when #{description}" do
|
18
|
-
r = FloatArrayRecord.create! :floats => value
|
19
|
-
r.reload
|
20
|
-
expect(r.floats).to eq(value)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Surus::Array::IntegerSerializer do
|
4
|
-
round_trip_examples = [
|
5
|
-
[nil, "nil"],
|
6
|
-
[[], "empty array"],
|
7
|
-
[[0], "single element"],
|
8
|
-
[[1, 2], "multiple elements"],
|
9
|
-
[[-1, -2], "negative element"],
|
10
|
-
[[1, 2, 2, 2], "duplicated elements"],
|
11
|
-
[[1, nil], "an element is nil"],
|
12
|
-
[(1..10_000).to_a, "huge array"]
|
13
|
-
]
|
14
|
-
|
15
|
-
round_trip_examples.each do |value, description|
|
16
|
-
it "round trips when #{description}" do
|
17
|
-
r = IntegerArrayRecord.create! :integers => value
|
18
|
-
r.reload
|
19
|
-
expect(r.integers).to eq(value)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Surus::Array::TextSerializer do
|
4
|
-
round_trip_examples = [
|
5
|
-
[nil, "nil"],
|
6
|
-
[[], "empty array"],
|
7
|
-
[["foo"], "single element"],
|
8
|
-
[["foo", "bar"], "multiple elements"],
|
9
|
-
[["foo", "bar", "bar", "bar"], "duplicated elements"],
|
10
|
-
[["foo bar", nil], "an element is nil"],
|
11
|
-
[["foo bar", 'NULL'], "an element is the string 'NULL'"],
|
12
|
-
[["foo bar", "baz"], "an element has a space"],
|
13
|
-
[["foo,bar", "baz"], "an element has a comma (,)"],
|
14
|
-
[["foo'bar", "baz"], "an element has a single quote (')"],
|
15
|
-
[['foo"bar', "baz"], "an element has a double quote (\")"],
|
16
|
-
[['foo\\bar', "baz"], "an element has a backslash (\\)"],
|
17
|
-
[['foo{}bar', "{baz}"], "an element has a braces ({})"],
|
18
|
-
[[%q~foo \\ / " ; ' ( ) {}bar \\'~, "bar"], "an element many special characters"],
|
19
|
-
[("aaa".."zzz").to_a, "huge array"]
|
20
|
-
]
|
21
|
-
|
22
|
-
round_trip_examples.each do |value, description|
|
23
|
-
it "round trips when #{description}" do
|
24
|
-
r = TextArrayRecord.create! :texts => value
|
25
|
-
r.reload
|
26
|
-
expect(r.texts).to eq(value)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|