+##############################################################################
+
+=method add_group
+
+ $kdbx->add_group($group, %options);
+ $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->find_groups({uuid => $parent}) 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 all_groups
+
+ \@groups = $kdbx->all_groups(%options);
+ \@groups = $kdbx->all_groups($base_group, %options);
+
+Get all groups deeply in a database, or all groups within a specified base group, in a flat array. Supported
+options:
+
+=for :list
+* C<base> - Only include groups within a base group (same as C<$base_group>) (default: root)
+* C<include_base> - Include the base group in the results (default: true)
+
+=cut
+
+sub all_groups {
+ my $self = shift;
+ my %args = @_ % 2 == 0 ? @_ : (base => shift, @_);
+ my $base = $args{base} // $self->root;
+
+ my @groups = $args{include_base} // 1 ? $self->_wrap_group($base) : ();
+
+ for my $subgroup (@{$base->{groups} || []}) {
+ my $more = $self->all_groups($subgroup);
+ push @groups, @$more;
+ }
+
+ return \@groups;
+}
+