believer 0.1.4 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -53,9 +53,9 @@ module Believer
53
53
  end
54
54
 
55
55
  cql << " FROM #{@record_class.table_name}"
56
- cql << " WHERE #{@wheres.map { |wc| "#{wc.to_cql}" }.join(' AND ')}" if @wheres && @wheres.any?
57
- cql << " #{@order_by.to_cql}" unless @order_by.nil?
58
- cql << " #{@limit_to.to_cql}" unless @limit_to.nil?
56
+ cql << " WHERE #{wheres.map { |wc| "#{wc.to_cql}" }.join(' AND ')}" if wheres.any?
57
+ cql << " #{order_by.to_cql}" unless order_by.nil?
58
+ cql << " #{limit_to.to_cql}" unless limit_to.nil?
59
59
  cql
60
60
  end
61
61
 
@@ -0,0 +1,90 @@
1
+ module Believer
2
+ module Relation
3
+ extend ::ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def cql_record_relations
7
+ @cql_record_relations ||= {}
8
+ end
9
+
10
+ def has_single(name, opts = {})
11
+ if opts[:foreign_key].nil?
12
+ opts[:foreign_key] = opts[:key].nil? ? :id : opts[:key]
13
+ end
14
+ if opts[:key].nil?
15
+ opts[:key] = opts[:foreign_key].nil? ? "#{self.name.underscore}_id".to_sym : opts[:foreign_key]
16
+ end
17
+ has_a_relation(name, opts.merge(:type => :one_2_one))
18
+ end
19
+
20
+ def has_some(name, opts = {})
21
+ if opts[:foreign_key].nil?
22
+ opts[:foreign_key] = opts[:key].nil? ? "#{self.name.underscore}_id".to_sym : opts[:key]
23
+ end
24
+ if opts[:key].nil?
25
+ opts[:key] = opts[:foreign_key].nil? ? :id : opts[:foreign_key]
26
+ end
27
+
28
+ has_a_relation(name, opts.merge(:type => :one_2_many))
29
+ end
30
+
31
+ # Defines a (one to many) relation.
32
+ # @param name [Symbol] the name of the relation, which will also be used as an accessor method
33
+ # @param opts [Hash] the options
34
+ # @option opts :class the name of the referenced class. If nil, it will be created from the relation name. Can be a constant or a String
35
+ # @option opts :foreign_key the name of the attribute of the referenced class which acts as the key to this object
36
+ # @option opts :key the name of the attribute of the referencing class which acts as the key the referenced records
37
+ # @option opts :filter a Proc or lambda which is called with a Believer::Query instance as a parameter to tweak the relation query
38
+ def has_a_relation(name, opts = {})
39
+ defaults = {
40
+ }
41
+ options = defaults.merge(opts)
42
+
43
+ # Use a proc to avoid classes not yet loaded being referenced
44
+ get_relation_class = lambda do
45
+ if options[:relation_class].nil?
46
+ relation_class = options[:class]
47
+ if relation_class.nil?
48
+ cn = name.to_s.camelize
49
+ if options[:type] == :one_2_many
50
+ cn = cn[0, (name.to_s.size - 1)]
51
+ end
52
+ relation_class = Kernel.const_get(cn)
53
+ elsif relation_class.is_a?(String)
54
+ relation_class = relation_class.split('::').inject(Kernel) { |scope, const_name| scope.const_get(const_name) }
55
+ end
56
+ options[:relation_class] = relation_class
57
+ end
58
+ options[:relation_class]
59
+ end
60
+
61
+ cql_record_relations[name] = options
62
+
63
+ opts[:foreign_key] = opts[:foreign_key].is_a?(Array) ? opts[:foreign_key] : [opts[:foreign_key]]
64
+ opts[:key] = opts[:key].is_a?(Array) ? opts[:key] : [opts[:key]]
65
+
66
+ raise "key and foreign_key must have same number of items" if opts[:key].size != opts[:foreign_key].size
67
+
68
+ self.redefine_method(name) do
69
+ relation_class = get_relation_class.call
70
+
71
+ q = relation_class.scoped
72
+ opts[:foreign_key].each_with_index do |fk, index|
73
+ key = opts[:key][index]
74
+ q = q.where(fk => self.send(key))
75
+ end
76
+ if options[:filter]
77
+ q = self.instance_exec(q, &(options[:filter]))
78
+ return EmptyResult.new unless q
79
+ end
80
+ return q.first if options[:type] == :one_2_one
81
+ q
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
@@ -1,16 +1,23 @@
1
1
  module Believer
2
+ # A command implementation which includes a CQL WHERE clause
2
3
  class ScopedCommand < Command
