cequel 1.0.0.rc1 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/lib/cequel.rb +18 -0
  3. data/lib/cequel/errors.rb +8 -4
  4. data/lib/cequel/metal.rb +14 -0
  5. data/lib/cequel/metal/batch.rb +21 -11
  6. data/lib/cequel/metal/batch_manager.rb +74 -0
  7. data/lib/cequel/metal/cql_row_specification.rb +19 -6
  8. data/lib/cequel/metal/data_set.rb +400 -163
  9. data/lib/cequel/metal/deleter.rb +45 -11
  10. data/lib/cequel/metal/incrementer.rb +23 -10
  11. data/lib/cequel/metal/inserter.rb +19 -6
  12. data/lib/cequel/metal/keyspace.rb +82 -159
  13. data/lib/cequel/metal/logger.rb +71 -0
  14. data/lib/cequel/metal/logging.rb +47 -0
  15. data/lib/cequel/metal/new_relic_instrumentation.rb +26 -0
  16. data/lib/cequel/metal/row.rb +36 -10
  17. data/lib/cequel/metal/row_specification.rb +21 -8
  18. data/lib/cequel/metal/statement.rb +30 -6
  19. data/lib/cequel/metal/updater.rb +89 -12
  20. data/lib/cequel/metal/writer.rb +23 -14
  21. data/lib/cequel/record.rb +52 -6
  22. data/lib/cequel/record/association_collection.rb +13 -6
  23. data/lib/cequel/record/associations.rb +146 -54
  24. data/lib/cequel/record/belongs_to_association.rb +34 -7
  25. data/lib/cequel/record/bound.rb +69 -12
  26. data/lib/cequel/record/bulk_writes.rb +29 -1
  27. data/lib/cequel/record/callbacks.rb +22 -6
  28. data/lib/cequel/record/collection.rb +273 -36
  29. data/lib/cequel/record/configuration_generator.rb +5 -0
  30. data/lib/cequel/record/data_set_builder.rb +86 -0
  31. data/lib/cequel/record/dirty.rb +11 -8
  32. data/lib/cequel/record/errors.rb +38 -4
  33. data/lib/cequel/record/has_many_association.rb +42 -9
  34. data/lib/cequel/record/lazy_record_collection.rb +39 -10
  35. data/lib/cequel/record/mass_assignment.rb +14 -6
  36. data/lib/cequel/record/persistence.rb +157 -20
  37. data/lib/cequel/record/properties.rb +147 -24
  38. data/lib/cequel/record/railtie.rb +15 -2
  39. data/lib/cequel/record/record_set.rb +504 -75
  40. data/lib/cequel/record/schema.rb +77 -13
  41. data/lib/cequel/record/scoped.rb +16 -11
  42. data/lib/cequel/record/secondary_indexes.rb +42 -6
  43. data/lib/cequel/record/tasks.rb +2 -1
  44. data/lib/cequel/record/validations.rb +51 -11
  45. data/lib/cequel/schema.rb +9 -0
  46. data/lib/cequel/schema/column.rb +172 -33
  47. data/lib/cequel/schema/create_table_dsl.rb +62 -31
  48. data/lib/cequel/schema/keyspace.rb +106 -7
  49. data/lib/cequel/schema/migration_validator.rb +128 -0
  50. data/lib/cequel/schema/table.rb +183 -20
  51. data/lib/cequel/schema/table_property.rb +92 -34
  52. data/lib/cequel/schema/table_reader.rb +45 -15
  53. data/lib/cequel/schema/table_synchronizer.rb +101 -43
  54. data/lib/cequel/schema/table_updater.rb +114 -19
  55. data/lib/cequel/schema/table_writer.rb +31 -13
  56. data/lib/cequel/schema/update_table_dsl.rb +71 -40
  57. data/lib/cequel/type.rb +214 -53
  58. data/lib/cequel/util.rb +6 -9
  59. data/lib/cequel/version.rb +2 -1
  60. data/spec/examples/record/associations_spec.rb +12 -12
  61. data/spec/examples/record/persistence_spec.rb +5 -5
  62. data/spec/examples/record/record_set_spec.rb +62 -50
  63. data/spec/examples/schema/table_synchronizer_spec.rb +37 -11
  64. data/spec/examples/schema/table_updater_spec.rb +3 -3
  65. data/spec/examples/spec_helper.rb +2 -11
  66. data/spec/examples/type_spec.rb +3 -3
  67. metadata +23 -4
  68. data/lib/cequel/new_relic_instrumentation.rb +0 -22
