arc 0.0.3 → 0.0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ #Arc (**Ar**el **C**onnection)
2
+ Arc is a database connection engine that provides everything Arel needs to construct an AST.
3
+ You can use sqlite, postgresql and/or mysql.
4
+
5
+ Arc gives you:
6
+
7
+ - quoting and casting of values as they enter and exit the data store
8
+ - standard and **thread safe** CRUD interface for executing queries
9
+ - a hash-like interface that provides information about the tables and columns in your database (see below)
10
+
11
+ There are two dependencies: [q][6] and arel itself.
12
+
13
+ Arc lets you use arel without the cost of including active record as a dependency.
14
+
15
+ [Arel][1] is a very capable and [inspired][2] bit of code which provides machinery for building an [abstract syntax tree][2](ast) of a complex sql query in pure ruby.
16
+
17
+
18
+ ##Arc is *not*:
19
+ Arc isn't an ORM.
20
+ There has been some [recent discussion][4] about the state of ruby ORMs. Arc does not make any attempt to [pass judgement][5] against any of the fine ORMs out there. Arc came out of a need for a lighter weight method for manipulating data in a database. Arc gives developers flexibility to build their own frameworks and write smaller libraries with fewer dependencies.
21
+
22
+ ##Installation
23
+ Add this to your Gemfile
24
+ gem 'pg' #'mysql2' or 'sqlite'
25
+ gem 'arc'
26
+
27
+ ##Basics
28
+ ####Connect to a database:
29
+
30
+ require 'arc'
31
+ @store = Arc::DataStores[:postgres].new({
32
+ database: arc_development,
33
+ host: localhost,
34
+ user: superman
35
+ })
36
+ @store[:superheros]
37
+ # => <Arc::DataStores::ObjectDefinitions::SqliteTable:0x007f86d4026f68 @name="superheros">
38
+ @store[:superheros].column_names
39
+ # => [:is_awesome, :name, :id ]
40
+ @store[:superheros][:id]
41
+ # => #<Arc::DataStores::ObjectDefinitions::SqliteColumn @name='id'>
42
+ @store[:superheros][:id].primary_key?
43
+ # => true
44
+ @store[:superheros][:is_awesome].type
45
+ # => :bool
46
+
47
+ ####Execute a query
48
+ Build an Arel query and pass it to one of the store's CRUD methods:
49
+
50
+ "Read" Example:
51
+
52
+ s = Arel::Table.new :superheros
53
+ s.project(s[:name], s[:id], s[:is_awesome])
54
+ @store.read s
55
+ # => [{ :id => 1, :name => 'superman', :is_awesome => true }
56
+ # => { :id => 2, :name => 'batman', :is_awesome => false }
57
+ # => { :id => 3, :name => 'ironman', :is_awesome => nil }]
58
+
59
+ "Create" example
60
+
61
+ im = Arel::InsertManager.new
62
+ im.insert([
63
+ [superheros[:name], 'green hornet'],
64
+ [superheros[:is_awesome], true]
65
+ ])
66
+ @store.create im
67
+ # => { :id => 4, :name => 'green hornet', :is_awesome => true }
68
+
69
+ ##Advanced
70
+ Arc handles some of the more complex features of arel, like complex joins:
71
+
72
+ s = Arel::Table.new :superheros
73
+ sp = Arel::Table.new :superheros_powers
74
+ p = Arel::Table.new :powers
75
+ stmt = s.join(sp).on(s[:id].eq(sp[:superhero_id]))
76
+ .join(p).on(p[:id].eq(sp[:power_id]))
77
+ .project(
78
+ s[:name].as('superhero_name'),
79
+ p[:name].as('power_name')
80
+ )
81
+ @store.read stmt
82
+ # => [{:superhero_name => 'superman', :power_name => 'flight'},
83
+ # => {:superhero_name => 'superman', :power_name => 'x-ray-vision'},
84
+ # => {:superhero_name => 'batman', :power_name => "a belt'}]
85
+
86
+ ##TODO
87
+ Arc is a new library. The test suite has excellent coverage, but bugs need to be identified, tested and fixed.
88
+ Next step is to add RDoc magic.
89
+ A long term goal would be to add on to the schema interface to allow for some ddl operations.
90
+
91
+ ##Development
92
+ Install dependencies with bundler
93
+ Make sure you have bundler installed, point your terminal to the project's root directory and run
94
+
95
+ $ bundle install
96
+ Running the tests:
97
+
98
+ $ rake test
99
+ To run the tests agains a particular adapter
100
+
101
+ $ rake test:adapter[<your-adapter-here>]
102
+
103
+
104
+ [1]: http://github.com/rails/arel
105
+ [2]: http://twitter.com/#!/jacobsimeon/status/97183215013466113
106
+ [3]: http://en.wikipedia.org/wiki/Abstract_syntax_tree
107
+ [4]: http://solnic.eu/2011/11/29/the-state-of-ruby-orm.html
108
+ [5]: https://github.com/garybernhardt/base
109
+ [6]: http://github.com/jacobsimeon/q
@@ -0,0 +1,74 @@
1
+ #Arc (**AR**el **C**onnection)
2
+ Arc lets you use arel without the cost of including active record as a dependency.
3
+ [Arel][1] is a very capable and [inspired][2] bit of code which provides machinery for building an [abstract syntax tree][2](ast) of a complex sql query in pure ruby.
4
+
5
+ ##Arc is:
6
+ Arc is a database connection engine that provides everything Arel needs to construct an AST
7
+ Arc supports sqlite, postgresql and mysql
8
+
9
+ @store = Arel::Table.engine = Arc::DataStores[:sqlite].new :database => ":memory:"
10
+ superheros = Arel::Table.new :superheros
11
+ query = superheros.project(
12
+ superheros[:name],
13
+ superheros[:is_awesome]
14
+ )
15
+ @result = @store.read(query)
16
+ # => [{ :name => 'superman', :is_awesome => true },
17
+ # => { :name => 'batman', :is_awesome => false }]
18
+
19
+ Arc handles quoting and casting of values when you create or update records and results are wrapped in lazy loading arrays and hashes.
20
+ <<<<<<< HEAD
21
+
22
+ =======
23
+ >>>>>>> e11634854b0583300a597ff8b7850d55048d8323
24
+ @result.class
25
+ # => Array
26
+ @result[0].class
27
+ # => Hash
28
+ @result[0][:is_awesome].class
29
+ # => TrueClass
30
+
31
+ Arc provides a standard and **thread safe** CRUD interface for executing queries
32
+ <<<<<<< HEAD
33
+
34
+ =======
35
+ >>>>>>> e11634854b0583300a597ff8b7850d55048d8323
36
+ @store.read superheros.project(superheros[:name])
37
+ # => [<superhero names here>]
38
+ im = Arel::InsertManager
39
+ im.insert([superheros[name], 'ironman'])
40
+ @store.create im
41
+ # => { :id => 3, :name => 'batman', :is_awesome => nil }
42
+ Arel::Table.engine
43
+
44
+ Arc tells what kind of schema you're working with
45
+ <<<<<<< HEAD
46
+
47
+ =======
48
+ >>>>>>> e11634854b0583300a597ff8b7850d55048d8323
49
+ @store[:superheros]
50
+ # => <Arc::DataStores::ObjectDefinitions::SqliteTable:0x007f86d4026f68 @name="superheros">
51
+ @store[:superheros].column_names
52
+ # => [:is_awesome, :name, :id ]
53
+ @store[:superheros][:id]
54
+ # => #<Arc::DataStores::ObjectDefinitions::SqliteColumn @name='id'>
55
+ @store[:superheros][:id].primary_key?
56
+ # => true
57
+ @store[:superheros][:is_awesome].type
58
+ # => :bool
59
+
60
+ ##Arc is *not*:
61
+ Arc is **not** an ORM.
62
+ There has been some [recent discussion][4] about the state of ruby ORMs. Arc does not make any attempt to [pass judgement][5] against any of the fine ORMs out there. Arc came out of a need for a lighter weight method for manipulating data in a database. Arc gives developers flexibility to build their own frameworks and write smaller libraries with fewer dependencies.
63
+
64
+ ##Setup
65
+
66
+ ##Basics
67
+
68
+ ##Advanced
69
+
70
+ [1]: http://github.com/rails/arel
71
+ [2]: http://twitter.com/#!/jacobsimeon/status/97183215013466113
72
+ [3]: http://en.wikipedia.org/wiki/Abstract_syntax_tree
73
+ [4]: http://solnic.eu/2011/11/29/the-state-of-ruby-orm.html
74
+ [5]: https://github.com/garybernhardt/base
data/Rakefile CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'yaml'
3
+
2
4
  task :test do