3
4
 
4
- attr_accessor :wheres
5
-
6
5
  def query_attributes
7
6
  attrs = super
8
- attrs.merge(:wheres => @wheres)
7
+ attrs.merge(:wheres => (wheres.dup))
8
+ end
9
+
10
+ def wheres
11
+ #puts "Wheres: #{@wheres}"
12
+ @wheres ||= []
13
+ end
14
+
15
+ def wheres=(w)
16
+ @wheres = w.is_a?(Array) ? w : [w]
9
17
  end
10
18
 
11
19
  def where(*args)
12
20
  q = clone
13
- q.wheres ||= []
14
21
  q.wheres << WhereClause.new(*args)
15
22
  q
16
23
  end
@@ -0,0 +1,49 @@
1
+ module Believer
2
+ module Test
3
+ # Controls the life cycle for all objects created in a test
4
+ module TestRunLifeCycle
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ Believer::Base.observers = Destructor
9
+
10
+ after(:each) do
11
+ Destructor.instance.cleanup
12
+ end
13
+ end
14
+
15
+ def saved_models
16
+ @saved_models ||= []
17
+ end
18
+
19
+ def after_save(model)
20
+ saved_models << model
21
+ end
22
+
23
+ # Detroys all CqlRecord::Base instances created
24
+ class Destructor < Believer::Observer
25
+ observe Believer::Base
26
+
27
+ def cleanup
28
+ saved_models.each do |model|
29
+ begin
30
+ model.destroy
31
+ rescue Exception => e
32
+ puts "Could not destroy model #{model}: #{e}\n#{e.backtrace.join("\n")}"
33
+ end
34
+ end
35
+ end
36
+
37
+ def saved_models
38
+ @saved_models ||= []
39
+ end
40
+
41
+ def after_save(model)
42
+ saved_models << model
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -2,17 +2,6 @@ module Believer
2
2
 
3
3
  module Values
4
4
 
5
- TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S%z'
6
-
7
- def to_cql_literal(value)
8
- return 'NULL' if value.nil?
9
- return "'#{value}'" if value.is_a?(String)
10
- return "#{value}" if value.is_a?(Numeric)
11
- return "'#{value.strftime(TIMESTAMP_FORMAT)}'" if value.is_a?(Time) || value.is_a?(DateTime)
12
- #return "#{value.to_i * 1000}" if value.is_a?(Time) || value.is_a?(DateTime)
13
- return nil
14
- end
15
-
16
5
  def convert_to_integer(v)
17
6
  return v.to_i unless v.nil?
18
7
  nil
@@ -24,6 +13,8 @@ module Believer
24
13
  end
25
14
 
26
15
  def convert_to_boolean(v)
16
+ return true if v.is_a?(TrueClass)
17
+ return false if v.is_a?(FalseClass)
27
18
  return v.to_bool if v.respond_to?(:to_bool)
28
19
  nil
29
20
  end
@@ -1,5 +1,5 @@
1
1
  module Believer
2
2
  module Version
3
- VERSION = '0.1.4'
3
+ VERSION = '0.2'
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  module Believer
2
2
 
3
3
  class WhereClause
4
- include Values
4
+ include CqlHelper
5
5
 
6
6
  def initialize(*args)
7
7
  if args.any?
@@ -3,9 +3,9 @@ require 'spec_helper'
3
3
  describe Believer::Delete do
4
4
 
5
5
  it "create a valid delete statement" do
6
- del = Believer::Delete.new(:record_class => Test::Computer)
6
+ del = Believer::Delete.new(:record_class => Test::Artist)
7
7
  del = del.where(:id => 1)
8
- del.to_cql.should == 'DELETE FROM computers WHERE id = 1'
8
+ del.to_cql.should == 'DELETE FROM artists WHERE id = 1'
9
9
  end
10
10
 
11
11
 
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Believer::Environment do
4
+
5
+ before :each do
6
+ @original_env = Believer::Base.environment
7
+ Believer::Base.environment = nil
8
+ end
9
+
10
+ after :each do
11
+ Believer::Base.environment = @original_env
12
+ end
13
+
14
+ it 'load the Merb configuration' do
15
+ Env = Struct.new(:root, :environment, :logger)
16
+
17
+ Merb = Env.new(File.join(RSpec.configuration.test_files_dir, 'merb'), :development, nil)
18
+ env = Believer::Base.environment
19
+ env.class.should == Believer::Environment::MerbEnv
20
+ env.configuration[:host].should == 'merb.local'
21
+ end
22
+
23
+ it 'load the rails configuration' do
24
+ Env = Struct.new(:root, :env, :logger)
25
+
26
+ Rails = Env.new(File.join(RSpec.configuration.test_files_dir, 'rails'), :development, nil)
27
+ env = Believer::Base.environment
28
+ env.class.should == Believer::Environment::RailsEnv
29
+ env.configuration[:host].should == '123.456.789.0'
30
+ end
31
+
32
+ end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Believer::Insert do
4
4
 
