Skip to content

Commit

Permalink
Add DBIish plugin (#81)
Browse files Browse the repository at this point in the history
* add DBIish plugin

* clean up

* fix plugin tests

* add new test

* skip-rest

* add example

* plans

* clean up
  • Loading branch information
rawleyfowler authored Feb 12, 2024
1 parent 5f43d8a commit 77facd5
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.precomp
.gitconfig
sdist
*.db
5 changes: 3 additions & 2 deletions META6.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"Humming-Bird::Plugin": "lib/Humming-Bird/Plugin.rakumod",
"Humming-Bird::Plugin::Config": "lib/Humming-Bird/Plugin/Config.rakumod",
"Humming-Bird::Plugin::Logger": "lib/Humming-Bird/Plugin/Logger.rakumod",
"Humming-Bird::Plugin::Session": "lib/Humming-Bird/Plugin/Session.rakumod"
"Humming-Bird::Plugin::Session": "lib/Humming-Bird/Plugin/Session.rakumod",
"Humming-Bird::Plugin::DBIish": "lib/Humming-Bird/Plugin/DBIish.rakumod"
},
"resources": [
],
Expand All @@ -49,5 +50,5 @@
"Test::Util::ServerPort",
"Cro::HTTP::Client"
],
"version": "3.0.4"
"version": "3.0.5"
}
5 changes: 5 additions & 0 deletions examples/dbiish/create-db.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
age INTEGER
);
32 changes: 32 additions & 0 deletions examples/dbiish/dbiish.raku
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use Humming-Bird::Core;
use JSON::Fast;

# Create database with:
# sqlite3 mydb.db < create-db.sql

# Tell Humming-Bird::Plugin::DBIish where to look for your db.
plugin 'DBIish', ['SQLite', :database('mydb.db')];

get '/users', sub ($request, $response) {
my $sth = $request.db.execute(q:to/SQL/);
SELECT * FROM users
SQL
my $json = to-json($sth.allrows(:array-of-hash));
return $response.json($json);
}

post '/users', sub ($request, $response) {
my $sth = $request.db.prepare(q:to/SQL/);
INSERT INTO users (name, age)
VALUES (?, ?)
RETURNING *
SQL

my $content = $request.content;
$sth = $sth.execute($content<name>, $content<age>);

my $json = to-json($sth.allrows(:array-of-hash));
return $response.json($json);
}