@@ -1,69 +1,163 @@
1
1
  module Cequel
2
-
3
2
  module Schema
4
-
3
+ #
4
+ # Encapsulates a series of schema modification statements that can be
5
+ # applied to an existing table
6
+ #
5
7
  class TableUpdater
6
-
7
- def self.apply(keyspace, table_name)
8
- new(keyspace, table_name).
9
- tap { |updater| yield updater if block_given? }.
10
- apply
8
+ #
9
+ # Construct a table updater and apply the schema modifications to the
10
+ # given table.
11
+ #
12
+ # @param (see #initialize)
13
+ # @yieldparam updater [TableUpdater] instance of updater whose
14
+ # modifications will be applied to the named table
15
+ # @return [void]
16
+ #
17
+ def self.apply(keyspace, table_name, &block)
18
+ new(keyspace, table_name).tap(&block).apply
11
19
  end
12
20
 
21
+ #
22
+ # @param keyspace [Metal::Keyspace] keyspace containing the table
23
+ # @param table_name [Symbol] name of the table to modify
24
+ # @private
25
+ #
13
26
  def initialize(keyspace, table_name)
14
27
  @keyspace, @table_name = keyspace, table_name
15
28
  @statements = []
16
29
  end
17
30
  private_class_method :new
18
31
 
32
+ #
33
+ # Apply the schema modifications to the table schema in the database
34
+ #
35
+ # @return [void]
36
+ #
37
+ # @api private
38
+ #
19
39
  def apply
20
40
  statements.each { |statement| keyspace.execute(statement) }
21
41
  end
22
42
 
43
+ #
44
+ # Add a column to the table
45
+ #
46
+ # @param name [Symbol] the name of the column
47
+ # @param type [Symbol,Type] the type of the column
48
+ # @return [void]
49
+ #
23
50
  def add_column(name, type)
24
- add_data_column(Column.new(name, type))
51
+ add_data_column(Column.new(name, type(type)))
25
52
  end
26
53
 
54
+ #
55
+ # Add a list to the table
56
+ #
57
+ # @param name [Symbol] the name of the list
58
+ # @param type [Symbol,Type] the type of the list elements
59
+ # @return [void]
60
+ #
27
61
  def add_list(name, type)
28
- add_data_column(List.new(name, type))
62
+ add_data_column(List.new(name, type(type)))
29
63
  end
30
64
 
65
+ #
66
+ # Add a set to the table
67
+ #
68
+ # @param name [Symbol] the name of the set
69
+ # @param type [Symbol,Type] the type of the set elements
70
+ # @return [void]
71
+ #
31
72
  def add_set(name, type)
32
- add_data_column(Set.new(name, type))
73
+ add_data_column(Set.new(name, type(type)))
33
74
  end
34
75
 
76
+ #
77
+ # Add a map to the table
78
+ #
79
+ # @param name [Symbol] the name of the map
80
+ # @param key_type [Symbol,Type] the type of the map's keys
81
+ # @param value_type [Symbol,Type] the type of the map's values
82
+ # @return [void]
83
+ #
35
84
  def add_map(name, key_type, value_type)
36
- add_data_column(Map.new(name, key_type, value_type))
85
+ add_data_column(Map.new(name, type(key_type), type(value_type)))
37
86
  end
38
87
 
88
+ #
89
+ # Change an existing column's type
90
+ #
91
+ # @param name [Symbol] the name of the column
92
+ # @param type [Symbol,Type] the new type of the column
93
+ # @return [void]
94
+ #
95
+ # @note Changing the type of a CQL column does not modify the data
96
+ # currently stored in the column. Thus, client-side handling is needed
97
+ # to convert old values to the new type at read time. Cequel does not
98
+ # currently support this functionality, although it may in the future.
99
+ # Altering column types is not recommended.
100
+ #
39
101
  def change_column(name, type)