5
5
  it "create statement based on hash" do
6
- insert = Believer::Insert.new(:record_class => Test::Computer, :values => {:id => 1, :brand => 'Apple'})
7
- insert.to_cql.should == "INSERT INTO computers (id, brand) VALUES (1, 'Apple')"
6
+ insert = Believer::Insert.new(:record_class => Test::Artist, :values => {:id => 1, :name => 'Beatles'})
7
+ insert.to_cql.should == "INSERT INTO artists (id, name) VALUES (1, 'Beatles')"
8
8
  end
9
9
  end
@@ -1,27 +1,27 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Believer::Query do
4
- include Believer::Test::RSpec::TestRunLifeCycle
4
+ include Believer::Test::TestRunLifeCycle
5
5
 
6
6
  it 'create simple statement' do
7
- q = Believer::Query.new(:record_class => Test::Computer)
8
- q = q.select(:id).
9
- select(:brand).
10
- where(:brand => 'Atari').
11
- where(:production_date => Time.utc(2013)).
12
- order(:id, :desc).
7
+ q = Believer::Query.new(:record_class => Test::Album)
8
+ q = q.select(:name).
9
+ select(:artist).
10
+ where(:name => 'Revolver').
11
+ where(:release_date => Time.utc(2013)).
12
+ order(:name, :desc).
13
13
  limit(10)
14
- q.to_cql.should == "SELECT id, brand FROM computers WHERE brand = 'Atari' AND production_date = '2013-01-01 00:00:00+0000' ORDER BY id DESC LIMIT 10"
14
+ q.to_cql.should == "SELECT name, artist FROM albums WHERE name = 'Revolver' AND release_date = '2013-01-01 00:00:00+0000' ORDER BY name DESC LIMIT 10"
15
15
  end
16
16
 
17
17
  it 'should behave like an Enumerable' do
