Deal with multi level package names in models
If the model type name doesn't resolve as a single level then it makes a mess of creating the table name:
use Red;
module Bar {
model Foo {
has Int $.id is serial;
has Str $.name is column;
}
}
my $*RED-DEBUG = $_ with %*ENV<RED_DEBUG>;
my $*RED-DEBUG-RESPONSE = $_ with %*ENV<RED_DEBUG_RESPONSE>;
my $*RED-DB = database "SQLite", |(:database($_) with %*ENV<RED_DATABASE>);
Bar::Foo.^create-table;
Gives rise to:
'bar::foo' is an invalid table name for driver Red::Driver::SQLite
in method create-table at /home/jonathan/devel/perl6/3rdparty-modules/Red/lib/MetamodelX/Red/Model.pm6 (MetamodelX::Red::Model) line 176
in block <unit> at yy line 16
Obviously this can be remedied by supplying the is table trait to the model, but organizing a set of classes within an outer module is a sufficiently common practice that maybe it should be handled a bit more nicely. The easiest would be just to use the "local" part of the name for the table by default, alternatively simply replacing the invalid characters with an '_'. A more refined solution would be, where the DB backend supports it, to allow the namespace qualifying of the tables perhaps even supplying an is namespace trait for the surrounding package. For Pg this would translate to the schema and perhaps for SQLite as an "attached database" (https://www.sqlite.org/lang_naming.html, which has its own difficulties.)
Again, as there is a sensible workaround I wouldn't give it too high a priority, but just something to think about it.
Yes, good idea!
As I got into this issue too, so, got a note to take into account... While mapping into a schema is an interesting idea it has a couple of issues. Firstly, schemas cannot be nested in Postgres (know nothing about other DBs). If an app with a complex structure defines a Models::Data::Table, we won't be able to create models.data.table. While this could be overrules by replacing :: with double underscores __ in containing module name (models__data schema) there is another potential issue of Postgres limiting names to 63 characters. Not sure how unlikely would it be to hit this limit. But considering that data structures (which models are) are usually been hidden deep inside code structure, the risk is not overly low. Perhaps a driver must take this into consideration and issue a warning if a name happens to be too long.
Update for a long-pending issue. With :api<2> changing the syntax of referencing and relationship traits making :model required, it would make sense to provide support for passing model type object to :model:
model M1 { ... }
model M2 {
has $.m1 is relationship(*.id, :model(M1));
}
And, yes, I did bump into this problem again a few minutes ago. :)
No. referencing trait explicitly declares $model to be a Str.
Worse than that, as I'm currently trying to investigate, Red::Attr::Relationship accepts $model as Str only.
I've forgotten mentioning it here, but I've created 2 new experimental features that modifies this behaviour:
shortnamethat makes Red use only the shortname of the module to generate the table nameformatsthat allows you to set functions that will be used to generate the tables and columns names. eg:
my &*RED-TABLE-FORMATER = -> $name { "RED_TABLE_$name" }
my &*RED-COLUMN-FORMATER = -> $name { "`$name`" }
(https://fco.github.io/Red/tutorials/experimental.html)
It's probably too late but FORMATER is spelled wrong :-D
Is it fixed now?