cql-model 0.3.0

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 @@
1
+ 1.9.3-p392
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Runtime dependencies
4
+ gem "cql-rb", "~> 1.0.0.pre4"
5
+
6
+ # Gems used during test and development
7
+ group :development do
8
+ gem "rake", "~> 0.9"
9
+ gem "rspec", "~> 2.0"
10
+ gem "cucumber", "~> 1.0"
11
+ gem "jeweler", "~> 1.8.3"
12
+ gem "debugger"
13
+ gem "rdoc", ">= 2.4.2"
14
+ gem "flexmock", "~> 0.8"
15
+ gem "syntax", "~> 1.0.0" #rspec will syntax-highlight code snippets if this gem is available
16
+ gem "nokogiri", "~> 1.5"
17
+ end
@@ -0,0 +1,56 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ builder (3.1.4)
5
+ columnize (0.3.6)
6
+ cql-rb (1.0.0.pre4)
7
+ cucumber (1.2.1)
8
+ builder (>= 2.1.2)
9
+ diff-lcs (>= 1.1.3)
10
+ gherkin (~> 2.11.0)
11
+ json (>= 1.4.6)
12
+ debugger (1.5.0)
13
+ columnize (>= 0.3.1)
14
+ debugger-linecache (~> 1.2.0)
15
+ debugger-ruby_core_source (~> 1.2.0)
16
+ debugger-linecache (1.2.0)
17
+ debugger-ruby_core_source (1.2.0)
18
+ diff-lcs (1.1.3)
19
+ flexmock (0.9.0)
20
+ gherkin (2.11.6)
21
+ json (>= 1.7.6)
22
+ git (1.2.5)
23
+ jeweler (1.8.4)
24
+ bundler (~> 1.0)
25
+ git (>= 1.2.5)
26
+ rake
27
+ rdoc
28
+ json (1.7.7)
29
+ nokogiri (1.5.9)
30
+ rake (0.9.6)
31
+ rdoc (4.0.1)
32
+ json (~> 1.4)
33
+ rspec (2.12.0)
34
+ rspec-core (~> 2.12.0)
35
+ rspec-expectations (~> 2.12.0)
36
+ rspec-mocks (~> 2.12.0)
37
+ rspec-core (2.12.2)
38
+ rspec-expectations (2.12.1)
39
+ diff-lcs (~> 1.1.3)
40
+ rspec-mocks (2.12.2)
41
+ syntax (1.0.0)
42
+
43
+ PLATFORMS
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ cql-rb (~> 1.0.0.pre4)
48
+ cucumber (~> 1.0)
49
+ debugger
50
+ flexmock (~> 0.8)
51
+ jeweler (~> 1.8.3)
52
+ nokogiri (~> 1.5)
53
+ rake (~> 0.9)
54
+ rdoc (>= 2.4.2)
55
+ rspec (~> 2.0)
56
+ syntax (~> 1.0.0)
@@ -0,0 +1,24 @@
1
+ Overview
2
+ ========
3
+
4
+ [![Build Status](https://travis-ci.org/xeger/cql-model.png?branch=master)](https://travis-ci.org/xeger/cql-model)
5
+
6
+ TODO
7
+
8
+ To-Do List
9
+ ==========
10
+
11
+ ## Features
12
+
13
+ * Add support for Time and other obvious Cassandra data types
14
+ * Using-keyspace override
15
+ * Declaration, read and write of set/list/map properties
16
+ * Batch mutations
17
+ * Notation for composite partition key (CompositeType), e.g. `primary_key [:id, :surname], :first_name`
18
+ * Prepared statement support for SELECT & named scopes
19
+ * Prepared statement support for INSERT/UPDATE
20
+
21
+ ## Usability / Correctness / Performance
22
+
23
+ * Better solution for using and switching namespaces -- thread/fiber safety
24
+ * Better use of cql-rb connection pooling
@@ -0,0 +1,54 @@
1
+ # -*-ruby-*-
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+
5
+ require 'rake'
6
+ require 'rdoc/task'
7
+ require 'rubygems/package_task'
8
+
9
+ require 'rake/clean'
10
+ require 'rspec/core/rake_task'
11
+ require 'cucumber/rake/task'
12
+
13
+ require 'jeweler'
14
+
15
+ task :default => [:cucumber, :spec]
16
+
17
+ desc "Run unit tests"
18
+ RSpec::Core::RakeTask.new do |t|
19
+ t.pattern = Dir['spec/**/*_spec.rb']
20
+ end
21
+
22
+ desc "Run functional tests"
23
+ Cucumber::Rake::Task.new do |t|
24
+ t.cucumber_opts = %w{--color --format pretty}
25
+ end
26
+
27
+ desc 'Generate documentation for the cql-model gem.'
28
+ Rake::RDocTask.new(:rdoc) do |rdoc|
29
+ rdoc.rdoc_dir = 'doc'
30
+ rdoc.title = 'Cql'
31
+ rdoc.options << '--line-numbers' << '--inline-source'
32
+ rdoc.rdoc_files.include('README.md')
33
+ rdoc.rdoc_files.include('lib/**/*.rb')
34
+ rdoc.rdoc_files.exclude('features/**/*')
35
+ rdoc.rdoc_files.exclude('spec/**/*')
36
+ end
37
+
38
+ Jeweler::Tasks.new do |gem|
39
+ # gem is a Gem::Specification; see http://docs.rubygems.org/read/chapter/20 for more options
40
+ gem.name = "cql-model"
41
+ gem.required_ruby_version = ">= 1.9.0"
42
+ gem.homepage = "https://github.com/xeger/cql-model"
43
+ gem.license = "MIT"
44
+ gem.summary = %Q{Cassandra CQL model.}
45
+ gem.description = %Q{Lightweight, performant OOP wrapper for Cassandra tables; inspired by DataMapper.}
46
+ gem.email = "gemspec@tracker.xeger.net"
47
+ gem.authors = ['Tony Spataro']
48
+ gem.files.exclude 'features/**/*'
49
+ gem.files.exclude 'spec/**/*'
50
+ end
51
+
52
+ Jeweler::RubygemsDotOrgTasks.new
53
+
54
+ CLEAN.include('pkg')
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
@@ -0,0 +1,85 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "cql-model"
8
+ s.version = "0.3.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tony Spataro"]
12
+ s.date = "2013-04-24"
13
+ s.description = "Lightweight, performant OOP wrapper for Cassandra tables; inspired by DataMapper."
14
+ s.email = "gemspec@tracker.xeger.net"
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".ruby-version",
20
+ "Gemfile",
21
+ "Gemfile.lock",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "cql-model.gemspec",
26
+ "cql_model.rconf",
27
+ "lib/cql/model.rb",
28
+ "lib/cql/model/dsl.rb",
29
+ "lib/cql/model/query.rb",
30
+ "lib/cql/model/query/comparison_expression.rb",
31
+ "lib/cql/model/query/expression.rb",
32
+ "lib/cql/model/query/insert_statement.rb",
33
+ "lib/cql/model/query/mutation_statement.rb",
34
+ "lib/cql/model/query/select_statement.rb",
35
+ "lib/cql/model/query/statement.rb",
36
+ "lib/cql/model/query/update_expression.rb",
37
+ "lib/cql/model/query/update_statement.rb"
38
+ ]
39
+ s.homepage = "https://github.com/xeger/cql-model"
40
+ s.licenses = ["MIT"]
41
+ s.require_paths = ["lib"]
42
+ s.required_ruby_version = Gem::Requirement.new(">= 1.9.0")
43
+ s.rubygems_version = "1.8.23"
44
+ s.summary = "Cassandra CQL model."
45
+
46
+ if s.respond_to? :specification_version then
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<cql-rb>, ["~> 1.0.0.pre4"])
51
+ s.add_development_dependency(%q<rake>, ["~> 0.9"])
52
+ s.add_development_dependency(%q<rspec>, ["~> 2.0"])
53
+ s.add_development_dependency(%q<cucumber>, ["~> 1.0"])
54
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
55
+ s.add_development_dependency(%q<debugger>, [">= 0"])
56
+ s.add_development_dependency(%q<rdoc>, [">= 2.4.2"])
57
+ s.add_development_dependency(%q<flexmock>, ["~> 0.8"])
58
+ s.add_development_dependency(%q<syntax>, ["~> 1.0.0"])
59
+ s.add_development_dependency(%q<nokogiri>, ["~> 1.5"])
60
+ else
61
+ s.add_dependency(%q<cql-rb>, ["~> 1.0.0.pre4"])
62
+ s.add_dependency(%q<rake>, ["~> 0.9"])
63
+ s.add_dependency(%q<rspec>, ["~> 2.0"])
64
+ s.add_dependency(%q<cucumber>, ["~> 1.0"])
65
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
66
+ s.add_dependency(%q<debugger>, [">= 0"])
67
+ s.add_dependency(%q<rdoc>, [">= 2.4.2"])
68
+ s.add_dependency(%q<flexmock>, ["~> 0.8"])
69
+ s.add_dependency(%q<syntax>, ["~> 1.0.0"])
70
+ s.add_dependency(%q<nokogiri>, ["~> 1.5"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<cql-rb>, ["~> 1.0.0.pre4"])
74
+ s.add_dependency(%q<rake>, ["~> 0.9"])
75
+ s.add_dependency(%q<rspec>, ["~> 2.0"])
76
+ s.add_dependency(%q<cucumber>, ["~> 1.0"])
77
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
78
+ s.add_dependency(%q<debugger>, [">= 0"])
79
+ s.add_dependency(%q<rdoc>, [">= 2.4.2"])
80
+ s.add_dependency(%q<flexmock>, ["~> 0.8"])
81
+ s.add_dependency(%q<syntax>, ["~> 1.0.0"])
82
+ s.add_dependency(%q<nokogiri>, ["~> 1.5"])
83
+ end
84
+ end
85
+
@@ -0,0 +1,11 @@
1
+ # Configuration settings for Cql
2
+ ruby do
3
+ version 'ruby-1.9.3-p392'
4
+ end
5
+ bundler do
6
+ version '1.2.1'
7
+ end
8
+ cassandra do
9
+ version '1.1.10'
10
+ end
11
+
@@ -0,0 +1,49 @@
1
+ require 'thread'
2
+ require 'cql'
3
+
4
+ module Cql::Model
5
+ # Raised if the user calls DSL that cannot generate valid CQL
6
+ class SyntaxError < Exception; end
7
+
8
+ # Raised if an insert statement does not specify all the primary keys
9
+ # or if an update statement does not specify any key (part of a composite primary key or a primary key)
10
+ class MissingKey < Exception; end
11
+
12
+ # Type aliases for use with the property-declaration DSL.
13
+ Uuid = Cql::Uuid
14
+ UUID = Uuid
15
+
16
+ # Type alias for use with the property-declaration DSL.
17
+ Boolean = TrueClass
18
+
19
+ end
20
+
21
+ require 'cql/model/query'
22
+ require 'cql/model/class_methods'
23
+ require 'cql/model/instance_methods'
24
+
25
+ module Cql::Model
26
+ def self.included(klass)
27
+ klass.__send__(:extend, Cql::Model::ClassMethods)
28
+ klass.__send__(:include, Cql::Model::InstanceMethods)
29
+ end
30
+
31
+ # Get or set the "master" client connection shared by every model that doesn't bother to
32
+ # set its own. Defaults to a localhost connection with no default keyspace; every query
33
+ # must be wrapped in a "using_keyspace" method call.
34
+ #
35
+ # @param [optional, Cql::Client] new_client the new client to set
36
+ # @return [Cql::Client] the current client
37
+ def self.cql_client(new_client=nil)
38
+ if new_client
39
+ @@cql_model_mutex.synchronize do
40
+ @@cql_client = new_client
41
+ end
42
+ else
43
+ @@cql_client ||= Cql::Client.new
44
+ @@cql_client.start! unless @@cql_client.connected?
45
+ end
46
+
47
+ @@cql_client
48
+ end
49
+ end
@@ -0,0 +1,178 @@
1
+ module Cql::Model::ClassMethods
2
+ def self.extended(klass)
3
+ klass.instance_eval do
4
+ # The mutex is shared by all Cql::Model inheritors
5
+ @@cql_model_mutex ||= Mutex.new
6
+
7
+ # Other attributes are tracked per-class
8
+ @cql_table_name ||= klass.name.split('::').last
9
+ @cql_model_properties ||= {}
10
+ @cql_model_keys ||= []
11
+ @cql_model_read_consistency ||= 'LOCAL_QUORUM'
12
+ @cql_model_write_consistency ||= 'LOCAL_QUORUM'
13
+ end
14
+ end
15
+
16
+ # Get or set the client connection used by this class.
17
+ #
18
+ # @param [optional, Cql::Client] new_client the new client to set
19
+ # @return [Cql::Client] the current client
20
+ def cql_client(new_client=nil)
21
+ if new_client
22
+ @@cql_model_mutex.synchronize do
23
+ @cql_client = new_client
24
+ end
25
+ end
26
+
27
+ @cql_client || ::Cql::Model.cql_client
28
+ end
29
+
30
+ # @TODO docs
31
+ def table_name(new_name=nil)
32
+ if new_name
33
+ @@cql_model_mutex.synchronize do
34
+ # Set the table name
35
+ @cql_table_name = new_name
36
+ end
37
+ else
38
+ # Get the table name
39
+ @cql_table_name
40
+ end
41
+ end
42
+
43
+ # @TODO docs
44
+ def read_consistency(new_consistency=nil)
45
+ if new_consistency
46
+ @cql_model_read_consistency = new_consistency
47
+ else
48
+ @cql_model_read_consistency
49
+ end
50
+ end
51
+
52
+ # @TODO docs
53
+ def write_consistency(new_consistency=nil)
54
+ if new_consistency
55
+ @cql_model_write_consistency = new_consistency
56
+ else
57
+ @cql_model_write_consistency
58
+ end
59
+ end
60
+
61
+ # Specify or get a primary key or a composite primary key
62
+ #
63
+ # @param key_vals [Symbol|Array<Symbol>] single key name or composite key names
64
+ #
65
+ # @return [Cql::Model] self
66
+ def primary_key(*keys)
67
+ if keys.empty?
68
+ @cql_model_keys
69
+ else
70
+ @@cql_model_mutex.synchronize do
71
+ @cql_model_keys = keys
72
+ end
73
+ self
74
+ end
75
+ end
76
+
77
+ # @TODO docs
78
+ def property(name, type, opts={})
79
+ definition = {}
80
+
81
+ # If the user specified the name as a symbol, then they automatically get
82
+ # a reader and writer because the property has a predictable, fixed column
83
+ # name.
84
+ if name.is_a?(Symbol)
85
+ definition[:reader] = opts[:reader] || name
86
+ definition[:writer] = opts[:writer] || "#{definition[:reader]}=".to_sym
87
+ name = name.to_s
88
+ end
89
+
90
+ @@cql_model_mutex.synchronize do
91
+ definition[:type] = type
92
+
93
+ if @cql_model_properties.key?(name) && (@cql_model_properties[name] != definition)
94
+ raise ArgumentError, "Property #{name} is already defined"
95
+ end
96
+
97
+ unless @cql_model_properties.key?(name)
98
+ @cql_model_properties[name] = definition
99
+
100
+ __send__(:define_method, definition[:reader]) do
101
+ self[name]
102
+ end if definition[:reader]
103
+
104
+ __send__(:define_method, definition[:writer]) do |value|
105
+ self[name] = value
106
+ end if definition[:writer]
107
+ end
108
+ end
109
+
110
+ self
111
+ end
112
+
113
+ # @TODO docs
114
+ def scope(name, &block)
115
+ @@cql_model_mutex.synchronize do
116
+ eigenclass = class <<self
117
+ self
118
+ end
119
+
120
+ eigenclass.instance_eval do
121
+ define_method(name.to_sym) do |*params|
122
+ # @TODO use a prepared statement for speed
123
+ self.select.where(*params, &block)
124
+ end
125
+ end
126
+ end
127
+
128
+ self
129
+ end
130
+
131
+ # Begin building a CQL SELECT statement.
132
+ #
133
+ # @param [Object] *params list of yield parameters for the block
134
+ #
135
+ # @example tell us how old Joe is
136
+ # Person.select.where { name == 'Joe' }.each { |person| puts person.age }
137
+ def select(*params)
138
+ Cql::Model::Query::SelectStatement.new(self).select(*params)
139
+ end
140
+
141
+ # Begin building a CQL INSERT statement.
142
+ # @see Cql::Model::Query::InsertStatement
143
+ #
144
+ # @param [Hash] values Hash of column values indexed by column name
145
+ # @return [Cql::Model::Query::InsertStatement] a query object to customize (timestamp, ttl, etc) or execute
146
+ #
147
+ # @example
148
+ # Person.create(:name => 'Joe', :age => 25).ttl(3600).execute
149
+ def insert(values)
150
+ Cql::Model::Query::InsertStatement.new(self).insert(values)
151
+ end
152
+
153
+ alias create insert
154
+
155
+ # Start an UPDATE CQL statement
156
+ # The method #keys must be called on the result before #execute
157
+ # @see Cql::Model::Query::UpdateStatement
158
+ #
159
+ # @param [Hash] values Hash of column values indexed by column name, optional
160
+ # @return [Cql::Model::Query::UpdateStatement] a query object to customize (keys, ttl, timestamp etc) then execute
161
+ #
162
+ # @example
163
+ # Person.update(:updated_at => Time.now.utc).keys(:name => ['joe', 'john', 'jane'])
164
+ # Person.update.ttl(3600).keys(:name => 'joe')
165
+ def update(values={})
166
+ Cql::Model::Query::UpdateStatement.new(self).update(values)
167
+ end
168
+
169
+ # @TODO docs
170
+ def each_row(&block)
171
+ Cql::Model::Query::SelectStatement.new(self).each_row(&block)
172
+ end
173
+
174
+ # @TODO docs
175
+ def each(&block)
176
+ Cql::Model::Query::SelectStatement.new(self).each(&block)
177
+ end
178
+ end