18
- puts Test::Computer.environment
19
- @objects = Test::Computer.create([
20
- {:id => 1, :brand => 'Dell'},
21
- {:id => 2, :brand => 'Apple'},
22
- {:id => 3, :brand => 'HP'}
18
+
19
+ @objects = Test::Artist.create([
20
+ {:name => 'Beatles', :label => 'Apple'},
21
+ {:name => 'Jethro Tull', :label => 'Crysalis'},
22
+ {:name => 'Pink Floyd', :label => 'Epic'}
23
23
  ])
24
- q = Believer::Query.new(:record_class => Test::Computer).where(:id => @objects.map {|o|o.id})
24
+ q = Believer::Query.new(:record_class => Test::Artist).where(:name => @objects.map {|o|o.name})
25
25
  Enumerable.instance_methods(false).each do |enum_method|
26
26
  q.respond_to?(enum_method.to_sym).should == true
27
27
  end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Believer::Relation do
4
+
5
+ before :each do
6
+ @artists = []
7
+ @artists << Test::Artist.create(:name => 'Beatles', :label => 'Apple')
8
+ @artists << Test::Artist.create(:name => 'Jethro Tull', :label => 'Crysalis')
9
+ @artists << Test::Artist.create(:name => 'Pink Floyd', :label => 'Epic')
10
+
11
+ @albums = []
12
+ @albums << Test::Album.create(:artist_name => 'Beatles', :name => 'Help', :release_date => Time.utc(1965))
13
+ @albums << Test::Album.create(:artist_name => 'Beatles', :name => 'Revolver', :release_date => Time.utc(1966))
14
+ @albums << Test::Album.create(:artist_name => 'Beatles', :name => 'Abbey Road', :release_date => Time.utc(1969))
15
+
16
+ @albums << Test::Album.create(:artist_name => 'Pink Floyd', :name => 'Dark side of the moon', :release_date => Time.utc(1973))
17
+ @albums << Test::Album.create(:artist_name => 'Pink Floyd', :name => 'Wish you were here', :release_date => Time.utc(1975))
18
+
19
+ @songs = []
20
+ @songs << Test::Song.create(:artist_name => 'Pink Floyd', :album_name => 'Wish you were here', :name => 'Have a cigar')
21
+
22
+ end
23
+
24
+ it "report correct size of one to many relation" do
25
+ a = Test::Artist.where(:name => 'Beatles').first
26
+ a.albums.size.should == 3
27
+ end
28
+
29
+ it "one to one relation" do
30
+ @songs[0].album.should == Test::Album.where(:artist_name => 'Pink Floyd', :name => 'Wish you were here').first
31
+ end
32
+
33
+ end
@@ -10,28 +10,14 @@ unless ENV['COVERAGE'] == 'no'
10
10
  end
11
11
 
12
12
  require 'believer'
13
-
14
- require 'believer/test/rspec/test_run_life_cycle'
15
-
16
-
17
-
13
+ require 'believer/test/test_run_life_cycle'
18
14
 
19
15
  Dir[File.expand_path('../support/*.rb', __FILE__)].each {|f| require f}
20
16
 
21
-
22
17
  setup_database
23
18
 
24
- #class Event < Cql::Model
25
- # primary_key :id
26
- #
27
- # column :location
28
- # column :date
29
- #end
30
- #
31
- #class Person < Cql::Model
32
- # primary_key :id
33
- #
34
- # column :first_name
35
- # column :last_name
36
- # column :birth_date, column_name: :dob
37
- #end
19
+ RSpec.configure do |c|
20
+ c.add_setting :test_files_dir, :default => File.expand_path('../test_files/', __FILE__)
21
+ end
22
+
23
+ File.expand_path('../test_files/', __FILE__)
@@ -8,7 +8,7 @@ def setup_database
8
8
  connection.use(env.connection_configuration[:keyspace])
9
9
  rescue Cql::QueryError
10
10
 
11
- env.create_keyspace(connection)
11
+ env.create_keyspace({}, connection)
12
12
  connection.use(env.connection_configuration[:keyspace])
13
13
 
14
14
  Test.classes.each do |cl|
@@ -1,34 +1,37 @@
1
1
 
2
2
  module Test
3
3
 
4
- class Processor < Believer::Base
5
- column :computer_id, :type => :integer
6
- column :speed, :type => :integer
7
- primary_key :computer_id
8
- end
9
-
10
- class Computer < Believer::Base
11
- include Believer::Owner
4
+ class Artist < Believer::Base
5
+ include Believer::Relation
12
6
 
7
+ column :name
8
+ column :label
13
9
 
14
- column :id, :type => :integer
15
- column :brand, :type => :string
16
- column :production_date, :type => :timestamp
10
+ primary_key :name
17
11
 
18
- primary_key :id
12
+ has_some :albums, :class => 'Test::Album', :key => :name, :foreign_key => :artist_name
13
+ end
19
14
 
20
- has_some :processors, :class => Processor
15
+ class Album < Believer::Base
16
+ column :artist_name
17
+ column :name
18
+ column :release_date, :type => :timestamp
21
19
 
20
+ primary_key :artist_name, :name
22
21
  end
23
22
 
24
- class Event < Believer::Base
25
- column :computer_id, :type => :integer
26
- column :event_type, :type => :integer
27
- column :time, :type => :integer, :key => true
28
- column :description, :type => :string
23
+ class Song < Believer::Base
24
+ include Believer::Relation
29
25
 
30
- primary_key [:computer_id, :event_type], :time
26
+ column :artist_name
27
+ column :album_name
28
+ column :name
29
+ column :track_number, :type => :integer
30
+ column :data, :cql_type => :blob
31
31
 
32
+ primary_key :artist_name, :album_name, :name
33
+
34
+ has_single :album, :class => 'Test::Album', :key => [:artist_name, :album_name], :foreign_key => [:artist_name, :name]
32
35
  end
33
36
 
34
37
  class Person < Believer::Base
@@ -41,8 +44,18 @@ module Test
41
44
 
42
45
  end
43
46
 
47
+ class Event < Believer::Base
48
+ column :computer_id, :type => :integer
49
+ column :event_type, :type => :integer
50
+ column :time, :type => :integer, :key => true
51
+ column :description, :type => :string
52
+
53
+ primary_key [:computer_id, :event_type], :time
54
+
55
+ end
56
+
44
57
  class Environment < Believer::Environment::BaseEnv
45
- def connection_configuration
58
+ def configuration
46
59
  {:host => '127.0.0.1', :keyspace => 'believer_test_space'}
47
60
  end
48
61
  end
@@ -52,7 +65,7 @@ module Test
52
65
  end
53
66
 
54
67
  Believer::Base.environment = test_environment
55
- CLASSES = [Processor, Computer, Event, Person]
68
+ CLASSES = [Artist, Album, Song, Event, Person]
56
69
  #CLASSES.each {|cl| cl.environment = test_environment}
57
70
 
58
71
  def self.classes