40
- alter_table("ALTER #{name} TYPE #{type.cql_name}")
102
+ alter_table("ALTER #{name} TYPE #{type(type).cql_name}")
41
103
  end
42
104
 
105
+ #
106
+ # Rename a column
107
+ #
108
+ # @param old_name [Symbol] the current name of the column
109
+ # @param new_name [Symbol] the new name of the column
110
+ # @return [void]
111
+ #
43
112
  def rename_column(old_name, new_name)
44
113
  alter_table(%(RENAME "#{old_name}" TO "#{new_name}"))
45
114
  end
46
115
 
116
+ #
117
+ # Change one or more table storage properties
118
+ #
119
+ # @param options [Hash] map of property names to new values
120
+ # @return [void]
121
+ #
122
+ # @see Table#add_property
123
+ #
47
124
  def change_properties(options)
48
- properties = options.
49
- map { |name, value| TableProperty.new(name, value).to_cql }
125
+ properties = options
126
+ .map { |name, value| TableProperty.build(name, value).to_cql }
50
127
  alter_table("WITH #{properties.join(' AND ')}")
51
128
  end
52
129
 
53
- def create_index(column, index_name)
54
- index_name ||= "#{table_name}_#{column}_idx"
55
- statements << "CREATE INDEX #{index_name} ON #{table_name} (#{column})"
130
+ #
131
+ # Create a secondary index
132
+ #
133
+ # @param column_name [Symbol] name of the column to add an index on
134
+ # @param index_name [Symbol] name of the index; will be inferred from
135
+ # convention if nil
136
+ # @return [void]
137
+ #
138
+ def create_index(column_name, index_name = nil)
139
+ index_name ||= "#{table_name}_#{column_name}_idx"
140
+ statements <<
141
+ "CREATE INDEX #{index_name} ON #{table_name} (#{column_name})"
56
142
  end
57
143
 
144
+ #
145
+ # Remove a secondary index
146
+ #
147
+ # @param index_name [Symbol] the name of the index to remove
148
+ # @return [void]
149
+ #
58
150
  def drop_index(index_name)
59
151
  statements << "DROP INDEX #{index_name}"
60
152
  end
61
153
 
154
+ # @!visibility protected
62
155
  def add_data_column(column)
63
156
  add_column_statement(column)
64
157
  end
65
158
 
66
159
  protected
160
+
67
161
  attr_reader :keyspace, :table_name, :statements
68
162
 
69
163
  private
@@ -76,8 +170,9 @@ module Cequel
76
170
  alter_table("ADD #{column.to_cql}")
77
171
  end
78
172
 
173
+ def type(type)
174
+ ::Cequel::Type[type]
175
+ end
79
176
  end
80
-
81
177
  end
82
-
83
178
  end
@@ -1,25 +1,44 @@
1
1
  module Cequel
2
-
3
2
  module Schema
4
-
5
-
3
+ #
4
+ # Creates a new table schema in the database
5
+ #
6
6
  class TableWriter
7
-
7
+ #
8
+ # Creates a new table schema in the database given an object
9
+ # representation of the schema to create
10
+ #
11
+ # @param (see #initialize)
12
+ # @return (see #apply)
13
+ #
8
14
  def self.apply(keyspace, table)
9
15
  new(keyspace, table).apply
10
16
  end
11
17
 
18
+ #
19
+ # @param keyspace [Keyspace] keyspace in which to create the table
20
+ # @param table [Table] object representation of table schema
21
+ # @private
22
+ #
12
23
  def initialize(keyspace, table)
13
24
  @keyspace, @table = keyspace, table
14
25
  end
15
26
  private_class_method :new
16
27
 
28
+ #
29
+ # Create the table in the keyspace
30
+ #
31
+ # @return [void]
32
+ #
33
+ # @api private
34
+ #
17
35
  def apply
18
36
  keyspace.execute(create_statement)
19
37
  index_statements.each { |statement| keyspace.execute(statement) }
20
38
  end
21
39
 
22
40
  protected
41
+
23
42
  attr_reader :keyspace, :table
24
43
 
25
44
  private
@@ -36,7 +55,8 @@ module Cequel
36
55
  table.data_columns.each do |column|
