diff --git a/ext/couchbase b/ext/couchbase index 8ceabca8..3a42a611 160000 --- a/ext/couchbase +++ b/ext/couchbase @@ -1 +1 @@ -Subproject commit 8ceabca85f93a16f829dec4be67a7e668f31a2a2 +Subproject commit 3a42a6117a38450d10eeebee2022c0367f03d687 diff --git a/ext/couchbase.cxx b/ext/couchbase.cxx index 61d32f78..08dcb986 100644 --- a/ext/couchbase.cxx +++ b/ext/couchbase.cxx @@ -5461,7 +5461,7 @@ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE options) VALUE collection = rb_hash_new(); rb_hash_aset(collection, rb_id2sym(rb_intern("uid")), ULL2NUM(c.uid)); rb_hash_aset(collection, rb_id2sym(rb_intern("name")), cb_str_new(c.name)); - rb_hash_aset(collection, rb_id2sym(rb_intern("max_expiry")), ULONG2NUM(c.max_expiry)); + rb_hash_aset(collection, rb_id2sym(rb_intern("max_expiry")), LONG2NUM(c.max_expiry)); if (c.history.has_value()) { rb_hash_aset(collection, rb_id2sym(rb_intern("history")), c.history.value() ? Qtrue : Qfalse); } @@ -5618,7 +5618,12 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA if (!NIL_P(settings)) { if (VALUE max_expiry = rb_hash_aref(settings, rb_id2sym(rb_intern("max_expiry"))); !NIL_P(max_expiry)) { if (TYPE(max_expiry) == T_FIXNUM) { - req.max_expiry = FIX2UINT(max_expiry); + req.max_expiry = FIX2INT(max_expiry); + if (req.max_expiry < -1) { + throw ruby_exception( + eInvalidArgument, + rb_sprintf("collection max expiry must be greater than or equal to -1, given %+" PRIsVALUE, max_expiry)); + } } else { throw ruby_exception(rb_eArgError, rb_sprintf("collection max expiry must be an Integer, given %+" PRIsVALUE, max_expiry)); @@ -5674,7 +5679,12 @@ cb_Backend_collection_update(VALUE self, VALUE bucket_name, VALUE scope_name, VA if (!NIL_P(settings)) { if (VALUE max_expiry = rb_hash_aref(settings, rb_id2sym(rb_intern("max_expiry"))); !NIL_P(max_expiry)) { if (TYPE(max_expiry) == T_FIXNUM) { - req.max_expiry = FIX2UINT(max_expiry); + req.max_expiry = FIX2INT(max_expiry); + if (req.max_expiry < -1) { + throw ruby_exception( + eInvalidArgument, + rb_sprintf("collection max expiry must be greater than or equal to -1, given %+" PRIsVALUE, max_expiry)); + } } else { throw ruby_exception(rb_eArgError, rb_sprintf("collection max expiry must be an Integer, given %+" PRIsVALUE, max_expiry)); diff --git a/lib/couchbase/management/collection_manager.rb b/lib/couchbase/management/collection_manager.rb index dd2ab7ae..d970453e 100644 --- a/lib/couchbase/management/collection_manager.rb +++ b/lib/couchbase/management/collection_manager.rb @@ -383,7 +383,7 @@ def initialize class CreateCollectionSettings # @return [Integer, nil] time in seconds of the maximum expiration time for new documents in the collection - # (set to +nil+ to disable it) + # (set to +nil+ to use the bucket-level setting, and to +-1+ set it to no-expiry) attr_accessor :max_expiry # @return [Boolean, nil] whether history retention override should be enabled in the collection (set to +nil+ to @@ -410,11 +410,11 @@ def to_backend class UpdateCollectionSettings # @return [Integer, nil] time in seconds of the maximum expiration time for new documents in the collection - # (set to +nil+ to disable it) + # (set to +nil+ to not update it, and to +-1+ set it to no-expiry) attr_accessor :max_expiry # @return [Boolean, nil] whether history retention override should be enabled in the collection (set to +nil+ to - # default to the bucket-level setting) + # not update it) attr_accessor :history def initialize(max_expiry: nil, history: nil) diff --git a/test/collection_manager_test.rb b/test/collection_manager_test.rb index e5b173f9..9a81f70b 100644 --- a/test/collection_manager_test.rb +++ b/test/collection_manager_test.rb @@ -208,6 +208,7 @@ def test_drop_collection_scope_does_not_exist end def test_create_collection_history_retention + skip("#{name}: CAVES does not support history retention") if use_caves? skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention? skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support history retention") if env.protostellar? @@ -229,6 +230,7 @@ def test_create_collection_history_retention end def test_update_collection_history_retention + skip("#{name}: CAVES does not support update_collection & history retention") if use_caves? skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention? skip("#{name}: Server does not support update_collection") unless env.server_version.supports_update_collection? @@ -259,6 +261,7 @@ def test_update_collection_history_retention end def test_create_collection_history_retention_unsupported + skip("#{name}: CAVES does not support history retention") if use_caves? skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support history retention") if env.protostellar? skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention? @@ -276,6 +279,7 @@ def test_create_collection_history_retention_unsupported end def test_update_collection_history_retention_unsupported + skip("#{name}: CAVES does not support update_collection & history retention") if use_caves? skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention? skip("#{name}: Server does not support update_collection") unless env.server_version.supports_update_collection? @@ -335,7 +339,63 @@ def test_create_collection_max_expiry end end + def test_create_collection_max_expiry_no_expiry + skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support setting max_expiry to -1 yet") if env.protostellar? + unless env.server_version.supports_collection_max_expiry_set_to_no_expiry? + skip("#{name}: The server does not support setting max_expiry to -1") + end + + scope_name = get_scope_name + collection_name = 'testcoll' + @collection_manager.create_scope(scope_name) + scope = get_scope(scope_name) + + assert scope + + settings = Management::CreateCollectionSettings.new(max_expiry: -1) + + @collection_manager.create_collection(scope_name, collection_name, settings) + + coll_spec = get_collection(scope_name, collection_name) + + assert coll_spec + assert_equal(-1, coll_spec.max_expiry) + end + + def test_create_collection_max_expiry_no_expiry_not_supported + skip("#{name}: The server supports setting max_expiry to -1") if env.server_version.supports_collection_max_expiry_set_to_no_expiry? + skip("#{name}: CAVES allows to -1") if use_caves? + + scope_name = get_scope_name + collection_name = 'testcoll' + @collection_manager.create_scope(scope_name) + scope = get_scope(scope_name) + + assert scope + + settings = Management::CreateCollectionSettings.new(max_expiry: -1) + + assert_raises(Error::InvalidArgument) do + @collection_manager.create_collection(scope_name, collection_name, settings) + end + end + + def test_create_collection_max_expiry_invalid + scope_name = get_scope_name + collection_name = 'testcoll' + @collection_manager.create_scope(scope_name) + scope = get_scope(scope_name) + + assert scope + + settings = Management::CreateCollectionSettings.new(max_expiry: -10) + assert_raises(Error::InvalidArgument) do + @collection_manager.create_collection(scope_name, collection_name, settings) + end + end + def test_update_collection_max_expiry + skip("#{name}: CAVES does not support update_collection") if use_caves? skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? unless env.server_version.supports_update_collection_max_expiry? skip("#{name}: Server does not support update_collection with max_expiry") @@ -381,7 +441,92 @@ def test_update_collection_max_expiry end end + def test_update_collection_max_expiry_no_expiry + skip("#{name}: CAVES does not support update_collection") if use_caves? + skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? + unless env.server_version.supports_collection_max_expiry_set_to_no_expiry? + skip("#{name}: The server does not support setting max_expiry to -1") + end + + scope_name = get_scope_name + collection_name = 'testcoll' + @collection_manager.create_scope(scope_name) + scope = get_scope(scope_name) + + assert scope + + settings = Management::CreateCollectionSettings.new(max_expiry: 600) + @collection_manager.create_collection(scope_name, collection_name, settings) + + coll_spec = get_collection(scope_name, collection_name) + + assert coll_spec + assert_equal 600, coll_spec.max_expiry + + settings = Management::UpdateCollectionSettings.new(max_expiry: -1) + + @collection_manager.update_collection(scope_name, collection_name, settings) + + coll_spec = get_collection(scope_name, collection_name) + + assert coll_spec + assert_equal(-1, coll_spec.max_expiry) + end + + def test_update_collection_max_expiry_no_expiry_not_supported + skip("#{name}: CAVES does not support update_collection") if use_caves? + skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? + skip("#{name}: The server supports setting max_expiry to -1") if env.server_version.supports_collection_max_expiry_set_to_no_expiry? + + scope_name = get_scope_name + collection_name = 'testcoll' + @collection_manager.create_scope(scope_name) + scope = get_scope(scope_name) + + assert scope + + settings = Management::CreateCollectionSettings.new(max_expiry: 600) + @collection_manager.create_collection(scope_name, collection_name, settings) + + coll_spec = get_collection(scope_name, collection_name) + + assert coll_spec + assert_equal 600, coll_spec.max_expiry + + settings = Management::UpdateCollectionSettings.new(max_expiry: -1) + + assert_raises(Error::InvalidArgument) do + @collection_manager.update_collection(scope_name, collection_name, settings) + end + end + + def test_update_collection_max_expiry_invalid + skip("#{name}: CAVES does not support update_collection") if use_caves? + skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? + + scope_name = get_scope_name + collection_name = 'testcoll' + @collection_manager.create_scope(scope_name) + scope = get_scope(scope_name) + + assert scope + + settings = Management::CreateCollectionSettings.new(max_expiry: 600) + @collection_manager.create_collection(scope_name, collection_name, settings) + + coll_spec = get_collection(scope_name, collection_name) + + assert coll_spec + assert_equal 600, coll_spec.max_expiry + + settings = Management::UpdateCollectionSettings.new(max_expiry: -10) + assert_raises(Error::InvalidArgument) do + @collection_manager.update_collection(scope_name, collection_name, settings) + end + end + def test_update_collection_does_not_exist + skip("#{name}: CAVES does not support update_collection") if use_caves? skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? unless env.server_version.supports_update_collection_max_expiry? skip("#{name}: Server does not support update_collection with max_expiry") @@ -401,6 +546,7 @@ def test_update_collection_does_not_exist end def test_update_collection_scope_does_not_exist + skip("#{name}: CAVES does not support update_collection") if use_caves? skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar? unless env.server_version.supports_update_collection_max_expiry? skip("#{name}: Server does not support update_collection with max_expiry") diff --git a/test/test_helper.rb b/test/test_helper.rb index b01683b0..b102473f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -110,6 +110,10 @@ def supports_update_collection? def supports_update_collection_max_expiry? @version >= Gem::Version.create("7.5.0") end + + def supports_collection_max_expiry_set_to_no_expiry? + @version >= Gem::Version.create("7.6.0") + end end require "couchbase"