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.
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