37
56
  if column.indexed?
38
57
  statements <<
39
- "CREATE INDEX #{column.index_name} ON #{table.name} (#{column.name})"
58
+ "CREATE INDEX #{column.index_name} " \
59
+ "ON #{table.name} (#{column.name})"
40
60
  end
41
61
  end
42
62
  end
@@ -51,8 +71,8 @@ module Cequel
51
71
  end
52
72
 
53
73
  def keys_cql
54
- partition_cql = table.partition_key_columns.
55
- map { |key| key.name }.join(', ')
74
+ partition_cql = table.partition_key_columns
75
+ .map { |key| key.name }.join(', ')
56
76
  if table.clustering_columns.any?
57
77
  nonpartition_cql =
58
78
  table.clustering_columns.map { |key| key.name }.join(', ')
@@ -63,19 +83,17 @@ module Cequel
63
83
  end
64
84
 
65
85
  def properties_cql
66
- properties_fragments = table.properties.
67
- map { |_, property| property.to_cql }
86
+ properties_fragments = table.properties
87
+ .map { |_, property| property.to_cql }
68
88
  properties_fragments << 'COMPACT STORAGE' if table.compact_storage?
69
89
  if table.clustering_columns.any?
70
90
  clustering_fragment =
71
91
  table.clustering_columns.map(&:clustering_order_cql).join(',')
72
- properties_fragments << "CLUSTERING ORDER BY (#{clustering_fragment})"
92
+ properties_fragments <<
93
+ "CLUSTERING ORDER BY (#{clustering_fragment})"
73
94
  end
74
95
  properties_fragments.join(' AND ') if properties_fragments.any?
75
96
  end
76
-
77
97
  end
78
-
79
98
  end
80
-
81
99
  end
@@ -1,60 +1,91 @@
1
1
  module Cequel
2
-
3
2
  module Schema
4
-
3
+ #
4
+ # DSL for describing a series of schema modification statements
5
+ #
5
6
  class UpdateTableDSL < BasicObject
6
-
7
+ extend ::Forwardable
8
+ #
9
+ # Describe a series of schema modifications and build a {TableUpdater}
10
+ # to encapsulate them
11
+ #
12
+ # @param (see #initialize)
13
+ # @yield a block evaluated in the context of an {UpdateTableDSL} instance
14
+ # @return [void]
15
+ #
16
+ # @api private
17
+ # @see Keyspace#update_table
18
+ #
7
19
  def self.apply(updater, &block)
8
20
  dsl = new(updater)
9
21
  dsl.instance_eval(&block)
10
22
  end
11
23
 
24
+ #
25
+ # @param updater [TableUpdater]
26
+ #
27
+ # @api private
28
+ #
12
29
  def initialize(updater)
13
30
  @updater = updater
14
31
  end
15
32
 
16
- def add_column(name, type)
17
- @updater.add_column(name, ::Cequel::Type[type])
18
- end
19
-
20
- def add_list(name, type)
21
- @updater.add_list(name, ::Cequel::Type[type])
22
- end
23
-
24
- def add_set(name, type)
25
- @updater.add_set(name, ::Cequel::Type[type])
26
- end
27
-
28
- def add_map(name, key_type, value_type)
29
- @updater.add_map(name, ::Cequel::Type[key_type],
30
- ::Cequel::Type[value_type])
31
- end
32
-
33
- def change_column(name, type)
34
- @updater.change_column(name, ::Cequel::Type[type])
35
- end
36
-
37
- def rename_column(old_name, new_name)
38
- @updater.rename_column(old_name, new_name)
39
- end
40
-
41
- def change_properties(options)
42
- @updater.change_properties(options)
43
- end
33
+ #
34
+ # @!method add_column(name, type)
35
+ # (see Cequel::Schema::TableUpdater#add_column)
36
+ #
37
+ def_delegator :@updater, :add_column
38
+
39
+ #
40
+ # @!method add_list(name, type)
41
+ # (see Cequel::Schema::TableUpdater#add_list)
42
+ #
43
+ def_delegator :@updater, :add_list
44
+
45
+ #
46
+ # @!method add_set(name, type)
47
+ # (see Cequel::Schema::TableUpdater#add_set)
48
+ #
49
+ def_delegator :@updater, :add_set
50
+
51
+ #
52
+ # @!method add_map(name, key_type, value_type)
53
+ # (see Cequel::Schema::TableUpdater#add_map)
54
+ #
55
+ def_delegator :@updater, :add_map
56
+
57
+ #
58
+ # @!method change_column(name, type)
59
+ # (see Cequel::Schema::TableUpdater#change_column)
60
+ #
61
+ def_delegator :@updater, :change_column
62
+
63
+ #
64
+ # @!method rename_column(old_name, new_name)
65
+ # (see Cequel::Schema::TableUpdater#rename_column)
66
+ #
67
+ def_delegator :@updater, :rename_column
68
+
69
+ #
70
+ # @!method change_properties(options)
71
+ # (see Cequel::Schema::TableUpdater#change_properties)
72
+ #
73
+ def_delegator :@updater, :change_properties
44
74
  alias_method :change_options, :change_properties
