+# {{{ sub LimitAttribute
+
+=head2 LimitAttribute PARAMHASH
+
+Takes NAME, OPERATOR and VALUE to find records that has the
+matching Attribute.
+
+If EMPTY is set, also select rows with an empty string as
+Attribute's Content.
+
+If NULL is set, also select rows without the named Attribute.
+
+=cut
+
+my %Negate = qw(
+ = !=
+ != =
+ > <=
+ < >=
+ >= <
+ <= >
+ LIKE NOT LIKE
+ NOT LIKE LIKE
+ IS IS NOT
+ IS NOT IS
+);
+
+sub LimitAttribute {
+ my ($self, %args) = @_;
+ my $clause = 'ALIAS';
+ my $operator = ($args{OPERATOR} || '=');
+
+ if ($args{NULL} and exists $args{VALUE}) {
+ $clause = 'LEFTJOIN';
+ $operator = $Negate{$operator};
+ }
+ elsif ($args{NEGATE}) {
+ $operator = $Negate{$operator};
+ }
+
+ my $alias = $self->Join(
+ TYPE => 'left',
+ ALIAS1 => $args{ALIAS} || 'main',
+ FIELD1 => 'id',
+ TABLE2 => 'Attributes',
+ FIELD2 => 'ObjectId'
+ );
+
+ my $type = ref($self);
+ $type =~ s/(?:s|Collection)$//; # XXX - Hack!
+
+ $self->Limit(
+ $clause => $alias,
+ FIELD => 'ObjectType',
+ OPERATOR => '=',
+ VALUE => $type,
+ );
+ $self->Limit(
+ $clause => $alias,
+ FIELD => 'Name',
+ OPERATOR => '=',
+ VALUE => $args{NAME},
+ ) if exists $args{NAME};
+
+ return unless exists $args{VALUE};
+
+ $self->Limit(
+ $clause => $alias,
+ FIELD => 'Content',
+ OPERATOR => $operator,
+ VALUE => $args{VALUE},
+ );
+
+ # Capture rows with the attribute defined as an empty string.
+ $self->Limit(
+ $clause => $alias,
+ FIELD => 'Content',
+ OPERATOR => '=',
+ VALUE => '',
+ ENTRYAGGREGATOR => $args{NULL} ? 'AND' : 'OR',
+ ) if $args{EMPTY};
+
+ # Capture rows without the attribute defined
+ $self->Limit(
+ %args,
+ ALIAS => $alias,
+ FIELD => 'id',
+ OPERATOR => ($args{NEGATE} ? 'IS NOT' : 'IS'),
+ VALUE => 'NULL',
+ ) if $args{NULL};
+}
+# }}}
+
+# {{{ sub LimitCustomField
+
+=head2 LimitCustomField
+
+Takes a paramhash of key/value pairs with the following keys:
+
+=over 4
+
+=item CUSTOMFIELD - CustomField id. Optional
+
+=item OPERATOR - The usual Limit operators
+
+=item VALUE - The value to compare against
+
+=back
+
+=cut
+
+sub _SingularClass {
+ my $self = shift;
+ my $class = ref($self);
+ $class =~ s/s$// or die "Cannot deduce SingularClass for $class";
+ return $class;
+}
+
+sub LimitCustomField {
+ my $self = shift;
+ my %args = ( VALUE => undef,
+ CUSTOMFIELD => undef,
+ OPERATOR => '=',
+ @_ );
+
+ my $alias = $self->Join(
+ TYPE => 'left',
+ ALIAS1 => 'main',
+ FIELD1 => 'id',
+ TABLE2 => 'ObjectCustomFieldValues',
+ FIELD2 => 'ObjectId'
+ );
+ $self->Limit(
+ ALIAS => $alias,
+ FIELD => 'CustomField',
+ OPERATOR => '=',
+ VALUE => $args{'CUSTOMFIELD'},
+ ) if ($args{'CUSTOMFIELD'});
+ $self->Limit(
+ ALIAS => $alias,
+ FIELD => 'ObjectType',
+ OPERATOR => '=',
+ VALUE => $self->_SingularClass,
+ );
+ $self->Limit(
+ ALIAS => $alias,
+ FIELD => 'Content',
+ OPERATOR => $args{'OPERATOR'},
+ VALUE => $args{'VALUE'},
+ );
+}
+