Skip to content

Custom strategies

ORM::Factory ships with four built-in strategies (build, create, attributes-for, build-stubbed). You can register your own at runtime — or replace a built-in — to integrate serialisation, alternative persistence flows, or any other build pipeline.

Registering a strategy

A strategy is any class that does the ORM::Factory::Strategy role:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
use ORM::Factory;

class JsonStrategy does ORM::Factory::Strategy {
  method to-sym(--> Str) { 'json' }

  method result(ORM::Factory::Evaluator $eval) {
    my %h = $eval.attributes-hash(:skip-associations);
    to-json(%h);
  }

  method association(Str:D $name, @variants, %overrides) {
    ORM::Factory.build($name, |@variants, |%overrides);
  }
}

ORM::Factory.register-strategy('json', JsonStrategy);

Once registered, the strategy is dispatched by name via FALLBACK, so the top-level helper is simply the name itself:

1
2
ORM::Factory.json('user');                     # → JSON for the user factory
ORM::Factory.json('user', 'admin', :name<Pat>); # variants + overrides flow through

Inspecting the registry

1
2
3
ORM::Factory.strategies.keys;       # registered names
ORM::Factory.strategy-class-for('json');  # the class
ORM::Factory.strategy-for('json');        # a fresh, persistence-wired instance

Re-registering a built-in

register-strategy accepts any built-in name, so a project can swap the default build behaviour without monkey-patching:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class ShoutBuildStrategy does ORM::Factory::Strategy {
  method to-sym(--> Str) { 'build' }
  method result(ORM::Factory::Evaluator $eval) {
    my $instance = $!persistence.instantiate($eval.factory.lookup-class, $eval.attributes-hash);
    $instance.name = $instance.name.uc if $instance.^can('name');
    $instance;
  }
  method association(Str:D $name, @variants, %overrides) {
    ORM::Factory.build($name, |@variants, |%overrides);
  }
}

ORM::Factory.register-strategy('build', ShoutBuildStrategy);
ORM::Factory.build('user').name;  # → uppercased

# Restore the default
ORM::Factory.register-strategy('build', ORM::Factory::BuildStrategy);

Per-strategy association cascade

association is the cascade hook. A strategy controls how every implicit or explicit association of the in-flight factory is built. For example, a strategy that always stubs associations regardless of the top-level call:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class StubAssocStrategy does ORM::Factory::Strategy {
  method to-sym(--> Str) { 'cascade-stub' }
  method result(ORM::Factory::Evaluator $eval) {
    $!persistence.instantiate($eval.factory.lookup-class, $eval.attributes-hash);
  }
  method association(Str:D $name, @variants, %overrides) {
    ORM::Factory.build-stubbed($name, |@variants, |%overrides);
  }
}

ORM::Factory.register-strategy('cascade-stub', StubAssocStrategy);
ORM::Factory.cascade-stub('article');  # article's author is stubbed