Skip to content

Commit 60bb4e9

Browse files
committed
RCBC-468: Support for maxTTL value of -1 for collection 'no expiry'
1 parent 49e7f50 commit 60bb4e9

File tree

5 files changed

+167
-7
lines changed

5 files changed

+167
-7
lines changed

ext/couchbase

ext/couchbase.cxx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5461,7 +5461,7 @@ cb_Backend_scope_get_all(VALUE self, VALUE bucket_name, VALUE options)
54615461
VALUE collection = rb_hash_new();
54625462
rb_hash_aset(collection, rb_id2sym(rb_intern("uid")), ULL2NUM(c.uid));
54635463
rb_hash_aset(collection, rb_id2sym(rb_intern("name")), cb_str_new(c.name));
5464-
rb_hash_aset(collection, rb_id2sym(rb_intern("max_expiry")), ULONG2NUM(c.max_expiry));
5464+
rb_hash_aset(collection, rb_id2sym(rb_intern("max_expiry")), LONG2NUM(c.max_expiry));
54655465
if (c.history.has_value()) {
54665466
rb_hash_aset(collection, rb_id2sym(rb_intern("history")), c.history.value() ? Qtrue : Qfalse);
54675467
}
@@ -5618,7 +5618,12 @@ cb_Backend_collection_create(VALUE self, VALUE bucket_name, VALUE scope_name, VA
56185618
if (!NIL_P(settings)) {
56195619
if (VALUE max_expiry = rb_hash_aref(settings, rb_id2sym(rb_intern("max_expiry"))); !NIL_P(max_expiry)) {
56205620
if (TYPE(max_expiry) == T_FIXNUM) {
5621-
req.max_expiry = FIX2UINT(max_expiry);
5621+
req.max_expiry = FIX2INT(max_expiry);
5622+
if (req.max_expiry < -1) {
5623+
throw ruby_exception(
5624+
eInvalidArgument,
5625+
rb_sprintf("collection max expiry must be greater than or equal to -1, given %+" PRIsVALUE, max_expiry));
5626+
}
56225627
} else {
56235628
throw ruby_exception(rb_eArgError,
56245629
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
56745679
if (!NIL_P(settings)) {
56755680
if (VALUE max_expiry = rb_hash_aref(settings, rb_id2sym(rb_intern("max_expiry"))); !NIL_P(max_expiry)) {
56765681
if (TYPE(max_expiry) == T_FIXNUM) {
5677-
req.max_expiry = FIX2UINT(max_expiry);
5682+
req.max_expiry = FIX2INT(max_expiry);
5683+
if (req.max_expiry < -1) {
5684+
throw ruby_exception(
5685+
eInvalidArgument,
5686+
rb_sprintf("collection max expiry must be greater than or equal to -1, given %+" PRIsVALUE, max_expiry));
5687+
}
56785688
} else {
56795689
throw ruby_exception(rb_eArgError,
56805690
rb_sprintf("collection max expiry must be an Integer, given %+" PRIsVALUE, max_expiry));

lib/couchbase/management/collection_manager.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ def initialize
383383

384384
class CreateCollectionSettings
385385
# @return [Integer, nil] time in seconds of the maximum expiration time for new documents in the collection
386-
# (set to +nil+ to disable it)
386+
# (set to +nil+ to use the bucket-level setting, and to +-1+ set it to no-expiry)
387387
attr_accessor :max_expiry
388388

389389
# @return [Boolean, nil] whether history retention override should be enabled in the collection (set to +nil+ to
@@ -410,11 +410,11 @@ def to_backend
410410

411411
class UpdateCollectionSettings
412412
# @return [Integer, nil] time in seconds of the maximum expiration time for new documents in the collection
413-
# (set to +nil+ to disable it)
413+
# (set to +nil+ to not update it, and to +-1+ set it to no-expiry)
414414
attr_accessor :max_expiry
415415

416416
# @return [Boolean, nil] whether history retention override should be enabled in the collection (set to +nil+ to
417-
# default to the bucket-level setting)
417+
# not update it)
418418
attr_accessor :history
419419

420420
def initialize(max_expiry: nil, history: nil)

test/collection_manager_test.rb

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ def test_drop_collection_scope_does_not_exist
208208
end
209209

210210
def test_create_collection_history_retention
211+
skip("#{name}: CAVES does not support history retention") if use_caves?
211212
skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention?
212213
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support history retention") if env.protostellar?
213214

@@ -229,6 +230,7 @@ def test_create_collection_history_retention
229230
end
230231

231232
def test_update_collection_history_retention
233+
skip("#{name}: CAVES does not support update_collection & history retention") if use_caves?
232234
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
233235
skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention?
234236
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
259261
end
260262

261263
def test_create_collection_history_retention_unsupported
264+
skip("#{name}: CAVES does not support history retention") if use_caves?
262265
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support history retention") if env.protostellar?
263266
skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention?
264267

@@ -276,6 +279,7 @@ def test_create_collection_history_retention_unsupported
276279
end
277280

278281
def test_update_collection_history_retention_unsupported
282+
skip("#{name}: CAVES does not support update_collection & history retention") if use_caves?
279283
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
280284
skip("#{name}: Server does not support history retention") unless env.server_version.supports_history_retention?
281285
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
335339
end
336340
end
337341

342+
def test_create_collection_max_expiry_no_expiry
343+
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support setting max_expiry to -1 yet") if env.protostellar?
344+
unless env.server_version.supports_collection_max_expiry_set_to_no_expiry?
345+
skip("#{name}: The server does not support setting max_expiry to -1")
346+
end
347+
348+
scope_name = get_scope_name
349+
collection_name = 'testcoll'
350+
@collection_manager.create_scope(scope_name)
351+
scope = get_scope(scope_name)
352+
353+
assert scope
354+
355+
settings = Management::CreateCollectionSettings.new(max_expiry: -1)
356+
357+
@collection_manager.create_collection(scope_name, collection_name, settings)
358+
359+
coll_spec = get_collection(scope_name, collection_name)
360+
361+
assert coll_spec
362+
assert_equal(-1, coll_spec.max_expiry)
363+
end
364+
365+
def test_create_collection_max_expiry_no_expiry_not_supported
366+
skip("#{name}: The server supports setting max_expiry to -1") if env.server_version.supports_collection_max_expiry_set_to_no_expiry?
367+
skip("#{name}: CAVES allows to -1") if use_caves?
368+
369+
scope_name = get_scope_name
370+
collection_name = 'testcoll'
371+
@collection_manager.create_scope(scope_name)
372+
scope = get_scope(scope_name)
373+
374+
assert scope
375+
376+
settings = Management::CreateCollectionSettings.new(max_expiry: -1)
377+
378+
assert_raises(Error::InvalidArgument) do
379+
@collection_manager.create_collection(scope_name, collection_name, settings)
380+
end
381+
end
382+
383+
def test_create_collection_max_expiry_invalid
384+
scope_name = get_scope_name
385+
collection_name = 'testcoll'
386+
@collection_manager.create_scope(scope_name)
387+
scope = get_scope(scope_name)
388+
389+
assert scope
390+
391+
settings = Management::CreateCollectionSettings.new(max_expiry: -10)
392+
assert_raises(Error::InvalidArgument) do
393+
@collection_manager.create_collection(scope_name, collection_name, settings)
394+
end
395+
end
396+
338397
def test_update_collection_max_expiry
398+
skip("#{name}: CAVES does not support update_collection") if use_caves?
339399
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
340400
unless env.server_version.supports_update_collection_max_expiry?
341401
skip("#{name}: Server does not support update_collection with max_expiry")
@@ -381,7 +441,92 @@ def test_update_collection_max_expiry
381441
end
382442
end
383443

444+
def test_update_collection_max_expiry_no_expiry
445+
skip("#{name}: CAVES does not support update_collection") if use_caves?
446+
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
447+
unless env.server_version.supports_collection_max_expiry_set_to_no_expiry?
448+
skip("#{name}: The server does not support setting max_expiry to -1")
449+
end
450+
451+
scope_name = get_scope_name
452+
collection_name = 'testcoll'
453+
@collection_manager.create_scope(scope_name)
454+
scope = get_scope(scope_name)
455+
456+
assert scope
457+
458+
settings = Management::CreateCollectionSettings.new(max_expiry: 600)
459+
@collection_manager.create_collection(scope_name, collection_name, settings)
460+
461+
coll_spec = get_collection(scope_name, collection_name)
462+
463+
assert coll_spec
464+
assert_equal 600, coll_spec.max_expiry
465+
466+
settings = Management::UpdateCollectionSettings.new(max_expiry: -1)
467+
468+
@collection_manager.update_collection(scope_name, collection_name, settings)
469+
470+
coll_spec = get_collection(scope_name, collection_name)
471+
472+
assert coll_spec
473+
assert_equal(-1, coll_spec.max_expiry)
474+
end
475+
476+
def test_update_collection_max_expiry_no_expiry_not_supported
477+
skip("#{name}: CAVES does not support update_collection") if use_caves?
478+
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
479+
skip("#{name}: The server supports setting max_expiry to -1") if env.server_version.supports_collection_max_expiry_set_to_no_expiry?
480+
481+
scope_name = get_scope_name
482+
collection_name = 'testcoll'
483+
@collection_manager.create_scope(scope_name)
484+
scope = get_scope(scope_name)
485+
486+
assert scope
487+
488+
settings = Management::CreateCollectionSettings.new(max_expiry: 600)
489+
@collection_manager.create_collection(scope_name, collection_name, settings)
490+
491+
coll_spec = get_collection(scope_name, collection_name)
492+
493+
assert coll_spec
494+
assert_equal 600, coll_spec.max_expiry
495+
496+
settings = Management::UpdateCollectionSettings.new(max_expiry: -1)
497+
498+
assert_raises(Error::InvalidArgument) do
499+
@collection_manager.update_collection(scope_name, collection_name, settings)
500+
end
501+
end
502+
503+
def test_update_collection_max_expiry_invalid
504+
skip("#{name}: CAVES does not support update_collection") if use_caves?
505+
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
506+
507+
scope_name = get_scope_name
508+
collection_name = 'testcoll'
509+
@collection_manager.create_scope(scope_name)
510+
scope = get_scope(scope_name)
511+
512+
assert scope
513+
514+
settings = Management::CreateCollectionSettings.new(max_expiry: 600)
515+
@collection_manager.create_collection(scope_name, collection_name, settings)
516+
517+
coll_spec = get_collection(scope_name, collection_name)
518+
519+
assert coll_spec
520+
assert_equal 600, coll_spec.max_expiry
521+
522+
settings = Management::UpdateCollectionSettings.new(max_expiry: -10)
523+
assert_raises(Error::InvalidArgument) do
524+
@collection_manager.update_collection(scope_name, collection_name, settings)
525+
end
526+
end
527+
384528
def test_update_collection_does_not_exist
529+
skip("#{name}: CAVES does not support update_collection") if use_caves?
385530
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
386531
unless env.server_version.supports_update_collection_max_expiry?
387532
skip("#{name}: Server does not support update_collection with max_expiry")
@@ -401,6 +546,7 @@ def test_update_collection_does_not_exist
401546
end
402547

403548
def test_update_collection_scope_does_not_exist
549+
skip("#{name}: CAVES does not support update_collection") if use_caves?
404550
skip("#{name}: The #{Couchbase::Protostellar::NAME} protocol does not support update_collection") if env.protostellar?
405551
unless env.server_version.supports_update_collection_max_expiry?
406552
skip("#{name}: Server does not support update_collection with max_expiry")

test/test_helper.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ def supports_update_collection?
110110
def supports_update_collection_max_expiry?
111111
@version >= Gem::Version.create("7.5.0")
112112
end
113+
114+
def supports_collection_max_expiry_set_to_no_expiry?
115+
@version >= Gem::Version.create("7.6.0")
116+
end
113117
end
114118

115119
require "couchbase"

0 commit comments

Comments
 (0)