45
75
 
46
- def create_index(column_name, index_name = nil)
47
- @updater.create_index(column_name, index_name)
48
- end
76
+ #
77
+ # @!method create_index(column_name, index_name = nil)
78
+ # (see Cequel::Schema::TableUpdater#create_index
79
+ #
80
+ def_delegator :@updater, :create_index
49
81
  alias_method :add_index, :create_index
50
82
 
51
- def drop_index(index_name)
52
- @updater.drop_index(index_name)
53
- end
83
+ #
84
+ # @!method drop_index(index_name)
85
+ # (see Cequel::Schema::TableUpdater#drop_index)
86
+ #
87
+ def_delegator :@updater, :drop_index
54
88
  alias_method :remove_index, :drop_index
55
-
56
89
  end
57
-
58
90
  end
59
-
60
91
  end
data/lib/cequel/type.rb CHANGED
@@ -1,71 +1,172 @@
1
1
  require 'singleton'
2
2
 
3
3
  module Cequel
4
-
4
+ #
5
+ # The Type module encapsulates information about the CQL3 type system. Each
6
+ # type has a `cql_name`, which is the name of the type as defined in CQL, and
7
+ # an `internal_name`, which is the name of the type in the lower-level
8
+ # interface that is exposed when introspecting table information in the
9
+ # database.
10
+ #
11
+ # As well as knowing their respective names, types also know how to cast Ruby
12
+ # objects to the correct canonical class corresponding to the type. These
13
+ # implicit types are used by the underlying `cassandra-cql` library to
14
+ # determine how to represent values when passing them to Cassandra.
15
+ #
16
+ # @since 1.0.0
17
+ #
5
18
  module Type
6
-
19
+ # Raised if an unknown type is looked up
7
20
  UnknownType = Class.new(ArgumentError)
8
21
 
9
22
  BY_CQL_NAME = {}
10
23
  BY_INTERNAL_NAME = {}
11
24
 
25
+ #
26
+ # Register a type for lookup
27
+ #
28
+ # @param type [Type] a new type
29
+ # @return [void]
30
+ #
12
31
  def self.register(type)
13
32
  BY_CQL_NAME[type.cql_name] = type
14
33
  type.cql_aliases.each { |aliaz| BY_CQL_NAME[aliaz] = type }
15
- BY_INTERNAL_NAME[type.internal_name] = type
34
+ type.internal_names.each do |internal_name|
35
+ BY_INTERNAL_NAME[internal_name] = type
36
+ end
16
37
  end
17
38
 
39
+ #
40
+ # Return a type corresponding to the given input
41
+ #
42
+ # @param cql_name [Symbol,Base] CQL name of a type, or a type
43
+ # @return [Base] type with the given CQL name
44
+ #
18
45
  def self.[](cql_name)
19
46
  cql_name.is_a?(Base) ? cql_name : lookup_cql(cql_name)
20
47
  end
21
48
 
49
+ #
50
+ # Look up a type by CQL name
51
+ #
52
+ # @param cql_name [Symbol] CQL name of a type
53
+ # @return [Base] type with the given CQL name
54
+ # @raise [UnknownType] if no type by that name is registered
55
+ #
22
56
  def self.lookup_cql(cql_name)
