/
Xoos.pm6
113 lines (101 loc) · 3.38 KB
/
Xoos.pm6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
unit role DB::Xoos;
use DB::Xoos::Model;
has $!db;
has $!driver;
has %!cache;
has $!connected;
has $!prefix;
multi method connect(Any:D: :$db, :%options) { ... }
multi method connect(Str:D $dsn, :%options) { ... }
method !from-structure($mod) {
my $name = $mod<name>//$mod<table>;
my $row-class = $mod<row-class> // "{$!prefix}::Row::{$mod<name>//$mod<table>.ucfirst}";
my $new-model := Metamodel::ClassHOW.new_type(:name('DB::Xoos::Model::'~$name));
$new-model.HOW.add_attribute($new-model, Attribute.new(
:name<@.columns>, :has_accessor(1), :type(Array), :package($new-model.WHAT),
));
$new-model.HOW.add_attribute($new-model, Attribute.new(
:name<@.relations>, :has_accessor(1), :type(Array), :package($new-model.WHAT),
));
my @role-attr = $mod<table>;
try {
require ::($row-class);
@role-attr.push($row-class);
};
$new-model.^add_role(DB::Xoos::Model[|@role-attr]);
$new-model.HOW.compose($new-model);
my @columns = [ $mod<columns>.keys.map({ $_ => $mod<columns>{$_} }) ];
my @relations = [ $mod<relations>.keys.map({ $_ => $mod<relations>{$_} }) ];
%!cache{$name} = $new-model.new(driver => $!driver, :$!prefix, db => $!db, dbo => self, :@columns, :@relations);
}
method load-models(@model-dirs?, :%dynamic?) {
my $base = $!prefix !~~ Nil ?? $!prefix !! ($?CALLERS::CLASS.^name//'');
my @possible = try {
CATCH {
default {
.say unless @model-dirs.elems;
}
};
"lib/{$base.subst('::', '/')}/Model".IO.dir.grep(
* ~~ :f && *.extension eq any('pm6', 'pl6')
) if "lib/{$base.subst('::', '/')}/Model".IO ~~ :d;
} // [];
for @possible -> $f {
next unless $f.index("lib/$base") !~~ Nil;
my $mod-name = $f.path.substr($f.index("lib/$base")+4, $f.rindex('.') - $f.index("lib/$base") - 4);
$mod-name .=subst(/^^(\/|\\)/, '');
$mod-name .=subst(/(\/|\\)/, '::', :g);
try {
my $m = (require ::($mod-name));
%!cache{$mod-name.split('::')[*-1]} = $m.new(:$!driver, :$!db, :$!prefix, dbo => self);
CATCH {
default {
warn "error loading $mod-name\n" ~ $_.Str;
}
}
}
}
if @model-dirs.elems {
my $no-yaml = (try require ::('YAML::Parser::LibYAML')) === Nil;
warn 'Cannot find YAML::Parser::LibYAML when attempting to load yaml models'
if $no-yaml;
unless $no-yaml {
my $parser = ::('YAML::Parser::LibYAML::EXPORT::DEFAULT::&yaml-parse');
for @model-dirs -> $dir {
my @files = $dir.IO.dir;
for @files -> $fil {
next if $fil !~~ :f || $fil.extension ne 'yaml';
my $mod = $parser.($fil.relative);
self!from-structure($mod);
}
}
}
}
self!from-structure($_) for %dynamic.values;
}
method model(Str $model-name, Str :$module?) {
if %!cache{$model-name}.defined {
return %!cache{$model-name};
}
my $prefix = $!prefix !~~ Nil ?? $!prefix !! $?OUTER::CLASS.^name;
my $model = $module.defined ?? $module !! "$prefix\::Model\::$model-name";
my $loaded = (try require ::("$model")) === Nil;
if !$loaded {
warn "Unable to load model: $model-name ($model)\n";
return Nil;
}
try {
my $m = (require ::("$model"));
%!cache{$model-name} = $m.new(:$!db, :$prefix, :$model-name, dbo => self);
CATCH { default {
say "Failed to load $model-name ($model): {$_}";
} }
}
%!cache{$model-name};
}
method loaded-models {
%!cache.keys;
}
method db {
$!db;
}