arc 0.0.3 → 0.0.3.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.
@@ -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