23
57
  BY_CQL_NAME.fetch(cql_name.to_sym)
24
58
  rescue KeyError
25
59
  raise UnknownType, "Unrecognized CQL type #{cql_name.inspect}"
26
60
  end
27
61
 
62
+ #
63
+ # Look up a type by internal name
64
+ #
65
+ # @param internal_name [String] internal name of a type
66
+ # @return [Base] type with the given internal name
67
+ # @raise [UnknownType] if no type by that name is registered
68
+ #
28
69
  def self.lookup_internal(internal_name)
29
70
  BY_INTERNAL_NAME.fetch(internal_name)
30
71
  rescue KeyError
31
72
  raise UnknownType, "Unrecognized internal type #{internal_name.inspect}"
32
73
  end
33
74
 
75
+ #
76
+ # The base class for all type objects. Types are singletons.
77
+ #
78
+ # @abstract Subclasses should implement {#cast}, and may implement
79
+ # {#internal_names} if it cannot be inferred from the class name. The
80
+ # name of the type class should be the camel-cased CQL name of the type
81
+ #
34
82
  class Base
35
83
  include Singleton
36
84
 
85
+ #
86
+ # @return the name of the type used in CQL. This is also the name that is
87
+ # used in all of Cequel's public interfaces
88
+ #
37
89
  def cql_name
38
90
  self.class.name.demodulize.underscore.to_sym
39
91
  end
40
92
 
93
+ #
94
+ # @return [Array<Symbol>] other names used in CQL for this type
95
+ #
41
96
  def cql_aliases
42
97
  []
43
98
  end
44
99
 
100
+ #
101
+ # @return [Array<String>] full class name of this type used in
102
+ # Cassandra's underlying representation
103
+ #
104
+ # @deprecated use {internal_names}
105
+ #
45
106
  def internal_name
46
- "org.apache.cassandra.db.marshal.#{self.class.name.demodulize}Type"
107
+ internal_names.first
47
108
  end
48
109
 
110
+ #
111
+ # @return [Array<String>] full class name(s) of this type used in
112
+ # Cassandra's underlying representation (allows for multiple values for
113
+ # types that have different names between different versions)
114
+ #
115
+ def internal_names
116
+ ["org.apache.cassandra.db.marshal.#{self.class.name.demodulize}Type"]
117
+ end
118
+
119
+ #
120
+ # @param value the value to cast
121
+ # @return the value cast to the correct Ruby class for this type
122
+ #
49
123
  def cast(value)
50
124
  value
51
125
  end
52
126
 
127
+ #
128
+ # CQL only allows changing column types when the old type's binary
129
+ # representation is compatible with the new type.
130
+ #
131
+ # @return [Array<Type>] new types that columns of this type may be
132
+ # altered to
133
+ #
134
+ def compatible_types
135
+ [Type[:blob]]
136
+ end
137
+
138
+ #
139
+ # A string representation of this type
140
+ #
53
141
  def to_s
54
142
  cql_name.to_s
55
143
  end
56
-
57
144
  end
58
145
 
146
+ #
147
+ # Abstract superclass for types that represent character data
148
+ #
149
+ # @abstract Subclasses must implement `#encoding`, which returns the name
150
+ # of the Ruby encoding corresponding to the character encoding used for
151
+ # values of this type
152
+ #
59
153
  class String < Base
60
-
61
154
  def cast(value)
62
155
  str = String(value)
63
156
  str.encoding.name == encoding ? str : str.dup.force_encoding(encoding)
64
157
  end
65
-
66
158
  end
67
159
 
160
+ #
161
+ # `ascii` columns store 7-bit ASCII character data
162
+ #
163
+ # @see TK CQL3 documentation for ascii type
164
+ #
68
165
  class Ascii < String
166
+ def compatible_types
167
+ super + [Type[:text]]
168
+ end
169
+
69
170
  private
70
171
 
71
172
  def encoding
@@ -74,14 +175,19 @@ module Cequel
74
175
  end
75
176
  register Ascii.instance
76
177
 
178
+ #
179
+ # `blob` columns store arbitrary bytes of data, represented as 8-bit ASCII
180
+ # strings of hex digits
181
+ #
182
+ # @see TK CQL3 documentation for blob type
183
+ #
77
184
  class Blob < String
