Tangra...omMany(3pm)

πŸ“¦
version 2.12 Β· 3 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

πŸ’– Tangra::Type::Ref::FromMany (that's the Tangram::Type::Ref::FromMany page, from section 3pm of the User Contributed Perl Documentation) πŸ’–

okay bestie sit DOWN because we're about to talk about mapping references to persistent objects and it's actually so good 🫢

✨ NAME ✨

Tangram::Type::Ref::FromMany β€” maps references to persistent objects, periodt πŸ’…


🌸 SYNOPSIS 🌸

use Tangram;

# or
use Tangram::Core;
use Tangram::Type::Ref::FromMany;

$schema = Tangram::Schema->new(
    classes => { Company => { fields => {
      ref => [ qw( ceo vice_ceo ) ]

# or

$schema = Tangram::Schema->new(
    classes => { Company => { fields => {
      ref =>
      {
         ceo =>
         {
            col => 'ceo',
            null => 0
         },

         vice_ceo =>
         {
            ...
         }

like. it's giving schema. it's giving ref. we love to see it 🌈


πŸ¦‹ DESCRIPTION πŸ¦‹

So this class? Its whole job β€” its entire main character energy β€” is mapping fields that hold a reference to a Perl object. The persistent fields get grouped together in a hash, tucked under the "ref" key in the field hash. iconic, honestly.

The target object must belong to a persistent class. no exceptions bestie, that's the vibe check.

Tangram uses a column on the source object to store the id of the target object. literally that's it, that's the trick πŸ’«

The persistent fields may be specified either as a hash or as an array of field names. your choice, your era.

In the hash form, each entry is a field name plus an associated option hash. And that option hash may contain the following fields:

  • aggreg
  • col
  • type_col
  • class
  • null
  • deep_update

okay now let's go through them one by one because they all matter πŸŽ€

Optional field "aggreg" specifies that the referenced element (if any) must be removed (erased) from persistent storage along with the source object. The default is not to aggregate. so by default it stays, no cap.

"col" sets the name of the column that contains the target object's id. This field is optional, it default to the persistent field name. You need to specify a column name if the field name is not an allowed SQL column identifier. (iykyk β€” weird field name, weird column, gotta spell it out πŸ’…)

"type_col" sets the name of the second column, that contains the target object's type id. This field is optional, it default to the value of "col" with "_type" appended. Set to the empty string ("") to disable this column, which requires that you also specify a class. so like. disable at your own risk and only with a class on deck πŸ™ˆ

"class" specifies the base class of the reference, which automatically disables "type_col" (currently unimplemented). yes bestie, it says unimplemented, we're just reporting the lore πŸ”₯

"null", if present and set to true, directs deploy() to generate SQL code that allows NULL values for that column.

Optional field "deep_update" specificies that the target object has to be updated automatically when "update" is called on the source object. Automatic update ensures consisitency between the Perl representation and the DBMS state, but degrades update performance so use it with caution. The default is not to do automatic updates. (yes, the original really spells it "specificies" and "consisitency" β€” we cherish them, we do not touch them 🫢)

⚠️ warning: there is currently something of a bug with all deep_update collections. If you (for instance) insert an object, and a property of that object that is deep_update, then sometimes things end up getting inserted twice β€” especially in mapping tables. This is currently under investigation. πŸ’€ so like. heads up. it's a known situation. the devs are on it.

You may also pass the names of the persistent fields in an array, in which case Tangram uses the field names as column names and allows NULL values. easy mode, slay ✨


πŸ‘‘ IMPLEMENTATION NOTES πŸ‘‘

🧚 INHERITANCE

Ref directly inherits from Tangram::Type::Scalar, and indirectly from Type. a whole family tree, we love lineage πŸ’œ

πŸ’Ύ STORING REFERENCES

When Tangram stores a reference to another object, it stores the target object's OID in the source object's table, just like what happens with other scalar types like String and Number.

At least that's what basically happens, but there can be complications. (not me foreshadowing 😭)

Complication #1: the target object is not persistent yet. Thus it doesn't have an OID yet. Tangram will attempt to store the target object; if this succeeds, the target object gets an OID too and Tangram can proceed. ok problem solved, moving on πŸ’…

Complication #2: Tangram may detect that the target object is already being saved; this happens in presence of cycles. Let's take an example:

    $homer = Person->new();
    $marge = Person->new();
    $homer->{partner} = $marge;
    $marge->{partner} = $homer;

    $storage->insert( $homer );

What happens here? Tangram detects that $homer refers to $marge, and that $marge is not yet persistent. So it ignores $homer for a while, and proceeds to storing $marge.

In the process, Tangram sees that $marge refers to $homer β€” which is not persistent yet! its insert() is suspended. Fortunately Tangram realizes that, and doesn't attempt to store $homer again. Instead it stores a NULL in the 'partner' column of Marge's row.

Tangram also schedules an UPDATE statement that will be executed just before returning from the call to insert(). That statement will patch Marge's 'partner' column with the proper OID. the way that it just... patches it later. obsessed 🌸

🌈 LOADING REFERENCES

Tangram never loads the target object in the process of retrieving the source object. Doing so could have disastrous consequences. For example, consider a family tree, where each Person has a reference to Mom and Dad. Pulling any single Person would eventually retrieve everybody up to Adam and Eve! If Tangram did work that way, that is...

Instead, Tangram ties all the fields that are declared as outgoing references to a package (Tangram::Lazy::Ref). The underlying object keeps track of the source object's OID, the Storage object, and the name of the persistent field.

When β€” if β€” a reference field is accessed, the target object is pulled from the database (if it's not already present in memory), and the field is untied and its value is replaced with a reference to the target object. As a result, the target object is loaded on demand, but in an almost transparent fashion (why almost? because you can always use tied() on the field and detect that strange things are taking place). sneak peek energy πŸ”βœ¨


and that's the page bestie!! this one's running under perl v5.36.0, dated 2022-10-16, so give it up for the vintage queen πŸ‘‘πŸ’– bye ily, go map some references πŸ¦‹πŸŒΈπŸ’…

πŸ“¦ where this page comes from