3
5
  ['sqlite', 'postgres', 'mysql'].each do |environment|
4
6
  puts "Running tests for environment #{environment}"
@@ -29,6 +31,16 @@ task :yank do
29
31
  end
30
32
 
31
33
  namespace :test do
34
+ task :integration do
35
+ before = ENV['ARC_ENV']
36
+ adapters = YAML::load(File.read("./spec/support/config.yml")).keys
37
+ adapters.each do |adapter|
38
+ ENV['ARC_ENV'] = adapter
39
+ puts "Running integration test for adapter: #{adapter}"
40
+ system "rspec spec/integration_spec.rb"
41
+ end
42
+ ENV['ARC_ENV'] = before
43
+ end
32
44
  task :adapter, :env do |task, args|
33
45
  ENV['ARC_ENV'] = args.env
34
46
  system 'rspec spec/data_stores/integration/'
data/lib/arc.rb CHANGED
@@ -8,4 +8,12 @@ require 'q/symbol'
8
8
  require 'q/dispatcher'
9
9
 
10
10
  require "arc/version"
11
- require 'arc/data_stores'
11
+ require 'arc/data_stores/abstract/store'
12
+
13
+ module Arc
14
+ module DataStores
15
+ extend Q::Dispatcher
16
+ require_pattern "arc/data_stores/%s/store.rb"
17
+ constant_suffix "DataStore"
18
+ end
19
+ end
@@ -12,7 +12,7 @@ module Arc
12
12
  def execute_ddl ddl
