The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
BEGIN {
	$|  = 1;
	$^W = 1;
}

use t::lib::Test;
use Test::More;
use DBD::SQLite;
use Data::Dumper;

# NOTE: It seems to be better to compare rounded values
# because stored coordinate values may have slight errors
# since SQLite 3.7.13 (DBD::SQLite 1.38_01).

sub is_deeply_approx {
    my ($got, $expected, $name) = @_;
    my $got_approx      = [map { sprintf "%0.2f", $_ } @$got];
    my $expected_approx = [map { sprintf "%0.2f", $_ } @$expected];
    is_deeply($got_approx, $expected_approx, $name);
}

my @coords = (
   # id, minX, maxX, minY, maxY
    [1,  1,    200,  1,    200],  # outside bounding box
    [2,  25,   100,  25,   50],   
    [3,  50,   125,  40,   150],   
    [4,  25,   200,  125,  125],  # hor.  line
    [5,  100,  100,  75,   175],  # vert. line
    [6,  100,  100,  75,   75],   # point
    [7,  150,  175,  150,  175]
);

my @test_regions = (
   # minX, maxX, minY, maxY
    [75,   75,   45,   45],       # query point
    [10,   140,  10,   175],      # ... box
    [30,   100,  75,   75]        # ... hor. line
);

my @test_results = (
    # results for contains tests (what does this region contain?)
    [],
    [2, 3, 5, 6],
    [6],
    
    # results for overlaps tests (what does this region overlap with?)
    [1..3],
    [1..6],
    [1, 3, 5, 6]
);

BEGIN {
	if (!grep /ENABLE_RTREE/, DBD::SQLite::compile_options()) {
		plan skip_all => 'RTREE is disabled for this DBD::SQLite';
	}
}
use Test::NoWarnings;

plan tests => @coords + (2 * @test_regions)  + 4;

# connect
my $dbh = connect_ok( RaiseError => 1 );

# TODO: test rtree and rtree_i32 tables

# create R* Tree table
$dbh->do(<<"") or die DBI::errstr;
  CREATE VIRTUAL TABLE try_rtree
        USING rtree_i32(id, minX, maxX, minY, maxY);

# populate it
my $insert_sth = $dbh->prepare(<<"") or die DBI::errstr;
INSERT INTO try_rtree VALUES (?,?,?,?,?)

for my $coord (@coords) {
    ok $insert_sth->execute(@$coord);
}

# find by primary key
my $sql = "SELECT * FROM try_rtree WHERE id = ?";

my $idx = 0;
for my $id (1..2) {
    my $results = $dbh->selectrow_arrayref($sql, undef, $id);
    is_deeply_approx($results, $coords[$idx], "Coords for $id match");
    $idx++;
}

# find contained regions
my $contained_sql = <<"";
SELECT id FROM try_rtree
    WHERE  minX >= ? AND maxX <= ?
    AND    minY >= ? AND maxY <= ?

# Since SQLite 3.7.13, coordinate values may have slight errors.
for my $region (@test_regions) {
    my $results = $dbh->selectcol_arrayref($contained_sql, undef, @$region);
    is_deeply_approx($results, shift @test_results);
}

# find overlapping regions
my $overlap_sql = <<"";
SELECT id FROM try_rtree
   WHERE    maxX >= ? AND minX <= ?
   AND      maxY >= ? AND minY <= ?

for my $region (@test_regions) {
    my $results = $dbh->selectcol_arrayref($overlap_sql, undef, @$region);
    is_deeply_approx($results, shift @test_results);
}