78
-
79
- def internal_name
80
- 'org.apache.cassandra.db.marshal.BytesType'
185
+ def internal_names
186
+ ['org.apache.cassandra.db.marshal.BytesType']
81
187
  end
82
188
 
83
189
  def cast(value)
84
- value = value.to_s(16) if Integer === value
190
+ value = value.to_s(16) if value.is_a?(Integer)
85
191
  super
86
192
  end
87
193
 
@@ -90,10 +196,14 @@ module Cequel
90
196
  def encoding
91
197
  'ASCII-8BIT'
92
198
  end
93
-
94
199
  end
95
200
  register Blob.instance
96
201
 
202
+ #
203
+ # `boolean` types store boolean values
204
+ #
205
+ # @see TK CQL3 documentation for boolean type
206
+ #
97
207
  class Boolean < Base
98
208
  def cast(value)
99
209
  !!value
@@ -101,26 +211,47 @@ module Cequel
101
211
  end
102
212
  register Boolean.instance
103
213
 
214
+ #
215
+ # Counter columns are a special type of column in Cassandra that can be
216
+ # incremented and decremented atomically. Counter columns cannot comingle
217
+ # with regular data columns in the same table. Unlike other columns,
218
+ # counter columns cannot be updated without Cassandra internally reading
219
+ # the existing state of the column
220
+ #
221
+ # @see TK CQL3 documentation for counter columns
222
+ #
104
223
  class Counter < Base
224
+ def internal_names
225
+ ['org.apache.cassandra.db.marshal.CounterColumnType']
226
+ end
105
227
 
106
- def internal_name
107
- 'org.apache.cassandra.db.marshal.CounterColumnType'
228
+ def compatible_types
229
+ []
108
230
  end
109
231
 
110
232
  def cast(value)
111
233
  Integer(value)
112
234
  end
113
-
114
235
  end
115
236
  register Counter.instance
116
237
 
238
+ #
239
+ # `decimal` columns store decimal numeric values
240
+ #
241
+ # @see TK CQL3 documentation for decimal columns
242
+ #
117
243
  class Decimal < Base
118
244
  def cast(value)
119
- BigDecimal === value ? value : BigDecimal.new(value, 0)
245
+ value.is_a?(BigDecimal) ? value : BigDecimal.new(value, 0)
120
246
  end
121
247
  end
122
248
  register Decimal.instance
123
249
 
250
+ #
251
+ # `double` columns store 64-bit floating-point numeric values
252
+ #
253
+ # @see TK CQL3 documentation for double columns
254
+ #
124
255
  class Double < Base
125
256
  def cast(value)
126
257
  Float(value)
@@ -128,44 +259,64 @@ module Cequel
128
259
  end
129
260
  register Double.instance
130
261
 
262
+ #
263
+ # TK
264
+ #
265
+ # @see TK CQL3 documentation for inet columns
266
+ #
131
267
  class Inet < Base
132
-
133
- def internal_name
134
- 'org.apache.cassandra.db.marshal.InetAddressType'
268
+ def internal_names
269
+ ['org.apache.cassandra.db.marshal.InetAddressType']
135
270
  end
136
-
137
271
  end
138
272
  register Inet.instance
139
273
 
274
+ #
275
+ # `int` columns store 32-bit integer values
276
+ #
277
+ # @see TK CQL3 documentation for int columns
278
+ #
140
279
  class Int < Base
141
-
142
- def internal_name
143
- 'org.apache.cassandra.db.marshal.Int32Type'
280
+ def internal_names
281
+ ['org.apache.cassandra.db.marshal.Int32Type']
144
282
  end
145
283
 
146
284
  def cast(value)
147
285
  Integer(value)
148
286
  end
149
-
150
287
  end
151
288
  register Int.instance
152
289
 
290
+ #
291
+ # `float` columns store 32-bit floating-point numeric values
292
+ #
293
+ # @see TK CQL3 documentation for float columns
294
+ #
153
295
  class Float < Double; end
154
296
  register Float.instance
155
297
 
