Airlock
view release on metacpan or search on metacpan
docs/superpowers/plans/2026-10-02-airlock-phase-1.md view on Meta::CPAN
=method find
my $row = $memory->find( hash => $hash );
my $row = $memory->find( user_code => 'BCDFGHJK' );
A copy of the matching row, or nothing.
=cut
sub update {
my ( $self, $hash, $from_state, $changes ) = @_;
$self->_same_process;
my $row = $self->_rows->{$hash} or return 0;
return 0 unless $row->{state} eq $from_state;
$row->{$_} = $changes->{$_} for keys %$changes;
return 1;
}
=method update
docs/superpowers/plans/2026-10-02-airlock-phase-1.md view on Meta::CPAN
my ( $self, $field, $value ) = @_;
croak __PACKAGE__.'->find by '.$field.' is not supported' unless $field eq 'hash' || $field eq 'user_code';
return unless defined $value;
return $self->_dbh->selectrow_hashref(
'SELECT '.join( ', ', $self->_fields ).' FROM '.$self->table.' WHERE '.$field.' = ?', undef, $value
);
}
# The WHERE on the old state is the whole point: of two concurrent redeems
# only one statement changes a row.
sub update {
my ( $self, $hash, $from_state, $changes ) = @_;
my %known = map { $_ => 1 } $self->_fields;
my @fields = sort keys %$changes;
croak __PACKAGE__.'->update unknown field' if grep { !$known{$_} } @fields;
my $changed = $self->_dbh->do(
'UPDATE '.$self->table.' SET '.join( ', ', map { $_.' = ?' } @fields ).' WHERE hash = ? AND state = ?',
undef, @{$changes}{@fields}, $hash, $from_state
);
return $changed > 0 ? 1 : 0;
}
docs/superpowers/plans/2026-10-02-airlock-phase-1.md view on Meta::CPAN
sub find {
my ( $self, $field, $value ) = @_;
croak __PACKAGE__.'->find by '.$field.' is not supported' unless $field eq 'hash' || $field eq 'user_code';
return unless defined $value;
my $row = $self->_rs->search( { $field => $value } )->single or return;
return { $row->get_columns };
}
# One UPDATE ... WHERE hash = ? AND state = ?. A resultset update returns the
# number of rows it changed, as '0E0' when there were none.
sub update {
my ( $self, $hash, $from_state, $changes ) = @_;
return $self->_rs->search( { hash => $hash, state => $from_state } )->update( { %$changes } ) > 0 ? 1 : 0;
}
sub purge {
my ( $self, $before ) = @_;
return $self->_rs->search( { expires => { '<' => $before } } )->delete + 0;
}
sub as_subs {
examples/lib/AirlockExample/StoreDBI.pm view on Meta::CPAN
my ( $self, $field, $value ) = @_;
croak __PACKAGE__.'->find by '.$field.' is not supported' unless $field eq 'hash' || $field eq 'user_code';
return unless defined $value;
return $self->_dbh->selectrow_hashref(
'SELECT '.join( ', ', $self->_fields ).' FROM '.$self->table.' WHERE '.$field.' = ?', undef, $value
);
}
# The WHERE on the old state is the whole point: of two concurrent redeems
# only one statement changes a row.
sub update {
my ( $self, $hash, $from_state, $changes ) = @_;
my %known = map { $_ => 1 } $self->_fields;
my @fields = sort keys %$changes;
croak __PACKAGE__.'->update unknown field' if grep { !$known{$_} } @fields;
# a reference to a number means "add it", done by the database in one statement
my @set = map { ref $changes->{$_} eq 'SCALAR' ? $_.' = '.$_.' + ?' : $_.' = ?' } @fields;
my $changed = $self->_dbh->do(
'UPDATE '.$self->table.' SET '.join( ', ', @set ).' WHERE hash = ? AND state = ?',
undef, ( map { ref eq 'SCALAR' ? $$_ : $_ } @{$changes}{@fields} ), $hash, $from_state
);
examples/lib/AirlockExample/StoreDBIO.pm view on Meta::CPAN
sub find {
my ( $self, $field, $value ) = @_;
croak __PACKAGE__.'->find by '.$field.' is not supported' unless $field eq 'hash' || $field eq 'user_code';
return unless defined $value;
my $row = $self->_rs->search( { $field => $value } )->single or return;
return { $row->get_columns };
}
# One UPDATE ... WHERE hash = ? AND state = ?. A resultset update returns the
# number of rows it changed, as '0E0' when there were none.
sub update {
my ( $self, $hash, $from_state, $changes ) = @_;
# a reference to a number means "add it", done by the database in one statement
my %set = map {
my $value = $changes->{$_};
$_ => ref $value eq 'SCALAR' ? \[ $_.' + ?', $$value ] : $value
} keys %$changes;
return $self->_rs->search( { hash => $hash, state => $from_state } )->update( \%set ) > 0 ? 1 : 0;
}
sub purge {
lib/Airlock/Store/Memory.pm view on Meta::CPAN
croak __PACKAGE__.'->find by '.$field.' is not supported'
unless $field eq 'hash' || $field eq 'user_code';
return unless defined $value;
for my $row ( values %{ $self->_rows } ) {
return { %$row } if defined $row->{$field} && $row->{$field} eq $value;
}
return;
}
sub update {
my ( $self, $hash, $from_state, $changes ) = @_;
$self->_same_process;
my $row = $self->_rows->{$hash} or return 0;
return 0 unless $row->{state} eq $from_state;
for my $field ( keys %$changes ) {
my $value = $changes->{$field};
$row->{$field} = ref $value eq 'SCALAR' ? ( $row->{$field} // 0 ) + $$value : $value;
}
return 1;
}
( run in 0.600 second using v1.01-cache-2.11-cpan-02e1dfdd527 )