use v6.d; use Red::Database; use Red::Driver; use Red::AST; use Red::AST::Select; use Red::AST::Infix; use Red::AST::Value; use Red::AST::LastInsertedRow; use Red::Statement; unit role Red::Driver::Cache does Red::Driver; method schema-reader {} proto cache($, $) is export { * } multi cache(Str $cache, Str $driver) { cache $cache => \(), $driver => \() } multi cache(Pair $cache-pair, Str $driver) { cache $cache-pair, $driver => \() } multi cache(Str $cache, Pair $driver-pair) { cache $cache => \(), $driver-pair } multi cache(Str $cache, Red::Driver $driver) { cache $cache => \(), $driver } multi cache(Pair (Str :key($cache-driver), Capture :value($cache-conf)), Red::Driver $driver) { my $cache = "Red::Driver::Cache::$cache-driver"; require ::($cache); ::($cache).new: :$driver, |$cache-conf } multi cache( Pair (Str :key($cache-driver), Capture :value($cache-conf)), Pair (Str :key($driver-name), Capture :value($driver-conf)) ) is export { my $driver = database $driver-name, |$driver-conf; my $cache = "Red::Driver::Cache::$cache-driver"; require ::($cache); ::($cache).new: :$driver, |$cache-conf } multi method get-from-cache(Red::AST) { ... } multi method set-on-cache(Red::AST, @) { ... } has Red::Driver $.driver is required; multi method default-type-for(Red::Column $a --> Str:D) { $!driver.default-type-for($a) } multi method is-valid-table-name(|c) { $!driver.is-valid-table-name(|c) } multi method type-by-name(|c) { $!driver.type-by-name(|c) } multi method inflate(|c) { $!driver.inflate(|c) } multi method deflate(|c) { $!driver.deflate(|c) } multi method prepare(Str $_) { $!driver.prepare($_) } multi method translate(Red::AST $ast, $context?) { $!driver.translate($ast, $context) } my class CachedStatement does Red::Statement { has Red::AST $.ast is required; has Iterator $.iterator is required; method stt-exec($stt, *@bind) { } method stt-row($stt) { $!iterator.pull-one } } my class Statement does Red::Statement { has Red::AST $.ast is required; has Red::Statement $.stt is required; has Iterator $.iterator; method stt-exec($stt, *@bind) { my @data; $!stt.stt-exec: $!stt, |@bind; while my $row = $!stt.row { @data.push: $row } note "setting data on cache" if $*RED-CACHE-DEBUG; $!driver.set-on-cache: $!ast, @data; $!iterator = @data.iterator } method stt-row($stt) { $!iterator.pull-one } } multi method prepare(Red::AST::Select $ast ) { CATCH { default { return $!driver.prepare: $ast } } with self.get-from-cache: $ast { PRE .^can: "iterator"; note "getting data from cache" if $*RED-CACHE-DEBUG; return CachedStatement.new: :driver(self), :iterator(.iterator), :$ast } do for $!driver.prepare: $ast -> $stt { Statement.new: :driver(self), :$stt, :$ast } }