listen(8080);
1 change: 0 additions & 1 deletion lib/Humming-Bird/Backend/HTTPServer.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ method listen(&handler) {
react {
self!timeout;
self!respond(&handler);

whenever IO::Socket::Async.listen($.addr // '0.0.0.0', $.port) -> $connection {
my %connection-map := {
socket => $connection,
Expand Down
8 changes: 4 additions & 4 deletions lib/Humming-Bird/Core.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use Humming-Bird::Glue;

unit module Humming-Bird::Core;

our constant $VERSION = '3.0.4';
our constant $VERSION = '3.0.5';

### ROUTING SECTION
my constant $PARAM_IDX = ':';
Expand Down Expand Up @@ -307,7 +307,7 @@ sub listen(Int:D $port, Str:D $addr = '0.0.0.0', :$no-block, :$timeout = 3, :$ba
require ::($fq);
CATCH {
default {
die "It doesn't look like $fq is a valid plugin? Are you sure it's installed? $_";
die "It doesn't look like $fq is a valid plugin? Are you sure it's installed?\n\n$_";
}
}
}
Expand All @@ -327,9 +327,9 @@ sub listen(Int:D $port, Str:D $addr = '0.0.0.0', :$no-block, :$timeout = 3, :$ba

say(
colored('Humming-Bird', 'green'),
" listening on port http://$addr:$port"
" listening on port http://$addr:$port",
"\n"
);
say '';
say(
colored('Warning', 'yellow'),
': Humming-Bird is currently running in DEV mode, please set HUMMING_BIRD_ENV to PROD or PRODUCTION to enable PRODUCTION mode.',
Expand Down
53 changes: 53 additions & 0 deletions lib/Humming-Bird/Plugin/DBIish.rakumod
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use MONKEY;
use Humming-Bird::Plugin;
use Humming-Bird::Core;

unit class Humming-Bird::Plugin::DBIish does Humming-Bird::Plugin;

my %databases;

method register($server, %routes, @middleware, @advice, **@args) {
my $dbiish = try "use DBIish; DBIish".EVAL;

if $dbiish ~~ Nil {
die 'You do not have DBIish installed, please install DBIish to use Humming-Bird::Plugin::DBIish.';
}

if @args.elems < 1 {
die "Invalid configuration for Humming-Bird::Plugin::DBIish, please provide more arguments.\n\nExample: `plugin 'DBIish', ['SQLite', 'mydb.db']`";
}

my $database-name = 'default';
my @database-args;

if @args.elems == 1 {
if @args[0].isa(Array) || @args[0].isa(List) {
@database-args = |@args[0];
} else {
$database-name = @args[0];
}
} else {
$database-name = @args[0];
@database-args = |@args[1];
}

if (%databases.keys.elems == 0) {
augment class Humming-Bird::Glue::HTTPAction {
method db(Str $database = 'default') {
%databases{$database};
}
}
}

my $dh = $dbiish.install-driver(shift @database-args);

say @database-args;
%databases{$database-name} = $dh.connect(|%(|@database-args));

CATCH {
default {
die "Failed to setup Humming-Bird::Plugin::DBIish cause:\n\n$_";
}
}
}

40 changes: 40 additions & 0 deletions lib/Humming-Bird/Plugin/HotReload.rakumod
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use MONKEY-TYPING;
use Humming-Bird::Plugin;
use Humming-Bird::Core;
use Humming-Bird::Backend;

unit class Humming-Bird::Plugin::HotReload does Humming-Bird::Plugin;

class Humming-Bird::Backend::HotReload does Humming-Bird::Backend {
has $.backend handles <port addr timeout>;
has Channel:D $!reload-chan .= new;
method listen(&handler) {
self!observe();
self!start-server();

react whenever $!reload-chan -> $reload {
$.backend.close;
self!start-server();
}
}

method !start-server {
start {
listen(self.port, self.addr, );
}
}

method !observe {

}
}

method register($server is rw, %routes, @middleware, @advice, **@args) {
die 'Humming-Bird::Backend::HotRealod is WIP. Please do not use it yet.';
$server = Humming-Bird::Backend::HotReload.new(backend => $server);
CATCH {
default {
warn 'Failed to find or parse your ".humming-bird.json" configuration. Ensure your file is well formed, and does exist.';
}
}
}
29 changes: 29 additions & 0 deletions t/opt/plugin-dbiish-sad.rakutest
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use v6;
use lib 'lib';
use Test;
use Humming-Bird::Core;
use Humming-Bird::Glue;
use Humming-Bird::Backend;
use Humming-Bird::Middleware;
use Humming-Bird::Advice;
use Humming-Bird::Plugin::DBIish;

plan 2;

my \DBIish = try "use DBIish; DBIish".EVAL;

if DBIish ~~ Nil {
skip-rest;
exit;
}

class TestBackend does Humming-Bird::Backend {
method listen(&handler) {
return; # Does nothing
}
}

lives-ok sub { plugin('DBIish'); }, 'Does plugin not die?';
dies-ok sub { listen(8080, :backend(TestBackend)); }, 'Does plugin register die?';

done-testing;
36 changes: 36 additions & 0 deletions t/opt/plugin-dbiish.rakutest
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use v6;
use lib 'lib';
use Test;
use Humming-Bird::Core;
use Humming-Bird::Glue;
use Humming-Bird::Backend;
use Humming-Bird::Middleware;
use Humming-Bird::Advice;

my \DBIish = try "use DBIish; DBIish".EVAL;

plan 9;

if DBIish ~~ Nil {
skip-rest;
exit;
}

class TestBackend does Humming-Bird::Backend {
method listen(&handler) {
return; # Does nothing
}
}

use-ok "Humming-Bird::Plugin::DBIish", 'Does use ok? (not that you should :P)';
lives-ok sub { plugin('DBIish', ['TestMock']); }, 'Does default plugin not die?';
lives-ok sub { plugin('DBIish', 'other-db', ['TestMock']); }, 'Does other-db plugin not die?';
lives-ok sub { listen(8080, :backend(TestBackend)); }, 'Does plugin register ok?';
ok Humming-Bird::Glue::HTTPAction.^can('db'), 'Did plugin properly run?';
my $action = Humming-Bird::Glue::HTTPAction.new;
ok $action.^can('db')[0].($action), 'Is default DB accessible?';
ok $action.^can('db')[0].($action, 'other-db'), 'Is other db accessible?';
is $action.^can('db')[0].($action).^name.Str, "DBDish::TestMock::Connection", 'Is default db correct type?';
is $action.^can('db')[0].($action, 'other-db').^name.Str, "DBDish::TestMock::Connection", 'Is other db correct type?';

done-testing;

0 comments on commit 77facd5

Please sign in to comment.