13
13
  case ddl
14
14
  when Array
15
- ddl.each { |s| @data_store.execute s }
15
+ ddl.each { |s| @data_store.execute s }
16
16
  when String
17
17
  execute_ddl ddl.split(';')
18
18
  end
@@ -18,28 +18,66 @@ module Arc
18
18
  raise NotImplementedError
19
19
  end
20
20
 
21
- def create query
22
- #add new data
23
- raise NotImplementedError
24
- end
25
-
26
21
  def read query
27
- #read existing data
28
- raise NotImplementedError
22
+ case query
23
+ when String
24
+ execute(query).symbolize_keys!
25
+ when Arel::SelectManager
26
+ result_for query
27
+ end
29
28
  end
30
-
31
- def update query
32
- #update existing data
33
- raise NotImplementedError
29
+
30
+ def create stmt
31
+ case stmt
32
+ when String
33
+ execute stmt
34
+ when Arel::InsertManager
35
+ table = stmt.instance_variable_get(:@ast).relation
36
+ execute stmt.to_sql
37
+ projections = schema[table.name.to_sym].column_names.map{ |c| table[c.to_sym] }
38
+ read(
39
+ table.project(*projections).where(
40
+ table.primary_key.eq(
41
+ Arel.sql(last_insert_rowid(table.name, table.primary_key.name).to_s)
42
+ )
43
+ )
44
+ )[0]
45
+ end
34
46
  end
35
-
36
- def destroy query
37
- #destroy existing data
38
- raise NotImplementedError
47
+
48
+ def update stmt, id=nil
49
+ case stmt
50
+ when String
51
+ execute stmt
52
+ when Arel::UpdateManager
53
+ execute stmt.to_sql
54
+ if id
55
+ table = stmt.instance_variable_get(:@ast).relation
56
+ projections = schema[table.name.to_sym].column_names.map{ |c| table[c.to_sym] }
57
+ read(
58
+ table.project(*projections)
59
+ .where(table.primary_key.eq id)
60
+ )[0]
61
+ end
62
+ end
63
+ end
64
+
65
+ def destroy stmt
66
+ case stmt
67
+ when String
68
+ execute stmt
69
+ when Arel::DeleteManager
70
+ execute stmt.to_sql
71
+ end
72
+ end
73
+
74
+ def last_insert_rowid table_name, pk_name
75
+ 'last_insert_rowid()'
39
76
  end
40
77
 
41
78
  def execute query
42
79
  #adapters should override this method to execute a query against the database
80
+ #the methods should return an array-like object of hash-like objects
43
81
  raise NotImplementedError
44
82
  end
45
83
  alias :with_store :with_resource
