persistence
Persistence adapters
ORM::Factory is ORM-agnostic at its core. The build strategies (build,
create, attributes-for, build-stubbed) target a small protocol ā
ORM::Factory::Persistence ā never a specific ORM directly.
The protocol
unit role ORM::Factory::Persistence;
method instantiate(Mu $class, %attrs) { ... }
method persist(Mu $instance) { ... }
method is-valid(Mu $instance --> Bool) { True }
method errors(Mu $instance) { Empty }
method primary-key(Mu $class --> Str) { 'id' }
method stub(Mu $instance) { $instance }instantiatebuilds an unsaved instance from a class and an attribute hash.buildcalls this and stops here.persistsaves the instance and returns it (raising if the ORM rejects it).createcallsinstantiatethenpersist.is-valid/errorsexpose validation state without committing.primary-keyis the name of the model's primary key column.stubreturns a frozen, no-DB-access stand-in.build-stubbedruns through this.
attributes-for deliberately bypasses the adapter entirely ā it returns a
plain attribute hash without ever instantiating, persisting, or stubbing.
The generic default
ORM::Factory::Persistence::Generic is the fallback adapter used when no
ORM-specific adapter is registered. It:
instantiates via
$class.new(|%attrs);persists by calling
.save-bangif present, else.save, else raisingX::ORM::Factory::Persistence::NoPersistencewith a clear hint;delegates
is-valid,errors,primary-keyto identically named methods on the instance / class if they exist, and falls back to sane defaults otherwise.
use ORM::Factory::Persistence::Generic;
my $adapter = ORM::Factory::Persistence::Generic.new;
my $user = $adapter.instantiate(User, %( fname => 'Greg' ));
$adapter.persist($user); # invokes $user.save-bang or $user.saveDetection and selection
On first access of ORM::Factory.persistence, the library:
checks for an explicit adapter set via
ORM::Factory.set-persistence;tries to
require ORM::Factory::Persistence::ActiveRecordā if it loads, uses that adapter (this is how theORM::ActiveRecordadapter auto-registers, with nousein your specs);falls back to
ORM::Factory::Persistence::Generic.
Once resolved, the adapter is cached for the rest of the process. Use
ORM::Factory.reset-persistence in tests to force re-detection.
# default ā auto-detected on first call
my $adapter = ORM::Factory.persistence;
# explicit, e.g. installing a custom adapter
ORM::Factory.set-persistence(MyAdapter.new);
# reset for the next test
ORM::Factory.reset-persistence;Writing a custom adapter
Implement the ORM::Factory::Persistence role and call set-persistence:
use ORM::Factory::Persistence;
class MyOrmAdapter does ORM::Factory::Persistence {
method instantiate(Mu $class, %attrs) { $class.from-hash(%attrs) }
method persist(Mu $instance) { $instance.commit; $instance }
method is-valid(Mu $instance) { $instance.validate-ok }
method errors(Mu $instance) { $instance.validation-errors }
method primary-key(Mu $class) { $class.pk-name }
method stub(Mu $instance) { $instance.frozen-stub }
}
ORM::Factory.set-persistence(MyOrmAdapter.new);Per-factory and global to-create / initialize-with / skip-create hooks
sit on top of this seam: they intercept before the adapter is consulted, and
fall through to the adapter when not present. See
Construction for the full hook protocol and resolution
order.
For the bundled ORM::ActiveRecord adapter, see
ORM::ActiveRecord adapter.