cequel 1.0.0.rc1 → 1.0.0.rc2
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.
- checksums.yaml +4 -4
- data/lib/cequel.rb +18 -0
- data/lib/cequel/errors.rb +8 -4
- data/lib/cequel/metal.rb +14 -0
- data/lib/cequel/metal/batch.rb +21 -11
- data/lib/cequel/metal/batch_manager.rb +74 -0
- data/lib/cequel/metal/cql_row_specification.rb +19 -6
- data/lib/cequel/metal/data_set.rb +400 -163
- data/lib/cequel/metal/deleter.rb +45 -11
- data/lib/cequel/metal/incrementer.rb +23 -10
- data/lib/cequel/metal/inserter.rb +19 -6
- data/lib/cequel/metal/keyspace.rb +82 -159
- data/lib/cequel/metal/logger.rb +71 -0
- data/lib/cequel/metal/logging.rb +47 -0
- data/lib/cequel/metal/new_relic_instrumentation.rb +26 -0
- data/lib/cequel/metal/row.rb +36 -10
- data/lib/cequel/metal/row_specification.rb +21 -8
- data/lib/cequel/metal/statement.rb +30 -6
- data/lib/cequel/metal/updater.rb +89 -12
- data/lib/cequel/metal/writer.rb +23 -14
- data/lib/cequel/record.rb +52 -6
- data/lib/cequel/record/association_collection.rb +13 -6
- data/lib/cequel/record/associations.rb +146 -54
- data/lib/cequel/record/belongs_to_association.rb +34 -7
- data/lib/cequel/record/bound.rb +69 -12
- data/lib/cequel/record/bulk_writes.rb +29 -1
- data/lib/cequel/record/callbacks.rb +22 -6
- data/lib/cequel/record/collection.rb +273 -36
- data/lib/cequel/record/configuration_generator.rb +5 -0
- data/lib/cequel/record/data_set_builder.rb +86 -0
- data/lib/cequel/record/dirty.rb +11 -8
- data/lib/cequel/record/errors.rb +38 -4
- data/lib/cequel/record/has_many_association.rb +42 -9
- data/lib/cequel/record/lazy_record_collection.rb +39 -10
- data/lib/cequel/record/mass_assignment.rb +14 -6
- data/lib/cequel/record/persistence.rb +157 -20
- data/lib/cequel/record/properties.rb +147 -24
- data/lib/cequel/record/railtie.rb +15 -2
- data/lib/cequel/record/record_set.rb +504 -75
- data/lib/cequel/record/schema.rb +77 -13
- data/lib/cequel/record/scoped.rb +16 -11
- data/lib/cequel/record/secondary_indexes.rb +42 -6
- data/lib/cequel/record/tasks.rb +2 -1
- data/lib/cequel/record/validations.rb +51 -11
- data/lib/cequel/schema.rb +9 -0
- data/lib/cequel/schema/column.rb +172 -33
- data/lib/cequel/schema/create_table_dsl.rb +62 -31
- data/lib/cequel/schema/keyspace.rb +106 -7
- data/lib/cequel/schema/migration_validator.rb +128 -0
- data/lib/cequel/schema/table.rb +183 -20
- data/lib/cequel/schema/table_property.rb +92 -34
- data/lib/cequel/schema/table_reader.rb +45 -15
- data/lib/cequel/schema/table_synchronizer.rb +101 -43
- data/lib/cequel/schema/table_updater.rb +114 -19
- data/lib/cequel/schema/table_writer.rb +31 -13
- data/lib/cequel/schema/update_table_dsl.rb +71 -40
- data/lib/cequel/type.rb +214 -53
- data/lib/cequel/util.rb +6 -9
- data/lib/cequel/version.rb +2 -1
- data/spec/examples/record/associations_spec.rb +12 -12
- data/spec/examples/record/persistence_spec.rb +5 -5
- data/spec/examples/record/record_set_spec.rb +62 -50
- data/spec/examples/schema/table_synchronizer_spec.rb +37 -11
- data/spec/examples/schema/table_updater_spec.rb +3 -3
- data/spec/examples/spec_helper.rb +2 -11
- data/spec/examples/type_spec.rb +3 -3
- metadata +23 -4
- 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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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.
|
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
|
-
|
54
|
-
|
55
|
-
|
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}
|
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 <<
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
107
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
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
|
-
|
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
|
-
|
187
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|