@@ -8,38 +8,16 @@ Mysql2::Client.default_query_options.merge!({
8
8
  module Arc::DataStores
9
9
  class MysqlDataStore < AbstractDataStore
10
10
 
11
- def read query
12
- case query
13
- when String
14
- execute(query).entries
15
- when Arel::SelectManager
16
- result_for query
17
- end
18
- end
19
-
20
- def create sql
21
- table = sql.match(/\AINSERT into ([^ (]*)/i)[1]
22
- execute sql
23
- read("select * from #{table} where id = " + last_row_id.to_s).first
24
- end
25
-
26
- def update sql
27
- execute sql
28
- end
29
-
30
- def destroy sql
31
- execute sql
32
- end
33
-
34
11
  def quote_column_name table
35
12
  "`#{table}`"
36
13
  end
37
14
  alias :quote_column :quote_column_name
38
15
 
39
16
  def execute query
40
- with_store do |store|
17
+ result = with_store do |store|
41
18
  store.query query
42
19
  end
20
+ result.entries if result.respond_to? :entries
43
21
  end
44
22
 
45
23
  def schema
@@ -61,7 +39,7 @@ module Arc::DataStores
61
39
  Mysql2::Client.new @config
62
40
  end
63
41
 
64
- def last_row_id
42
+ def last_insert_rowid table, column
65
43
  with_store do |store|
66
44
  store.last_id
67
45
  end
@@ -5,28 +5,10 @@ module Arc
5
5
  module DataStores
6
6
  class PostgresDataStore < AbstractDataStore
7
7
 
8
- def read query
9
- case query
10
- when String
11
- execute(query).to_a.symbolize_keys!
12
- when Arel::SelectManager
13
- result_for query
14
- end
15
- end
16
-
17
- def create sql
18
- table = sql.match(/\AINSERT into ([^ (]*)/i)[1]
19
- sql[-1] = sql[-1] == ';' ? '' : sql[-1]
20
- sql += " RETURNING id" unless sql =~ /returning/
21
- id = execute(sql).to_a[0].first[1]
22
- read("select * from #{table} where id = #{id}")[0]
23
- end
24
8
  def execute query
25
- with_store { |connection| connection.exec query }
9
+ with_store { |connection| connection.exec query }.to_a.symbolize_keys!
26
10
  end
27
- alias :destroy :execute
28
- alias :update :execute
29
-
11
+
30
12
  def schema
31
13
  @schema ||= ObjectDefinitions::PostgresSchema.new self
32
14
  end
@@ -43,6 +25,10 @@ module Arc
43
25
  end
44
26
  end
45
27
 
28
+ def last_insert_rowid table, field
29
+ id = execute("SELECT currval('#{table}_#{field}_seq');")[0][:currval]
30
+ end
31
+
46
32
  private
47
33
  def create_connection
48
34
  PGconn.connect({
@@ -4,33 +4,10 @@ require 'arc/data_stores/sqlite/object_definitions'
4
4
  module Arc
5
5
  module DataStores
6
6
  class SqliteDataStore < AbstractDataStore
7
-
8
- def read query
9
- case query
10
- when String
11
- execute(query).symbolize_keys!
12
- when Arel::SelectManager
13
- result_for query
14
- end
15
- end
16
-
17
- def create sql
18
- table = sql.match(/\AINSERT into ([^ (]*)/i)[1]
19
- execute sql
20
- read("select * from #{table} where id = last_insert_rowid();")[0]
21
- end
22
-
23
- def update sql
24
- execute sql
25
- end
26
-
27
- def destroy sql
28
- execute sql
29
- end
30
7
 
31
8
  def execute query
32
9
  with_store do |connection|
33
- result = connection.execute(query)
10
+ result = connection.execute(query).symbolize_keys!
34
11
  end
35
12
  end
36
13
 
@@ -1,3 +1,3 @@
1
1
  module Arc
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.3.1"
3
3
  end
@@ -3,59 +3,41 @@ require 'spec_helper'
3
3
  module Arc
4
4
  module DataStores
5
5
  describe ArelCompatibility do
6
- it '#specifies which arel visitor to use' do
7
- ArcTest.with_store do |s|
8
- Arel::Visitors.for s
9
- end
10
- end
11
- it '#responds to #connection_pool#spec#config' do
12
- ArcTest.with_store do |s|
13
- s.connection_pool.spec.config[:adapter].should == ArcTest.config_key.to_s
14
- end
6
+
7
+ before :all do
8
+ @s = ArcTest.get_store
15
9
  end
16
- it 'responds to #with_connection and yields an object which has an execute method' do
17
- ArcTest.with_store do |s|
18
- s.with_connection do |connection|
19
- s.connection.should respond_to(:execute)
20
- end
10
+
11
+ it '#responds to #connection_pool#spec#config' do
12
+ @s.connection_pool.spec.config[:adapter].should == ArcTest.adapter.to_s
13
+ end
14
+ it 'responds to #with_connection and yields an object which has an execute method' do
15
+ @s.with_connection do |connection|
16
+ connection.should respond_to(:execute)
21
17
  end
22
18
  end
23
19
  it 'provides a visitor at #connection.visitor' do
24
- ArcTest.with_store do |s|
25
- s.stub!(:visitor).and_return("lol")
26
- s.connection.visitor.should == "lol"
27
- end
20
+ @s.stub!(:visitor).and_return("lol")
21
+ @s.connection.visitor.should == "lol"
28
22
  end
29
23
  it "aliases #quote_table to #quote_table_name" do
30
- ArcTest.with_store do |s|
31
- s.method(:quote_table).should == s.method(:quote_table_name)
32
- end
24
+ @s.method(:quote_table).should == @s.method(:quote_table_name)
33
25
  end
34
26
  it 'aliases quote_column to #quote_column_name' do
35
- ArcTest.with_store do |s|
36
- s.method(:quote_column).should == s.method(:quote_column_name)
37
- end
27
+ @s.method(:quote_column).should == @s.method(:quote_column_name)
38
28
  end
39
29
  it 'provides a table_exists? method' do
40
- ArcTest.with_store do |s|
41
- s.table_exists?(:superheros).should be_true
42
- end
30
+ @s.table_exists?(:superheros).should be_true
43
31
  end
44
32
  it 'provides a hashlike object at #connection_pool.columns_hash' do
45
- ArcTest.with_store do |s|
46
- s.connection_pool.columns_hash.should be(s)
47
- end
33
+ @s.connection_pool.columns_hash.should be(@s)
48
34
  end
49
35
  it 'responds to primary_key given a table name' do
50
- ArcTest.with_store do |s|
51
- s.connection.primary_key(:superheros).should be(:id)
52
- end
36
+ @s.connection.primary_key(:superheros).should be(:id)
53
37
  end
54
38
  it 'should quote a hash' do
55
- ArcTest.with_store do |s|
56
- hash = {:a => :b}
57
- s.quote_hash(hash).should == "'#{hash.to_yaml}'"
58
- end
39
+ hash = {:a => :b}
40
+ @s.quote_hash(hash).should == "'#{hash.to_yaml}'"
59
41
  end
60
42
 
61
43
  end
@@ -6,7 +6,7 @@ module Arc
6
6
  before :each do
7
7
  @store = AbstractDataStore.new ArcTest.config[:empty]
8
8
  @query = "omg"
9
- @sstore = Arc::DataStores[:sqlite].new ArcTest.config[:sqlite]
9
+ @sstore = Arc::DataStores[:sqlite].new ArcTest._config[:sqlite]
10
10
  @sstore.schema.execute_ddl File.read("spec/support/schemas/sqlite.sql")
11
11
  Arel::Table.engine = @sstore
12
12
  end
@@ -3,7 +3,7 @@ require 'arc/data_stores/mysql/store'
3
3
 
4
4
  describe Arc::DataStores::MysqlDataStore do
5
5
  before :each do
6
- @store = Arc::DataStores[:mysql].new ArcTest.config[:mysql]
6
+ @store = Arc::DataStores[:mysql].new ArcTest._config[:mysql]
7
7
  end
8
8
 
9
9
  it 'saves binary data', :wip => true do
@@ -3,7 +3,7 @@ require 'arc/data_stores/postgres/store'
3
3
 
4
4
  describe Arc::DataStores::PostgresDataStore do
5
5
  before :each do
6
- @store = Arc::DataStores[:postgres].new ArcTest.config[:postgres]
6
+ @store = Arc::DataStores[:postgres].new ArcTest._config[:postgres]
7
7
  ddl = File.read "spec/support/schemas/postgres.sql"
8
8
  @store.schema.execute_ddl ddl
9
9
  end
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arc do
4
+ #thread safety
5
+ #create a record
6
+ #read a record
7
+ #complex query
8
+ #update a record
9
+ #destroy a record
10
+
11
+ #convenience method for building a tree of arel values
12
+ def values_array table_name, hash
13
+ hash.keys.map do |attr|
14
+ [@tables[table_name][attr], hash[attr]]
15
+ end
16
+ end
17
+
18
+ #grab a superhero record by name
19
+ def get_hero(hero_name)
20
+ query = @tables[:superheros]
21
+ .project('*')
22
+ .where(@tables[:superheros][:name].eq(hero_name))
23
+ .to_sql
24
+ @store.read query
25
+ end
26
+
27
+ before :all do
28
+ @store = ArcTest.get_store
29
+ @tables = Hash.new do |hash, key|
30
+ hash[key] = Arel::Table.new key
31
+ end
32
+ end
33
+
34
+ it "Safely executes queries initiated on different threads" do
35
+ threads = []
36
+ s = @tables[:superheros]
37
+ query = s.project( s[:name] )
38
+ result = @store.read(query)[0][:name]
39
+ 5.times do
40
+ threads << Thread.start do
41
+ Thread.current[:result] = @store.read(query)[0][:name]
42
+ end
43
+ end
44
+ names = threads.map {|t| t.join; t[:result] }
45
+ names.each {|n| n.should == result }
46
+ end
47
+
48
+ describe '#create and #read' do
49
+ before :each do
50
+ Timecop.freeze Time.now do
51
+ @created_at = Time.parse('2011-12-27 11:52:56 -0700')
52
+ properties = {
53
+ :name => "green hornet",
54
+ :born_on => @created_at,
55
+ :photo => File.read('spec/support/resources/ironman.gif'),
56
+ :created_at => @created_at
57
+ }
58
+ im = Arel::InsertManager.new Arel::Table.engine
59
+ im.insert values_array(:superheros, properties)
60
+ @result = @store.create im
61
+ end
62
+ end
63
+
64
+ it 'creates a new record' do
65
+ superheros = @tables[:superheros]
66
+ query = @tables[:superheros]
67
+ .project(
68
+ superheros[:name],
69
+ superheros[:born_on],
70
+ superheros[:created_at],
71
+ superheros[:photo]
72
+ )
73
+ .where(@tables[:superheros][:name].eq('green hornet'))
74
+ result = @store.read query
75
+ result[0][:name].should == 'green hornet'
76
+ result[0][:born_on].should == Date.today
77
+ result[0][:created_at].should == @created_at
78
+ result[0][:photo].should == File.read('spec/support/resources/ironman.gif').force_encoding("BINARY")
79
+ end
80
+
81
+ it 'returns the record with a populated primary key' do
82
+ @result[:id].should_not be_nil
83
+ @result[:name].should == 'green hornet'
84
+ @result[:born_on].should == Date.today
85
+ end
86
+
87
+ end
88
+
89
+ describe '#update' do
90
+ it 'updates a record (and returns the updated record when passing an id)' do
91
+ s = @tables[:superheros]
92
+ stmt = s.project(s[:id]).where(s[:name].eq('megaman'))
93
+ id = @store.read(stmt)[0][:id]
94
+
95
+ properties = {:name => 'batman'}
96
+ um = Arel::UpdateManager.new @store
97
+ um.table @tables[:superheros]
98
+ um.set(values_array(:superheros, properties))
99
+ .where(@tables[:superheros][:name].eq('megaman'))
100
+ result = @store.update um, id
101
+ result[:name].should == 'batman'
102
+ result[:born_on].should be_a(Date)
103
+
104
+ megaman = get_hero('megaman')
105
+ megaman.size.should == 0
106
+ megaman.should be_a(Enumerable)
107
+
108
+ batman = get_hero('batman')
109
+ batman.size.should == 1
110
+ batman.first[:name].should == 'batman'
111
+ end
112
+ end
113
+
114
+ describe '#destroy' do
115
+ it 'deletes a record' do
116
+ delete = Arel::DeleteManager.new @store
117
+ delete
118
+ .from(@tables[:superheros])
119
+ .where(@tables[:superheros][:name].eq('superman'))
120
+ @store.destroy delete
121
+ superman = get_hero('superman')
122
+ superman.size.should == 0
123
+ superman.size.should == 0
124
+ superman.should be_a(Enumerable)
125
+ end
126
+ end
127
+ end
@@ -71,12 +71,12 @@ module Arc
71
71
  end
72
72
  it 'quotes an object based on column type' do
73
73
  superman = "superman"
74
- ArcTest.with_store do |store|
75
- c = store[:superheros][:name]
76
- quoter.quote(superman, c).should == "'superman'"
77
- c = store[:superheros][:id]
78
- quoter.quote(10, c).should == '10'
79
- end
74
+ store = ArcTest.get_store
75
+ c = store[:superheros][:name]
76
+ quoter.quote(superman, c).should == "'superman'"
77
+ c = store[:superheros][:id]
78
+ quoter.quote(10, c).should == '10'
79
+ ArcTest.drop_store store
80
80
  end
81
81
  it 'quotes a bigdecimal' do
82
82
  big_decimal = BigDecimal.new((1 << 100).to_s)
@@ -6,76 +6,42 @@ require 'bundler/setup'
6
6
  require 'rspec'
7
7
  require 'arc'
8
8
  require 'arel'
9
- require 'q/resource_pool'
10
9
  require 'timecop'
11
10
 
12
- RSpec.configure do |config|
13
- config.after(:all) do
14
- ArcTest.drop
15
- end
16
- end
17
-
18
11
  module ArcTest
19
12
  DEFAULT_ADAPTER = 'sqlite'
20
13
 
21
- class StoreProvider < ResourcePool
22
- def create_resource
23
- Arc::DataStores[ArcTest.adapter].new ArcTest.current_config
24
- end
25
- end
26
-
27
14
  class << self
28
-
29
- def config_key
15
+ def env
30
16
  @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
17
  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
18
+ alias :adapter :env
19
+ def adapter
20
+ env
53
21
  end
54
22
 
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
23
+ def get_store
24
+ @store = begin
25
+ s = Arc::DataStores[ArcTest.adapter].new ArcTest.config
26
+ Arel::Table.engine = s
27
+ s.schema.execute_ddl File.read("spec/support/schemas/#{adapter}.sql")
28
+ load "spec/support/seed.rb"
29
+ s
64
30
  end
65
31
  end
66
32
 
67
- def current_config
68
- config[config_key]
33
+ def drop_store store
34
+ store.schema.execute_ddl File.read("spec/support/schemas/drop_#{adapter}.sql")
69
35
  end
70
36
 
71
- def adapter
72
- current_config[:adapter].to_sym
37
+ def _config
38
+ @config ||= YAML::load(File.read "spec/support/config.yml").symbolize_keys!
73
39
  end
74
40
 
75
- private
76
- def provider
77
- @provider ||= StoreProvider.new nil
41
+ def config
42
+ _config[env]
78
43
  end
44
+
79
45
  end
80
46
 
81
47
  end
@@ -54,7 +54,7 @@ data.each_pair do |name, tuples|
54
54
  [table[key], tuple[key]]
55
55
  end
56
56
  stmt.insert(values)
57
- record = Arel::Table.engine.create(stmt.to_sql)
57
+ record = Arel::Table.engine.create(stmt)
58
58
  ids[name][record[:name]] = record[:id]
59
59
  end
60
60
  end
@@ -70,5 +70,5 @@ power_sets.each do |set|
70
70
  [power_map[:superhero_id], ids[:superheros][set[0]]],
71
71
  [power_map[:power_id], ids[:powers][set[1]]]
72
72
  ])
73
- Arel::Table.engine.create im.to_sql
73
+ Arel::Table.engine.create im
74
74
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-27 00:00:00.000000000Z
12
+ date: 2011-12-28 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: agent-q
16
- requirement: &70144475547120 !ruby/object:Gem::Requirement
16
+ requirement: &70332275934140 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70144475547120
24
+ version_requirements: *70332275934140
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: arel
27
- requirement: &70144475546620 !ruby/object:Gem::Requirement
27
+ requirement: &70332275933640 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70144475546620
35
+ version_requirements: *70332275933640
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: pg
38
- requirement: &70144475546020 !ruby/object:Gem::Requirement
38
+ requirement: &70332275932980 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70144475546020
46
+ version_requirements: *70332275932980
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: sqlite3
49
- requirement: &70144475545200 !ruby/object:Gem::Requirement
49
+ requirement: &70332275932240 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70144475545200
57
+ version_requirements: *70332275932240
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: mysql2
60
- requirement: &70144475544780 !ruby/object:Gem::Requirement
60
+ requirement: &70332275931820 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70144475544780
68
+ version_requirements: *70332275931820
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &70144475544360 !ruby/object:Gem::Requirement
71
+ requirement: &70332275931360 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70144475544360
79
+ version_requirements: *70332275931360
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: simplecov
82
- requirement: &70144475543720 !ruby/object:Gem::Requirement
82
+ requirement: &70332275930860 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70144475543720
90
+ version_requirements: *70332275930860
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: timecop
93
- requirement: &70144475543240 !ruby/object:Gem::Requirement
93
+ requirement: &70332275930440 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,7 +98,7 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70144475543240
101
+ version_requirements: *70332275930440
102
102
  description: Compatible with mysql, sqlite, and postgres
103
103
  email:
104
104
  - jacob.s.morris@gmail.com
@@ -109,11 +109,12 @@ files:
109
109
  - .gitignore
110
110
  - .rspec
111
111
  - Gemfile
112
+ - README.md
113
+ - README.md.orig
112
114
  - Rakefile
113
115
  - arc.gemspec
114
116
  - lib/arc.rb
115
117
  - lib/arc/casting.rb
116
- - lib/arc/data_stores.rb
117
118
  - lib/arc/data_stores/abstract/arel_compatibility.rb
118
119
  - lib/arc/data_stores/abstract/object_definitions.rb
119
120
  - lib/arc/data_stores/abstract/store.rb
@@ -130,12 +131,11 @@ files:
130
131
  - spec/data_stores/abstract/arel_compatibility_spec.rb
131
132
  - spec/data_stores/abstract/object_definitions_spec.rb
132
133
  - spec/data_stores/abstract/store_spec.rb
133
- - spec/data_stores/integration/crud_spec.rb
134
- - spec/data_stores/integration/schema_spec.rb
135
134
  - spec/data_stores/mysql/store_spec.rb
136
135
  - spec/data_stores/postgres/store_spec.rb
137
136
  - spec/data_stores/sqlite/store_spec.rb
138
137
  - spec/data_stores_spec.rb
138
+ - spec/integration_spec.rb
139
139
  - spec/quoting_spec.rb
140
140
  - spec/spec_helper.rb
141
141
  - spec/support/config.yml
@@ -180,12 +180,11 @@ test_files:
180
180
  - spec/data_stores/abstract/arel_compatibility_spec.rb
181
181
  - spec/data_stores/abstract/object_definitions_spec.rb
182
182
  - spec/data_stores/abstract/store_spec.rb
183
- - spec/data_stores/integration/crud_spec.rb
184
- - spec/data_stores/integration/schema_spec.rb
185
183
  - spec/data_stores/mysql/store_spec.rb
186
184
  - spec/data_stores/postgres/store_spec.rb
187
185
  - spec/data_stores/sqlite/store_spec.rb
188
186
  - spec/data_stores_spec.rb
187
+ - spec/integration_spec.rb
189
188
  - spec/quoting_spec.rb
190
189
  - spec/spec_helper.rb
191
190
  - spec/support/config.yml
@@ -1,9 +0,0 @@
1
- require 'arc/data_stores/abstract/store'
2
-
3
- module Arc
4
- module DataStores
5
- extend Q::Dispatcher
6
- require_pattern "arc/data_stores/%s/store.rb"
7
- constant_suffix "DataStore"
8
- end
9
- end
@@ -1,107 +0,0 @@
1
- require 'spec_helper'
2
- require 'pp'
3
- module Arc
4
- module DataStores
5
- describe 'The data store crud operations' do
6
- #convenience method for building a tree of arel values
7
- def values_array table_name, hash
8
- hash.keys.map do |attr|
9
- [@tables[table_name][attr], hash[attr]]
10
- end
11
- end
12
-
13
- #grab a superhero record by name
14
- def get_hero(hero_name)
15
- query = @tables[:superheros]
16
- .project('*')
17
- .where(@tables[:superheros][:name].eq(hero_name))
18
- .to_sql
19
- @store.read query
20
- end
21
-
22
- before :each do
23
- ArcTest.with_store do |store|
24
- Arel::Table.engine = store
25
- load "spec/support/seed.rb"
26
- end
27
- @tables = Hash.new { |hash, key| hash[key] = Arel::Table.new key }
28
- @store = Arel::Table.engine
29
- end
30
-
31
- describe '#create and #read' do
32
- before :each do
33
- Timecop.freeze Time.now do
34
- @created_at = Time.parse('2011-12-27 11:52:56 -0700')
35
- properties = {
36
- :name => "green hornet",
37
- :born_on => @created_at,
38
- :photo => File.read('spec/support/resources/ironman.gif'),
39
- :created_at => @created_at
40
- }
41
- im = Arel::InsertManager.new Arel::Table.engine
42
- im.insert values_array(:superheros, properties)
43
- @result = @store.create im.to_sql
44
- end
45
- end
46
-
47
- it 'creates a new record' do
48
- superheros = @tables[:superheros]
49
- query = @tables[:superheros]
50
- .project(
51
- superheros[:name],
52
- superheros[:born_on],
53
- superheros[:created_at],
54
- superheros[:photo]
55
- )
56
- .where(@tables[:superheros][:name].eq('green hornet'))
57
- result = @store.read query
58
- result[0][:name].should == 'green hornet'
59
- result[0][:born_on].should == Date.today
60
- result[0][:created_at].should == @created_at
61
- result[0][:photo].should == File.read('spec/support/resources/ironman.gif').force_encoding("BINARY")
62
- end
63
-
64
- it 'returns the record with a populated primary key' do
65
- @result[:id].should_not be_nil
66
- @result[:name].should == 'green hornet'
67
- end
68
-
69
- end
70
-
71
- describe '#update' do
72
- it 'updates a record and returns the updated record' do
73
- properties = {:name => 'batman'}
74
- um = Arel::UpdateManager.new @store
75
- um.table @tables[:superheros]
76
- um.set(values_array(:superheros, properties))
77
- .where(@tables[:superheros][:name].eq('megaman'))
78
- query = um.to_sql
79
- result = @store.update query
80
-
81
- megaman = get_hero('megaman')
82
- megaman.size.should == 0
83
- megaman.should be_a(Enumerable)
84
-
85
- batman = get_hero('batman')
86
- batman.size.should == 1
87
- batman.first[:name].should == 'batman'
88
- end
89
- end
90
-
91
- describe '#destroy' do
92
- it 'deletes a record' do
93
- delete = Arel::DeleteManager.new @store
94
- delete
95
- .from(@tables[:superheros])
96
- .where(@tables[:superheros][:name].eq('superman'))
97
- @store.destroy delete.to_sql
98
- superman = get_hero('superman')
99
- superman.size.should == 0
100
- superman.size.should == 0
101
- superman.should be_a(Enumerable)
102
- end
103
- end
104
-
105
- end
106
- end
107
- end
@@ -1,49 +0,0 @@
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
- [:superheros, :powers, :superheros_powers].each do |t|
10
- store.schema.table_names.should include(t)
11
- end
12
- end
13
- end
14
-
15
- it 'provides a Table object for each table' do
16
- ArcTest.with_store do |store|
17
- heros = store[:superheros]
18
- heros.should be_a(Table)
19
- heros.column_names.should include(:id)
20
- heros.column_names.should include(:name)
21
- end
22
- end
23
-
24
- it 'provides a Column object for each column' do
25
- ArcTest.with_store do |store|
26
- heros = store[:superheros]
27
- id = heros[:id]
28
- id.should be_a(Column)
29
- id.pk?.should be_true
30
- id.allows_null?.should be_false
31
- id.default.should be_nil
32
- id.name.should == "id"
33
- id.type.should == :integer
34
-
35
- #name column
36
- name = heros[:name]
37
- name.should be_a(Column)
38
- name.pk?.should be_false
39
- name.allows_null?.should be_false
40
- name.default.should be_nil
41
- name.name.should == "name"
42
- name.type.should == :varchar
43
- end
44
- end
45
-
46
- end
47
- end
48
- end
49
- end