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,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
- def partition_key(name, type)
17
- @table.add_partition_key(name, type)
18
- end
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
- def key(name, type, clustering_order = nil)
21
- @table.add_key(name, type, clustering_order)
22
- end
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
- def column(name, type, options = {})
25
- column = @table.add_data_column(name, type, options[:index])
26
- end
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
- def list(name, type)
29
- @table.add_list(name, type)
30
- end
52
+ #
53
+ # @!method list(name, type)
54
+ # (see Cequel::Schema::Table#add_list)
55
+ #
56
+ def_delegator :@table, :add_list, :list
31
57
 
32
- def set(name, type)
33
- @table.add_set(name, type)
34
- end
58
+ #
59
+ # @!method set(name, type)
60
+ # (see Cequel::Schema::Table#add_set)
61
+ #
62
+ def_delegator :@table, :add_set, :set
35
63
 
36
- def map(name, key_type, value_type)
37
- @table.add_map(
38
- name,
39
- key_type,
40
- value_type
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
- def with(name, value)
45
- @table.add_property(name, value)
46
- end
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
- options[:replication_factor] ||= 1 if options[:class] == 'SimpleStrategy'
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
@@ -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
- attr_reader :name,
10
- :columns,
11
- :partition_key_columns,
12
- :clustering_columns,
13
- :data_columns,
14
- :properties
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
- raise ArgumentError,
28
- "Can't set clustering order for partition key #{name}"
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).tap do |column|
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
- def add_data_column(name, type, index_name)
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.new(name, value).tap do |property|
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