File Coverage

blib/lib/DBIx/QuickDB/Driver/DuckDB.pm
Criterion Covered Total %
statement 31 69 44.9
branch 4 18 22.2
condition 0 6 0.0
subroutine 9 18 50.0
pod 9 9 100.0
total 53 120 44.1


line stmt bran cond sub pod time code
1             package DBIx::QuickDB::Driver::DuckDB;
2 4     4   201098 use strict;
  4         7  
  4         141  
3 4     4   18 use warnings;
  4         8  
  4         217  
4              
5 4     4   2519 use IPC::Cmd qw/can_run/;
  4         221208  
  4         309  
6 4     4   53 use Scalar::Util qw/reftype/;
  4         8  
  4         234  
7              
8             our $VERSION = '0.000042';
9              
10 4     4   384 use parent 'DBIx::QuickDB::Driver';
  4         230  
  4         29  
11              
12 4     4   222 use DBIx::QuickDB::Util::HashBase qw{-duckdb -started};
  4         7  
  4         53  
13              
14             my ($DUCKDB, $DBDDUCKDB);
15              
16             BEGIN {
17 4     4   16 local $@;
18              
19 4         37 $DUCKDB = can_run('duckdb');
20 4         1306 $DBDDUCKDB = eval { require DBD::DuckDB; 'DBD::DuckDB' };
  4         2955  
  0         0  
21             }
22              
23             sub version_string {
24 0     0 1 0 my $binary;
25              
26             # Go in reverse order assuming the last param hash provided is most important
27 0         0 for my $arg (reverse @_) {
28 0 0       0 my $type = reftype($arg) or next; # skip if not a ref
29 0 0       0 next unless $type eq 'HASH'; # We have a hashref, possibly blessed
30              
31             # If we find a launcher we are done looping, we want to use this binary.
32 0 0       0 $binary = $arg->{+DUCKDB} and last;
33             }
34              
35             # If no args provided one to use we fallback to the default from $PATH
36 0   0     0 $binary ||= $DUCKDB;
37              
38 0 0       0 return 'unknown' unless $binary;
39              
40             # Call the binary with '--version', capturing and returning the output using backticks.
41 0         0 return `$binary --version`;
42             }
43              
44 6     6   34 sub _default_paths { return (duckdb => $DUCKDB) }
45              
46             sub viable {
47 6     6 1 14 my $this = shift;
48 6         14 my ($spec) = @_;
49              
50 6 50       24 my %check = (ref($this) ? %$this : (), $this->_default_paths, %$spec);
51              
52 6         13 my @bad;
53 6 50       20 push @bad => "'DBD::DuckDB' module could not be loaded, needed for connecting" unless $DBDDUCKDB;
54 6 50       21 push @bad => "'duckdb' command is missing, needed for loading SQL" unless $check{+DUCKDB};
55              
56 6 50       16 return (1, undef) unless @bad;
57 6         35 return (0, join "\n" => @bad);
58             }
59              
60             sub init {
61 0     0 1   my $self = shift;
62 0           $self->SUPER::init();
63              
64 0           my %defaults = $self->_default_paths;
65 0   0       $self->{$_} ||= $defaults{$_} for keys %defaults;
66              
67 0           $self->{+STARTED} = 1;
68              
69 0           return;
70             }
71              
72 0     0     sub bootstrap { return }
73 0     0 1   sub start { return }
74 0     0 1   sub stop { return }
75              
76             sub clone {
77 0     0 1   my $self = shift;
78              
79 0           local $self->{+STARTED} = 0;
80              
81 0           return $self->SUPER::clone(@_);
82             }
83              
84             sub connect_string {
85 0     0 1   my $self = shift;
86 0           my ($db_name) = @_;
87 0 0         $db_name = 'quickdb' unless defined $db_name;
88              
89 0           my $dir = $self->{+DIR};
90 0           my $path = "$dir/$db_name";
91              
92 0           require DBD::DuckDB;
93 0           return "dbi:DuckDB:dbname=$path";
94             }
95              
96             sub load_sql {
97 0     0 1   my $self = shift;
98 0           my ($db_name, $file) = @_;
99              
100 0           my $dir = $self->{+DIR};
101 0           my $path = "$dir/$db_name";
102              
103             # DBD::DuckDB cannot prepare multiple statements in one do(); the CLI reads
104             # statements from STDIN, so pipe the file through it.
105 0           $self->run_command([$self->{+DUCKDB}, $path], {stdin => $file});
106             }
107              
108             sub shell_command {
109 0     0 1   my $self = shift;
110 0           my ($db_name) = @_;
111              
112 0           my $dir = $self->{+DIR};
113 0           my $path = "$dir/$db_name";
114              
115 0           return ($self->{+DUCKDB}, $path);
116             }
117              
118             1;
119              
120             __END__