156
- class Long < Int
157
-
158
- def internal_name
159
- 'org.apache.cassandra.db.marshal.LongType'
298
+ #
299
+ # `bigint` columns store 64-bit integer values
300
+ #
301
+ # @see TK CQL3 documentation for bigint columns
302
+ #
303
+ class Bigint < Int
304
+ def internal_names
305
+ ['org.apache.cassandra.db.marshal.LongType']
160
306
  end
161
-
162
307
  end
163
- register Long.instance
164
-
308
+ register Bigint.instance
309
+
310
+ #
311
+ # `text` columns store UTF-8 character data. They are also known as
312
+ # `varchar` columns; the names can be used interchangeably. Text columns do
313
+ # not have a length limit
314
+ #
315
+ # @see TK CQL3 documentation for text columns
316
+ #
165
317
  class Text < String
166
-
167
- def internal_name
168
- 'org.apache.cassandra.db.marshal.UTF8Type'
318
+ def internal_names
319
+ ['org.apache.cassandra.db.marshal.UTF8Type']
169
320
  end
170
321
 
171
322
  def cql_aliases
@@ -177,31 +328,38 @@ module Cequel
177
328
  def encoding
178
329
  'UTF-8'
179
330
  end
180
-
181
331
  end
182
332
  register Text.instance
183
333
 
334
+ #
335
+ # `timestamp` columns store timestamps. Timestamps do not include time zone
336
+ # data, and all input times are cast to UTC before being stored.
337
+ #
184
338
  class Timestamp < Base
185
-
186
- def internal_name
187
- 'org.apache.cassandra.db.marshal.DateType'
339
+ def internal_names
340
+ ['org.apache.cassandra.db.marshal.DateType',
341
+ 'org.apache.cassandra.db.marshal.TimestampType']
188
342
  end
189
343
 
190
344
  def cast(value)
191
- if ::String === value then Time.parse(value)
345
+ if value.is_a?(::String) then Time.parse(value)
192
346
  elsif value.respond_to?(:to_time) then value.to_time
193
- elsif Numeric === value then Time.at(value)
347
+ elsif value.is_a?(Numeric) then Time.at(value)
194
348
  else Time.parse(value.to_s)
195
349
  end.utc
196
350
  end
197
-
198
351
  end
199
352
  register Timestamp.instance
200
353
 
354
+ #
355
+ # `uuid` columns store type 1 and type 4 UUIDs. Cequel uses the
356
+ # `CassandraCQL::UUID` type to represent UUIDs in Ruby, since this is what
357
+ # the underlying `cassandra-cql` library expects. Other UUID formats are
358
+ # supported as inputs.
359
+ #
201
360
  class Uuid < Base
202
-
203
- def internal_name
204
- 'org.apache.cassandra.db.marshal.UUIDType'
361
+ def internal_names
362
+ ['org.apache.cassandra.db.marshal.UUIDType']
205
363
  end
206
364
 
207
365
  def cast(value)
@@ -211,28 +369,31 @@ module Cequel
211
369
  else CassandraCQL::UUID.new(value)
212
370
  end
213
371
  end
214
-
215
372
  end
216
373
  register Uuid.instance
217
374
 
375
+ #
376
+ # `timeuuid` columns are a special type of UUID column that support
377
+ # time-based queries. For instance, a `timeuuid` clustering column can be
378
+ # filtered by ranges of times into which the UUIDs must fall. This
379
+ # functionality presumes the use of type 1 UUIDs, which encode the
380
+ # timestamp of their creation.
381
+ #
218
382
  class Timeuuid < Uuid
219
-
220
- def internal_name
221
- 'org.apache.cassandra.db.marshal.TimeUUIDType'
383
+ def internal_names
384
+ ['org.apache.cassandra.db.marshal.TimeUUIDType']
222
385
  end
223
-
224
386
  end
225
387
  register Timeuuid.instance
226
388
 
389
+ #
390
+ # `varint` columns store arbitrary-length integer data
391
+ #
227
392
  class Varint < Int
228
-
229
393
  def internal_name
230
394
  'org.apache.cassandra.db.marshal.IntegerType'
231
395
  end
232
-
233
396
  end
234
397
  register Varint.instance
235
-
236
398
  end
237
-
238
399
  end