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,56 +1,87 @@
|
|
1
1
|
module Cequel
|
2
|
-
|
3
2
|
module Schema
|
4
|
-
|
3
|
+
#
|
4
|
+
# Implements a DSL that can be used to define a table schema
|
5
|
+
#
|
6
|
+
# @see Keyspace#create_table
|
7
|
+
#
|
5
8
|
class CreateTableDSL < BasicObject
|
6
|
-
|
9
|
+
extend ::Forwardable
|
10
|
+
#
|
11
|
+
# Evaluate `block` in the context of this DSL, and apply directives to
|
12
|
+
# `table`
|
13
|
+
#
|
14
|
+
# @param table [Table] a table
|
15
|
+
# @yield block evaluated in the context of the create table DSL
|
16
|
+
# @return [void]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
7
20
|
def self.apply(table, &block)
|
8
21
|
dsl = new(table)
|
9
22
|
dsl.instance_eval(&block)
|
10
23
|
end
|
11
24
|
|
25
|
+
#
|
26
|
+
# @param table [Table] table to apply directives to
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
12
30
|
def initialize(table)
|
13
31
|
@table = table
|
14
32
|
end
|
15
33
|
|
16
|
-
|
17
|
-
|
18
|
-
|
34
|
+
#
|
35
|
+
# @!method partition_key(name, type)
|
36
|
+
# (see Cequel::Schema::Table#add_partition_key)
|
37
|
+
#
|
38
|
+
def_delegator :@table, :add_partition_key, :partition_key
|
19
39
|
|
20
|
-
|
21
|
-
|
22
|
-
|
40
|
+
#
|
41
|
+
# @!method key(name, type, clustering_order = nil)
|
42
|
+
# (see Cequel::Schema::Table#add_key)
|
43
|
+
#
|
44
|
+
def_delegator :@table, :add_key, :key
|
23
45
|
|
24
|
-
|
25
|
-
|
26
|
-
|
46
|
+
#
|
47
|
+
# @!method column(name, type, options = {})
|
48
|
+
# (see Cequel::Schema::Table#add_data_column)
|
49
|
+
#
|
50
|
+
def_delegator :@table, :add_data_column, :column
|
27
51
|
|
28
|
-
|
29
|
-
|
30
|
-
|
52
|
+
#
|
53
|
+
# @!method list(name, type)
|
54
|
+
# (see Cequel::Schema::Table#add_list)
|
55
|
+
#
|
56
|
+
def_delegator :@table, :add_list, :list
|
31
57
|
|
32
|
-
|
33
|
-
|
34
|
-
|
58
|
+
#
|
59
|
+
# @!method set(name, type)
|
60
|
+
# (see Cequel::Schema::Table#add_set)
|
61
|
+
#
|
62
|
+
def_delegator :@table, :add_set, :set
|
35
63
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
)
|
42
|
-
end
|
64
|
+
#
|
65
|
+
# @!method map(name, key_type, value_type)
|
66
|
+
# (see Cequel::Schema::Table#add_map)
|
67
|
+
#
|
68
|
+
def_delegator :@table, :add_map, :map
|
43
69
|
|
44
|
-
|
45
|
-
|
46
|
-
|
70
|
+
#
|
71
|
+
# @!method with(name, value)
|
72
|
+
# (see Cequel::Schema::Table#add_property)
|
73
|
+
#
|
74
|
+
def_delegator :@table, :add_property, :with
|
47
75
|
|
76
|
+
#
|
77
|
+
# Direct that this table use "compact storage". This is primarily useful
|
78
|
+
# for backwards compatibility with legacy CQL2 table schemas.
|
79
|
+
#
|
80
|
+
# @return [void]
|
81
|
+
#
|
48
82
|
def compact_storage
|
49
83
|
@table.compact_storage = true
|
50
84
|
end
|
51
|
-
|
52
85
|
end
|
53
|
-
|
54
86
|
end
|
55
|
-
|
56
87
|
end
|
@@ -1,20 +1,44 @@
|
|
1
1
|
module Cequel
|
2
|
-
|
3
2
|
module Schema
|
4
|
-
|
3
|
+
#
|
4
|
+
# Provides read/write access to the schema for a keyspace and the tables it
|
5
|
+
# contains
|
6
|
+
#
|
7
|
+
# @deprecated These methods will be exposed directly on
|
8
|
+
# {Cequel::Metal::Keyspace} in a future version of Cequel
|
9
|
+
#
|
5
10
|
class Keyspace
|
6
|
-
|
11
|
+
#
|
12
|
+
# @param keyspace [Keyspace] the keyspace whose schema this object
|
13
|
+
# manipulates
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
7
17
|
def initialize(keyspace)
|
8
18
|
@keyspace = keyspace
|
9
19
|
end
|
10
20
|
|
21
|
+
#
|
22
|
+
# Create this keyspace in the database
|
23
|
+
#
|
24
|
+
# @param options [Options] persistence options for this keyspace.
|
25
|
+
# @option options [String] :class ("SimpleStrategy") the replication
|
26
|
+
# strategy to use for this keyspace
|
27
|
+
# @option options [Integer] :replication_factor (1) the number of
|
28
|
+
# replicas that should exist for each piece of data
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @see TK CQL3 CREATE KEYSPACE documentation
|
32
|
+
#
|
11
33
|
def create!(options = {})
|
12
34
|
bare_connection =
|
13
35
|
Metal::Keyspace.new(keyspace.configuration.except(:keyspace))
|
14
36
|
|
15
37
|
options = options.symbolize_keys
|
16
38
|
options[:class] ||= 'SimpleStrategy'
|
17
|
-
|
39
|
+
if options[:class] == 'SimpleStrategy'
|
40
|
+
options[:replication_factor] ||= 1
|
41
|
+
end
|
18
42
|
options_strs = options.map do |name, value|
|
19
43
|
"'#{name}': #{CassandraCQL::Statement.quote(value)}"
|
20
44
|
end
|
@@ -25,34 +49,111 @@ module Cequel
|
|
25
49
|
CQL
|
26
50
|
end
|
27
51
|
|
52
|
+
#
|
53
|
+
# Drop this keyspace from the database
|
54
|
+
#
|
55
|
+
# @return [void]
|
56
|
+
#
|
57
|
+
# @see TK CQL3 DROP KEYSPACE documentation
|
58
|
+
#
|
28
59
|
def drop!
|
29
60
|
keyspace.execute("DROP KEYSPACE #{keyspace.name}")
|
30
61
|
end
|
31
62
|
|
63
|
+
#
|
64
|
+
# @param name [Symbol] name of the table to read
|
65
|
+
# @return [Table] object representation of the table schema as it
|
66
|
+
# currently exists in the database
|
67
|
+
#
|
32
68
|
def read_table(name)
|
33
69
|
TableReader.read(keyspace, name)
|
34
70
|
end
|
35
71
|
|
72
|
+
#
|
73
|
+
# Create a table in the keyspace
|
74
|
+
#
|
75
|
+
# @param name [Symbol] name of the new table to create
|
76
|
+
# @yield block evaluated in the context of a {CreateTableDSL}
|
77
|
+
# @return [void]
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# schema.create_table :posts do
|
81
|
+
# partition_key :blog_subdomain, :text
|
82
|
+
# key :id, :timeuuid
|
83
|
+
#
|
84
|
+
# column :title, :text
|
85
|
+
# column :body, :text
|
86
|
+
# column :author_id, :uuid, :index => true
|
87
|
+
#
|
88
|
+
# with :caching, :all
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# @see CreateTableDSL
|
92
|
+
#
|
36
93
|
def create_table(name, &block)
|
37
94
|
table = Table.new(name)
|
38
95
|
CreateTableDSL.apply(table, &block)
|
39
96
|
TableWriter.apply(keyspace, table)
|
40
97
|
end
|
41
98
|
|
99
|
+
#
|
100
|
+
# Make changes to an existing table in the keyspace
|
101
|
+
#
|
102
|
+
# @param name [Symbol] the name of the table to alter
|
103
|
+
# @yield block evaluated in the context of an {UpdateTableDSL}
|
104
|
+
# @return [void]
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# schema.alter_table :posts do
|
108
|
+
# add_set :categories, :text
|
109
|
+
# rename_column :author_id, :author_uuid
|
110
|
+
# create_index :title
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# @see UpdateTableDSL
|
114
|
+
#
|
42
115
|
def alter_table(name, &block)
|
43
116
|
updater = TableUpdater.apply(keyspace, name) do |updater|
|
44
117
|
UpdateTableDSL.apply(updater, &block)
|
45
118
|
end
|
46
119
|
end
|
47
120
|
|
121
|
+
#
|
122
|
+
# Remove all data from this table. Truncating a table can be much slower
|
123
|
+
# than simply iterating over its keys and issuing `DELETE` statements,
|
124
|
+
# particularly if the table does not have many rows. Truncating is
|
125
|
+
# equivalent to dropping a table and then recreating it
|
126
|
+
#
|
127
|
+
# @param name [Symbol] name of the table to truncate.
|
128
|
+
# @return [void]
|
129
|
+
#
|
48
130
|
def truncate_table(name)
|
49
131
|
keyspace.execute("TRUNCATE #{name}")
|
50
132
|
end
|
51
133
|
|
134
|
+
#
|
135
|
+
# Drop this table from the keyspace
|
136
|
+
#
|
137
|
+
# @param name [Symbol] name of the table to drop
|
138
|
+
# @return [void]
|
139
|
+
#
|
52
140
|
def drop_table(name)
|
53
141
|
keyspace.execute("DROP TABLE #{name}")
|
54
142
|
end
|
55
143
|
|
144
|
+
#
|
145
|
+
# Create or update a table to match a given schema structure. The desired
|
146
|
+
# schema structure is defined by the directives given in the block; this
|
147
|
+
# is then compared to the existing table in the database (if it is
|
148
|
+
# defined at all), and then the table is created or altered accordingly.
|
149
|
+
#
|
150
|
+
# @param name [Symbol] name of the table to synchronize
|
151
|
+
# @yield (see #create_table)
|
152
|
+
# @return [void]
|
153
|
+
# @raise (see TableSynchronizer#apply)
|
154
|
+
#
|
155
|
+
# @see #create_table Example of DSL usage
|
156
|
+
#
|
56
157
|
def sync_table(name, &block)
|
57
158
|
existing = read_table(name)
|
58
159
|
updated = Table.new(name)
|
@@ -62,10 +163,8 @@ module Cequel
|
|
62
163
|
alias_method :synchronize_table, :sync_table
|
63
164
|
|
64
165
|
protected
|
65
|
-
attr_reader :keyspace
|
66
166
|
|
167
|
+
attr_reader :keyspace
|
67
168
|
end
|
68
|
-
|
69
169
|
end
|
70
|
-
|
71
170
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Cequel
|
2
|
+
module Schema
|
3
|
+
#
|
4
|
+
# This is a utility class to test that it is possible to perform a given
|
5
|
+
# table schema migration
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
class MigrationValidator
|
10
|
+
extend Forwardable
|
11
|
+
#
|
12
|
+
# Check for various impossible schema changes and raise if any are found
|
13
|
+
#
|
14
|
+
# @param (see #initialize)
|
15
|
+
# @return [void]
|
16
|
+
# @raise (see #validate)
|
17
|
+
#
|
18
|
+
def self.validate!(synchronizer)
|
19
|
+
new(synchronizer).validate!
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# @param synchronizer [TableSynchronizer] the synchronizer to validate
|
24
|
+
#
|
25
|
+
def initialize(synchronizer)
|
26
|
+
@synchronizer = synchronizer
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Check for various impossible schema changes and raise if any are found
|
31
|
+
#
|
32
|
+
# @raise [InvalidSchemaMigration] if it is impossible to modify existing
|
33
|
+
# table to match desired schema
|
34
|
+
#
|
35
|
+
def validate!
|
36
|
+
assert_keys_match!
|
37
|
+
assert_data_columns_match!
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_reader :synchronizer
|
43
|
+
def_delegators :synchronizer, :each_key_pair,
|
44
|
+
:each_clustering_column_pair, :each_data_column_pair,
|
45
|
+
:existing, :updated
|
46
|
+
|
47
|
+
def assert_keys_match!
|
48
|
+
assert_partition_keys_match!
|
49
|
+
assert_clustering_columns_match!
|
50
|
+
assert_same_key_types!
|
51
|
+
assert_same_clustering_order!
|
52
|
+
end
|
53
|
+
|
54
|
+
def assert_same_key_types!
|
55
|
+
each_key_pair do |old_key, new_key|
|
56
|
+
if old_key.type != new_key.type
|
57
|
+
fail InvalidSchemaMigration,
|
58
|
+
"Can't change type of key column #{old_key.name} from " \
|
59
|
+
"#{old_key.type} to #{new_key.type}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def assert_same_clustering_order!
|
65
|
+
each_clustering_column_pair do |old_key, new_key|
|
66
|
+
if old_key.clustering_order != new_key.clustering_order
|
67
|
+
fail InvalidSchemaMigration,
|
68
|
+
"Can't change the clustering order of #{old_key.name} from " \
|
69
|
+
"#{old_key.clustering_order} to #{new_key.clustering_order}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def assert_partition_keys_match!
|
75
|
+
if existing.partition_key_column_count !=
|
76
|
+
updated.partition_key_column_count
|
77
|
+
|
78
|
+
fail InvalidSchemaMigration,
|
79
|
+
"Existing partition keys " \
|
80
|
+
"#{existing.partition_key_column_names.join(',')} " \
|
81
|
+
"differ from specified partition keys " \
|
82
|
+
"#{updated.partition_key_column_names.join(',')}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def assert_clustering_columns_match!
|
87
|
+
if existing.clustering_column_count != updated.clustering_column_count
|
88
|
+
fail InvalidSchemaMigration,
|
89
|
+
"Existing clustering columns " \
|
90
|
+
"#{existing.clustering_column_names.join(',')} " \
|
91
|
+
"differ from specified clustering keys " \
|
92
|
+
"#{updated.clustering_column_names.join(',')}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def assert_data_columns_match!
|
97
|
+
each_data_column_pair do |old_column, new_column|
|
98
|
+
if old_column && new_column
|
99
|
+
assert_valid_type_transition!(old_column, new_column)
|
100
|
+
assert_same_column_structure!(old_column, new_column)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def assert_valid_type_transition!(old_column, new_column)
|
106
|
+
if old_column.type != new_column.type
|
107
|
+
valid_new_types = old_column.type.compatible_types
|
108
|
+
unless valid_new_types.include?(new_column.type)
|
109
|
+
fail InvalidSchemaMigration,
|
110
|
+
"Can't change #{old_column.name} from " \
|
111
|
+
"#{old_column.type} to #{new_column.type}. " \
|
112
|
+
"#{old_column.type} columns may only be altered to " \
|
113
|
+
"#{valid_new_types.to_sentence}."
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def assert_same_column_structure!(old_column, new_column)
|
119
|
+
if old_column.class != new_column.class
|
120
|
+
fail InvalidSchemaMigration,
|
121
|
+
"Can't change #{old_column.name} from " \
|
122
|
+
"#{old_column.class.name.demodulize} to " \
|
123
|
+
"#{new_column.class.name.demodulize}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/cequel/schema/table.rb
CHANGED
@@ -1,19 +1,42 @@
|
|
1
1
|
require 'stringio'
|
2
2
|
|
3
3
|
module Cequel
|
4
|
-
|
5
4
|
module Schema
|
6
|
-
|
5
|
+
#
|
6
|
+
# An object representation of a CQL3 table schema.
|
7
|
+
#
|
8
|
+
# @see Keyspace#read_table
|
9
|
+
#
|
7
10
|
class Table
|
11
|
+
STORAGE_PROPERTIES = %w[
|
12
|
+
bloom_filter_fp_chance caching comment compaction compression
|
13
|
+
dclocal_read_repair_chance gc_grace_seconds read_repair_chance
|
14
|
+
replicate_on_write
|
15
|
+
]
|
8
16
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
# @return [Symbol] the name of the table
|
18
|
+
attr_reader :name
|
19
|
+
# @return [Array<Column>] all columns defined on the table
|
20
|
+
attr_reader :columns
|
21
|
+
# @return [Array<PartitionKey>] partition key columns defined on the
|
22
|
+
# table
|
23
|
+
attr_reader :partition_key_columns
|
24
|
+
# @return [Array<ClusteringColumn>] clustering columns defined on the
|
25
|
+
# table
|
26
|
+
attr_reader :clustering_columns
|
27
|
+
# @return [Array<DataColumn,CollectionColumn>] data columns and
|
28
|
+
# collection columns defined on the table
|
29
|
+
attr_reader :data_columns
|
30
|
+
# @return [Hash] storage properties defined on the table
|
31
|
+
attr_reader :properties
|
32
|
+
# @return [Boolean] `true` if this table is configured with compact
|
33
|
+
# storage
|
15
34
|
attr_writer :compact_storage
|
16
35
|
|
36
|
+
#
|
37
|
+
# @param name [Symbol] the name of the table
|
38
|
+
# @api private
|
39
|
+
#
|
17
40
|
def initialize(name)
|
18
41
|
@name = name
|
19
42
|
@partition_key_columns, @clustering_columns, @data_columns = [], [], []
|
@@ -21,11 +44,24 @@ module Cequel
|
|
21
44
|
@properties = ActiveSupport::HashWithIndifferentAccess.new
|
22
45
|
end
|
23
46
|
|
47
|
+
#
|
48
|
+
# Define a key column. If this is the first key column defined, it will
|
49
|
+
# be a partition key; otherwise, it will be a clustering column.
|
50
|
+
#
|
51
|
+
# @param name [Symbol] the name of the column
|
52
|
+
# @param type [Symbol,Type] the type for the column
|
53
|
+
# @param clustering_order [:asc,:desc] whether rows should be in
|
54
|
+
# ascending or descending order by this column. Only meaningful for
|
55
|
+
# clustering columns.
|
56
|
+
# @return [void]
|
57
|
+
#
|
58
|
+
# @see #add_partition_key
|
59
|
+
#
|
24
60
|
def add_key(name, type, clustering_order = nil)
|
25
61
|
if @partition_key_columns.empty?
|
26
62
|
unless clustering_order.nil?
|
27
|
-
|
28
|
-
|
63
|
+
fail ArgumentError,
|
64
|
+
"Can't set clustering order for partition key #{name}"
|
29
65
|
end
|
30
66
|
add_partition_key(name, type)
|
31
67
|
else
|
@@ -33,82 +69,212 @@ module Cequel
|
|
33
69
|
end
|
34
70
|
end
|
35
71
|
|
72
|
+
#
|
73
|
+
# Define a partition key for the table
|
74
|
+
#
|
75
|
+
# @param name [Symbol] the name of the column
|
76
|
+
# @param type [Symbol,Type] the type for the column
|
77
|
+
# @return [void]
|
78
|
+
#
|
36
79
|
def add_partition_key(name, type)
|
37
80
|
PartitionKey.new(name, type(type)).tap do |column|
|
38
81
|
@partition_key_columns << add_column(column)
|
39
82
|
end
|
40
83
|
end
|
41
84
|
|
85
|
+
#
|
86
|
+
# Define a clustering column for the table
|
87
|
+
#
|
88
|
+
# @param (see #add_key)
|
89
|
+
# @return [void]
|
90
|
+
#
|
42
91
|
def add_clustering_column(name, type, clustering_order = nil)
|
43
|
-
ClusteringColumn.new(name, type(type), clustering_order)
|
44
|
-
@clustering_columns << add_column(column)
|
45
|
-
end
|
92
|
+
ClusteringColumn.new(name, type(type), clustering_order)
|
93
|
+
.tap { |column| @clustering_columns << add_column(column) }
|
46
94
|
end
|
47
95
|
|
48
|
-
|
96
|
+
#
|
97
|
+
# Define a data column on the table
|
98
|
+
#
|
99
|
+
# @param name [Symbol] name of the column
|
100
|
+
# @param type [Type] type for the column
|
101
|
+
# @param options [Options] options for the column
|
102
|
+
# @option options [Boolean,Symbol] :index (nil) name of a secondary index
|
103
|
+
# to apply to the column, or `true` to infer an index name by
|
104
|
+
# convention
|
105
|
+
# @return [void]
|
106
|
+
#
|
107
|
+
def add_data_column(name, type, options = {})
|
108
|
+
options = {index: options} unless options.is_a?(Hash)
|
109
|
+
index_name = options[:index]
|
49
110
|
index_name = :"#{@name}_#{name}_idx" if index_name == true
|
50
|
-
DataColumn.new(name, type(type), index_name)
|
51
|
-
tap { |column| @data_columns << add_column(column) }
|
111
|
+
DataColumn.new(name, type(type), index_name)
|
112
|
+
.tap { |column| @data_columns << add_column(column) }
|
52
113
|
end
|
53
114
|
|
115
|
+
#
|
116
|
+
# Define a list column on the table
|
117
|
+
#
|
118
|
+
# @param name [Symbol] name of the list
|
119
|
+
# @param type [Symbol,Type] type of the list's elements
|
120
|
+
# @return [void]
|
121
|
+
#
|
122
|
+
# @see List
|
123
|
+
#
|
54
124
|
def add_list(name, type)
|
55
125
|
List.new(name, type(type)).tap do |column|
|
56
126
|
@data_columns << add_column(column)
|
57
127
|
end
|
58
128
|
end
|
59
129
|
|
130
|
+
#
|
131
|
+
# Define a set column on the table
|
132
|
+
#
|
133
|
+
# @param name [Symbol] name of the set
|
134
|
+
# @param type [Symbol,Type] type of the set's elements
|
135
|
+
# @return [void]
|
136
|
+
#
|
137
|
+
# @see Set
|
138
|
+
#
|
60
139
|
def add_set(name, type)
|
61
140
|
Set.new(name, type(type)).tap do |column|
|
62
141
|
@data_columns << add_column(column)
|
63
142
|
end
|
64
143
|
end
|
65
144
|
|
145
|
+
#
|
146
|
+
# Define a map column on the table
|
147
|
+
#
|
148
|
+
# @param name [Symbol] name of the set
|
149
|
+
# @param key_type [Symbol,Type] type of the map's keys
|
150
|
+
# @param value_type [Symbol,Type] type of the map's values
|
151
|
+
# @return [void]
|
152
|
+
#
|
153
|
+
# @see Map
|
154
|
+
#
|
66
155
|
def add_map(name, key_type, value_type)
|
67
156
|
Map.new(name, type(key_type), type(value_type)).tap do |column|
|
68
157
|
@data_columns << add_column(column)
|
69
158
|
end
|
70
159
|
end
|
71
160
|
|
161
|
+
#
|
162
|
+
# Define a storage property for the table
|
163
|
+
#
|
164
|
+
# @param name [Symbol] name of the property
|
165
|
+
# @param value value for the property
|
166
|
+
# @return [void]
|
167
|
+
#
|
168
|
+
# @see STORAGE_PROPERTIES List of storage property names
|
169
|
+
# @see TK list of CQL3 table storage properties
|
170
|
+
#
|
72
171
|
def add_property(name, value)
|
73
|
-
TableProperty.
|
172
|
+
TableProperty.build(name, value).tap do |property|
|
74
173
|
@properties[name] = property
|
75
174
|
end
|
76
175
|
end
|
77
176
|
|
177
|
+
#
|
178
|
+
# @param name [Symbol] name of column to look up
|
179
|
+
# @return [Column] column defined on table with given name
|
180
|
+
#
|
78
181
|
def column(name)
|
79
182
|
columns_by_name[name.to_sym]
|
80
183
|
end
|
81
184
|
|
185
|
+
#
|
186
|
+
# @return [Array<Column>] all key columns (partition + clustering)
|
187
|
+
#
|
82
188
|
def key_columns
|
83
189
|
@partition_key_columns + @clustering_columns
|
84
190
|
end
|
85
191
|
|
192
|
+
#
|
193
|
+
# @return [Array<Symbol>] names of all key columns (partition +
|
194
|
+
# clustering)
|
195
|
+
#
|
86
196
|
def key_column_names
|
87
197
|
key_columns.map { |key| key.name }
|
88
198
|
end
|
89
199
|
|
200
|
+
#
|
201
|
+
# @return [Integer] total number of key columns
|
202
|
+
#
|
203
|
+
def key_column_count
|
204
|
+
key_columns.length
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# @return [Array<Symbol>] names of partition key columns
|
209
|
+
#
|
210
|
+
def partition_key_column_names
|
211
|
+
partition_key_columns.map { |key| key.name }
|
212
|
+
end
|
213
|
+
|
214
|
+
#
|
215
|
+
# @return [Integer] number of partition key columns
|
216
|
+
#
|
217
|
+
def partition_key_column_count
|
218
|
+
partition_key_columns.length
|
219
|
+
end
|
220
|
+
|
221
|
+
#
|
222
|
+
# @return [Array<Symbol>] names of clustering columns
|
223
|
+
#
|
224
|
+
def clustering_column_names
|
225
|
+
clustering_columns.map { |key| key.name }
|
226
|
+
end
|
227
|
+
|
228
|
+
#
|
229
|
+
# @return [Integer] number of clustering columns
|
230
|
+
#
|
231
|
+
def clustering_column_count
|
232
|
+
clustering_columns.length
|
233
|
+
end
|
234
|
+
|
235
|
+
#
|
236
|
+
# @param name [Symbol] name of partition key column to look up
|
237
|
+
# @return [PartitionKey] partition key column with given name
|
238
|
+
#
|
90
239
|
def partition_key(name)
|
91
240
|
@partition_key_columns.find { |column| column.name == name }
|
92
241
|
end
|
93
242
|
|
243
|
+
#
|
244
|
+
# @param name [Symbol] name of clustering column to look up
|
245
|
+
# @return [ClusteringColumn] clustering column with given name
|
246
|
+
#
|
94
247
|
def clustering_column(name)
|
95
248
|
@clustering_columns.find { |column| column.name == name }
|
96
249
|
end
|
97
250
|
|
251
|
+
#
|
252
|
+
# @param name [Symbol] name of data column to look up
|
253
|
+
# @return [DataColumn,CollectionColumn] data column or collection column
|
254
|
+
# with given name
|
255
|
+
#
|
98
256
|
def data_column(name)
|
99
257
|
name = name.to_sym
|
100
258
|
@data_columns.find { |column| column.name == name }
|
101
259
|
end
|
102
260
|
|
261
|
+
#
|
262
|
+
# @param name [Symbol] name of property to look up
|
263
|
+
# @return [TableProperty] property as defined on table
|
264
|
+
#
|
103
265
|
def property(name)
|
104
266
|
@properties[name].try(:value)
|
105
267
|
end
|
106
268
|
|
269
|
+
#
|
270
|
+
# @return [Boolean] `true` if this table uses compact storage
|
271
|
+
#
|
107
272
|
def compact_storage?
|
108
273
|
!!@compact_storage
|
109
274
|
end
|
110
275
|
|
111
276
|
protected
|
277
|
+
|
112
278
|
attr_reader :columns_by_name
|
113
279
|
|
114
280
|
private
|
@@ -121,9 +287,6 @@ module Cequel
|
|
121
287
|
def type(type)
|
122
288
|
::Cequel::Type[type]
|
123
289
|
end
|
124
|
-
|
125
290
|
end
|
126
|
-
|
127
291
|
end
|
128
|
-
|
129
292
|
end
|