+ if (my $group = shift) {
+ $self->last_selected_group($group->uuid);
+ return $group;
+ }
+ my $uuid = $self->last_selected_group;
+ return if $uuid eq UUID_NULL;
+ return $self->groups->grep(uuid => $uuid)->next;
+}
+
+=method last_top_visible
+
+ $group = $kdbx->last_top_visible;
+ $kdbx->last_top_visible($group);
+
+Get or set the last top visible group. May return C<undef> if unset.
+
+=cut
+
+sub last_top_visible {
+ my $self = shift;
+ if (my $group = shift) {
+ $self->last_top_visible_group($group->uuid);
+ return $group;
+ }
+ my $uuid = $self->last_top_visible_group;
+ return if $uuid eq UUID_NULL;
+ return $self->groups->grep(uuid => $uuid)->next;
+}
+
+##############################################################################
+
+=method add_group
+
+ $kdbx->add_group($group);
+ $kdbx->add_group(%group_attributes, %options);
+
+Add a group to a database. This is equivalent to identifying a parent group and calling
+L<File::KDBX::Group/add_group> on the parent group, forwarding the arguments. Available options:
+
+=for :list
+* C<group> (aka C<parent>) - Group object or group UUID to add the group to (default: root group)
+
+=cut
+
+sub add_group {
+ my $self = shift;
+ my $group = @_ % 2 == 1 ? shift : undef;
+ my %args = @_;
+
+ # find the right group to add the group to
+ my $parent = delete $args{group} // delete $args{parent} // $self->root;
+ $parent = $self->groups->grep({uuid => $parent})->next if !ref $parent;
+ $parent or throw 'Invalid group';
+
+ return $parent->add_group(defined $group ? $group : (), %args, kdbx => $self);
+}
+
+sub _wrap_group {
+ my $self = shift;
+ my $group = shift;
+ require File::KDBX::Group;
+ return File::KDBX::Group->wrap($group, $self);
+}
+
+=method groups
+
+ \&iterator = $kdbx->groups(%options);
+ \&iterator = $kdbx->groups($base_group, %options);
+
+Get an iterator over I<groups> within a database. Options:
+
+=for :list
+* C<base> - Only include groups within a base group (same as C<$base_group>) (default: L</root>)
+* C<inclusive> - Include the base group in the results (default: true)
+* C<algorithm> - Search algorithm, one of C<ids>, C<bfs> or C<dfs> (default: C<ids>)
+
+=cut
+
+sub groups {
+ my $self = shift;
+ my %args = @_ % 2 == 0 ? @_ : (base => shift, @_);
+ my $base = delete $args{base} // $self->root;
+
+ return $base->groups_deeply(%args);