arc 0.0.1

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.
Files changed (41) hide show
  1. data/.gitignore +9 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +21 -0
  4. data/Rakefile +35 -0
  5. data/arc.gemspec +20 -0
  6. data/lib/arc.rb +13 -0
  7. data/lib/arc/casting.rb +66 -0
  8. data/lib/arc/data_stores.rb +9 -0
  9. data/lib/arc/data_stores/abstract/arel_compatibility.rb +50 -0
  10. data/lib/arc/data_stores/abstract/object_definitions.rb +55 -0
  11. data/lib/arc/data_stores/abstract/store.rb +55 -0
  12. data/lib/arc/data_stores/mysql/object_definitions.rb +54 -0
  13. data/lib/arc/data_stores/mysql/store.rb +51 -0
  14. data/lib/arc/data_stores/postgres/object_definitions.rb +70 -0
  15. data/lib/arc/data_stores/postgres/store.rb +38 -0
  16. data/lib/arc/data_stores/sqlite/object_definitions.rb +51 -0
  17. data/lib/arc/data_stores/sqlite/store.rb +43 -0
  18. data/lib/arc/quoting.rb +91 -0
  19. data/lib/arc/reactor.rb +29 -0
  20. data/lib/arc/version.rb +3 -0
  21. data/spec/casting_spec.rb +74 -0
  22. data/spec/data_stores/abstract/arel_compatibility_spec.rb +63 -0
  23. data/spec/data_stores/abstract/object_definitions_spec.rb +75 -0
  24. data/spec/data_stores/abstract/store_spec.rb +59 -0
  25. data/spec/data_stores/integration/crud_spec.rb +79 -0
  26. data/spec/data_stores/integration/schema_spec.rb +47 -0
  27. data/spec/data_stores/mysql/store_spec.rb +11 -0
  28. data/spec/data_stores/postgres/store_spec.rb +11 -0
  29. data/spec/data_stores/sqlite/store_spec.rb +11 -0
  30. data/spec/data_stores_spec.rb +15 -0
  31. data/spec/quoting_spec.rb +97 -0
  32. data/spec/spec_helper.rb +81 -0
  33. data/spec/support/config.yml +16 -0
  34. data/spec/support/resources/rails.png +0 -0
  35. data/spec/support/schemas/drop_mysql.sql +1 -0
  36. data/spec/support/schemas/drop_postgres.sql +1 -0
  37. data/spec/support/schemas/drop_sqlite.sql +1 -0
  38. data/spec/support/schemas/mysql.sql +10 -0
  39. data/spec/support/schemas/postgres.sql +12 -0
  40. data/spec/support/schemas/sqlite.sql +12 -0
  41. metadata +105 -0
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ require 'arc/data_stores/abstract/object_definitions'
3
+
4
+ module Arc
5
+ module DataStores
6
+ module ObjectDefinitions
7
+ describe ObjectDefinitions do
8
+ before :each do
9
+ @store = AbstractDataStore.new ArcTest.config[:empty]
10
+ end
11
+
12
+ describe Schema do
13
+ it 'includes Collector' do
14
+ Schema.included_modules.should include(Collector)
15
+ end
16
+ it 'aliases item_names to table_names' do
17
+ schema = Schema.new nil
18
+ schema.should respond_to(:table_names)
19
+ end
20
+ end
21
+
22
+ describe Table do
23
+ it 'includes Collector' do
24
+ Table.included_modules.should include(Collector)
25
+ end
26
+ it 'aliases item_names to column_names' do
27
+ table = Table.new nil, :superheros
28
+ table.should respond_to(:column_names)
29
+ end
30
+ describe '#new' do
31
+ it 'has a name' do
32
+ Table.new('superheros').name.should == 'superheros'
33
+ end
34
+ it 'sets the data store' do
35
+ Table.new('superheros', @store).instance_variable_get(:@data_store).should be(@store)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "Column#new" do
41
+ it 'sets the datastore' do
42
+ c = Column.new @store
43
+ c.instance_variable_get(:@data_store).should be(@store)
44
+ end
45
+ it "sets the column's name" do
46
+ c = Column.new nil, :name => :superheros
47
+ c.name.should == :superheros
48
+ end
49
+ it "sets the column's allows_null" do
50
+ c = Column.new nil, :allows_null => false
51
+ c.allows_null?.should == false
52
+ end
53
+ it "sets the column's default value" do
54
+ c = Column.new nil, :default => "superman"
55
+ c.default.should == "superman"
56
+ end
57
+ it "sets the column's primary_key?" do
58
+ c = Column.new nil, :primary_key => true
59
+ c.pk?.should be_true
60
+ c.primary_key?.should be_true
61
+ end
62
+ it "sets the string representation of the column's type" do
63
+ c = Column.new nil, :type => "INTEGER"
64
+ c.instance_variable_get(:@stype).should == "INTEGER"
65
+ end
66
+ it 'throws NotImplementedError when querying type' do
67
+ c = Column.new nil
68
+ ->{ c.type }.should raise_error(NotImplementedError)
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ module Arc
4
+ module DataStores
5
+ describe AbstractDataStore do
6
+ before :each do
7
+ @store = AbstractDataStore.new ArcTest.config[:empty]
8
+ @query = "omg"
9
+ end
10
+
11
+ it 'proxies methods to the schema' do
12
+ store = AbstractDataStore.new({})
13
+ schema = ObjectDefinitions::Schema.new(store)
14
+ schema.stub(:[]).and_return(ObjectDefinitions::Table.new :fake_table)
15
+ store.stub!(:schema).and_return(schema)
16
+ store[:fake_table].should be_a(ObjectDefinitions::Table)
17
+ end
18
+
19
+ it 'includes arel compatibility' do
20
+ @store.should be_a(ArelCompatibility)
21
+ end
22
+
23
+ it 'includes quoting module' do
24
+ @store.should be_a(Arc::Quoting)
25
+ end
26
+
27
+ describe '#new' do
28
+ it 'does not define connection creation' do
29
+ store = AbstractDataStore.new ArcTest.config[:sqlite]
30
+ ->{ store.send :with_store }.should raise_error(NotImplementedError)
31
+ end
32
+ end
33
+
34
+ describe 'abstract methods throw NotImplementedError' do
35
+ it '#schema raises not implemented error' do
36
+ ->{ @store.schema }.should raise_error(NotImplementedError)
37
+ end
38
+ it '#create raises not implemented error' do
39
+ ->{ @store.create @query }.should raise_error(NotImplementedError)
40
+ end
41
+ it '#read raises not implemented error' do
42
+ ->{ @store.read @query }.should raise_error(NotImplementedError)
43
+ end
44
+ it '#update raises not implemented error' do
45
+ ->{ @store.update @query }.should raise_error(NotImplementedError)
46
+ end
47
+ it '#destroy raises not implemented error' do
48
+ ->{ @store.destroy @query }.should raise_error(NotImplementedError)
49
+ end
50
+ it '#execute raises not implemented error' do
51
+ ->{ @store.execute @rquery }.should raise_error(NotImplementedError)
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+
59
+
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ module Arc
4
+ module DataStores
5
+ describe 'The data store crud operations' do
6
+
7
+ describe '#create' do
8
+ it 'creates a new record' do
9
+ ArcTest.with_store do |store|
10
+ query = "SELECT * FROM superheros WHERE name = 'green hornet'"
11
+ result = store.read query
12
+ result.size.should == 0
13
+
14
+ store.create "INSERT INTO superheros (name) VALUES('green hornet');"
15
+ store.read(query).size.should == 1
16
+
17
+ #cleanup
18
+ store.destroy "DELETE FROM superheros where name = 'green hornet'"
19
+ end
20
+ end
21
+
22
+ it 'returns the record with a populated primary key' do
23
+ ArcTest.with_store do |store|
24
+ result = store.create "INSERT INTO superheros (name) VALUES('green lantern')"
25
+ result[:id].should_not be_nil
26
+ result[:name].should == 'green lantern'
27
+ #cleanup
28
+ store.destroy "DELETE FROM superheros where name = 'green lantern'"
29
+ end
30
+ end
31
+ end
32
+
33
+ describe '#read' do
34
+ it 'reads existing data' do
35
+ heros = ['superman', 'batman', 'spiderman']
36
+ query = "SELECT * FROM superheros"
37
+
38
+ ArcTest.with_store do |store|
39
+ result = store.read query
40
+ result.size.should == 3
41
+ result.each do |h|
42
+ h.should be_a(Hash)
43
+ heros.should include(h[:name])
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ describe '#update' do
50
+ it 'updates a record and returns the updated record' do
51
+ ArcTest.with_store do |store|
52
+ query = "UPDATE superheros SET name = 'wussy' WHERE name = 'batman'"
53
+ result = store.update query
54
+ batman = store.read "SELECT * from superheros WHERE name = 'batman'"
55
+ batman.size.should == 0
56
+ batman.should be_a(Enumerable)
57
+ batman = store.read "SELECT * from superheros WHERE name = 'wussy'"
58
+ batman.first[:name].should == 'wussy'
59
+ end
60
+ end
61
+ end
62
+
63
+ describe '#destroy' do
64
+ it 'deletes a record' do
65
+ ArcTest.with_store do |store|
66
+ query = "SELECT * FROM superheros WHERE name = 'batman'"
67
+ batman = store.read query
68
+ batman.first[:name].should == 'batman'
69
+ store.destroy "DELETE FROM superheros WHERE name = 'batman'"
70
+ batman = store.read query
71
+ batman.size.should == 0
72
+ batman.should be_a(Enumerable)
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module Arc
4
+ module DataStores
5
+ module ObjectDefinitions
6
+ describe "All the Schemas!" do
7
+ it 'lists the table names' do
8
+ ArcTest.with_store do |store|
9
+ store.schema.table_names.should == [:superheros]
10
+ end
11
+ end
12
+
13
+ it 'provides a Table object for each table' do
14
+ ArcTest.with_store do |store|
15
+ heros = store[:superheros]
16
+ heros.should be_a(Table)
17
+ heros.column_names.should include(:id)
18
+ heros.column_names.should include(:name)
19
+ end
20
+ end
21
+
22
+ it 'provides a Column object for each column' do
23
+ ArcTest.with_store do |store|
24
+ heros = store[:superheros]
25
+ id = heros[:id]
26
+ id.should be_a(Column)
27
+ id.pk?.should be_true
28
+ id.allows_null?.should be_false
29
+ id.default.should be_nil
30
+ id.name.should == "id"
31
+ id.type.should == :integer
32
+
33
+ #name column
34
+ name = heros[:name]
35
+ name.should be_a(Column)
36
+ name.pk?.should be_false
37
+ name.allows_null?.should be_false
38
+ name.default.should be_nil
39
+ name.name.should == "name"
40
+ name.type.should == :varchar
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'arc/data_stores/mysql/store'
3
+
4
+ describe Arc::DataStores::MysqlDataStore do
5
+ describe "#schema" do
6
+ it 'is an instance of Arc::DataStores::MysqlSchema' do
7
+ store = Arc::DataStores::MysqlDataStore.new ArcTest.config[:mysql]
8
+ store.schema.should be_a(Arc::DataStores::ObjectDefinitions::MysqlSchema)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'arc/data_stores/postgres/store'
3
+
4
+ describe Arc::DataStores::PostgresDataStore do
5
+ describe "#schema" do
6
+ it 'is an instance of Arc::DataStores::PostgresSchema' do
7
+ store = Arc::DataStores::PostgresDataStore.new ArcTest.config[:Postgres]
8
+ store.schema.should be_a(Arc::DataStores::ObjectDefinitions::PostgresSchema)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'arc/data_stores/sqlite/store'
3
+
4
+ describe Arc::DataStores::SqliteDataStore do
5
+ describe "#schema" do
6
+ it 'is an instance of Arc::DataStores::SqliteSchema' do
7
+ store = Arc::DataStores::SqliteDataStore.new(:database => ":memory:")
8
+ store.schema.should be_a(Arc::DataStores::ObjectDefinitions::SqliteSchema)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ module Arc
4
+ describe DataStores do
5
+ it 'extends Q::Dispatcher' do
6
+ DataStores.should be_a(Q::Dispatcher)
7
+ end
8
+ it "specifies 'DataStore' as the constant_suffix" do
9
+ DataStores.instance_variable_get(:@constant_suffix).should == "DataStore"
10
+ end
11
+ it "specifies 'arc/data_stores/%s_data_store' as the require_pattern" do
12
+ DataStores.instance_variable_get(:@require_pattern).should == "arc/data_stores/%s/store.rb"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ module Arc
4
+ describe Quoting do
5
+ describe '#quote' do
6
+ def quoter
7
+ @quoter ||= Class.new { include Quoting }.new
8
+ end
9
+ it 'quotes a column name' do
10
+ quoter.quote_column('my_column').should == '"my_column"'
11
+ end
12
+ it 'quotes a table name' do
13
+ t = 'my_table'
14
+ quoter.should_receive(:quote_column_name).with(t)
15
+ quoter.quote_table(t)
16
+ end
17
+ it 'should throw an exception if it cannot find a convertible class' do
18
+ ->{ quoter.quote(Class.new.new) }.should raise_error(Quoting::CannotCastValueError)
19
+ end
20
+ it 'should wrap the symbol using single quotes' do
21
+ quoter.quote(:superman).should == "'superman'"
22
+ quoter.quote('superman', Symbol).should == "'superman'"
23
+ end
24
+ it 'quotes a string' do
25
+ quoter.quote("\\").should == "'\\\\'"
26
+ quoter.quote("'").should == "''''"
27
+ quoter.quote("my%String", String).should == "'my%String'"
28
+ end
29
+ it 'quotes a date object' do
30
+ date = Date.today
31
+ fmt = '%Y-%m-%d'
32
+ quoter.quote(date).should == "'#{date.strftime fmt}'"
33
+ quoter.quote(date.strftime(fmt), Date).should == "'#{date.strftime fmt}'"
34
+ end
35
+ it 'quotes a time object' do
36
+ time = Time.now
37
+ fmt = '%Y-%m-%d %H:%M:%S'
38
+ quoter.quote(time).should == "'#{time.strftime fmt}'"
39
+ quoter.quote(time.strftime(fmt), Time).should == "'#{time.strftime fmt}'"
40
+ end
41
+ it 'quotes a fixnum' do
42
+ fixnum = 10
43
+ quoter.quote(fixnum).should == fixnum.to_s
44
+ quoter.quote(fixnum.to_s, Fixnum).should == fixnum.to_s
45
+ quoter.quote(fixnum.to_s, nil)
46
+ end
47
+ it 'quotes a bignum' do
48
+ bignum = 1<<100
49
+ quoter.quote(bignum).should == bignum.to_s
50
+ quoter.quote(bignum.to_s, Bignum).should == bignum.to_s
51
+ end
52
+ it 'quotes a float' do
53
+ float = 1.2
54
+ quoter.quote(float).should == float.to_s
55
+ quoter.quote(float, Float).should == float.to_s
56
+ end
57
+ it 'quotes a class name' do
58
+ klass = String
59
+ quoter.quote(klass).should == "'String'"
60
+ end
61
+ it 'quotes boolean values' do
62
+ quoter.quote(true, :boolean).should == "'t'"
63
+ quoter.quote(false, :boolean).should == "'f'"
64
+ end
65
+ it 'quotes an object based on column type' do
66
+ superman = "superman"
67
+ ArcTest.with_store do |store|
68
+ c = store[:superheros][:name]
69
+ quoter.quote(superman, c).should == "'superman'"
70
+ c = store[:superheros][:id]
71
+ quoter.quote(10, c).should == '10'
72
+ end
73
+ end
74
+ it 'quotes a bigdecimal' do
75
+ big_decimal = BigDecimal.new((1 << 100).to_s)
76
+ quoter.quote(big_decimal).should == big_decimal.to_s('F')
77
+ quoter.quote(big_decimal.to_s('F'), BigDecimal).should == big_decimal.to_s('F')
78
+ end
79
+ it 'quotes nil' do
80
+ quoter.quote(nil).should == 'NULL'
81
+ quoter.quote('NULL', NilClass).should == 'NULL'
82
+ quoter.quote(nil, NilClass).should == 'NULL'
83
+ end
84
+ it 'quotes true' do
85
+ quoter.quote(true).should == "'t'"
86
+ quoter.quote('true', TrueClass).should == "'t'"
87
+ end
88
+ it 'quotes false' do
89
+ quoter.quote(false).should == "'f'"
90
+ quoter.quote('false', FalseClass).should == "'f'"
91
+ end
92
+ it 'escapes and quotes a binary string' do
93
+ quoter.quote("\0%", :binary).should == "'%00%25'"
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,81 @@
1
+ #generate a coverage report
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ require 'bundler/setup'
6
+ require 'rspec'
7
+ require 'arc'
8
+ require 'arel'
9
+ require 'q/resource_pool'
10
+
11
+
12
+ RSpec.configure do |config|
13
+ config.after(:all) do
14
+ ArcTest.drop
15
+ end
16
+ end
17
+
18
+ module ArcTest
19
+ DEFAULT_ADAPTER = 'sqlite'
20
+
21
+ class StoreProvider < ResourcePool
22
+ def create_resource
23
+ Arc::DataStores[ArcTest.adapter].new ArcTest.current_config
24
+ end
25
+ end
26
+
27
+ class << self
28
+
29
+ def config_key
30
+ @config_key ||= (ENV['ARC_ENV'] ||= ArcTest::DEFAULT_ADAPTER).to_sym
31
+ end
32
+
33
+ def file_root
34
+ @file_root ||= "#{File.dirname __FILE__}/support/schemas"
35
+ end
36
+
37
+ def config
38
+ @config ||= YAML::load(File.read "#{File.dirname __FILE__}/support/config.yml").symbolize_keys!
39
+ end
40
+
41
+ def drop
42
+ return unless @schema_loaded
43
+ @drop_ddl ||= File.read "#{file_root}/drop_#{config_key}.sql"
44
+ provider.with_resource { |store| store.schema.execute_ddl @drop_ddl }
45
+ @schema_loaded = false
46
+ end
47
+
48
+ def load_schema
49
+ return if @schema_loaded
50
+ @ddl ||= File.read "#{file_root}/#{config_key}.sql"
51
+ provider.with_resource { |store| store.schema.execute_ddl @ddl }
52
+ @schema_loaded = true
53
+ end
54
+
55
+ def reset_schema
56
+ drop
57
+ load_schema
58
+ end
59
+
60
+ def with_store
61
+ reset_schema
62
+ provider.with_resource do |store|
63
+ yield store
64
+ end
65
+ end
66
+
67
+ def current_config
68
+ config[config_key]
69
+ end
70
+
71
+ def adapter
72
+ current_config[:adapter].to_sym
73
+ end
74
+
75
+ private
76
+ def provider
77
+ @provider ||= StoreProvider.new nil
78
+ end
79
+ end
80
+
81
+ end