Hello community, here is the log from the commit of package perl-Mojo-SQLite for openSUSE:Factory checked in at 2017-07-21 22:50:39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-Mojo-SQLite (Old) and /work/SRC/openSUSE:Factory/.perl-Mojo-SQLite.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-Mojo-SQLite" Fri Jul 21 22:50:39 2017 rev:6 rq:511755 version:3.000 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-Mojo-SQLite/perl-Mojo-SQLite.changes 2017-06-07 09:56:33.317086128 +0200 +++ /work/SRC/openSUSE:Factory/.perl-Mojo-SQLite.new/perl-Mojo-SQLite.changes 2017-07-21 22:50:40.377947910 +0200 @@ -1,0 +2,17 @@ +Fri Jul 21 05:50:16 UTC 2017 - [email protected] + +- updated to 3.000 + see /usr/share/doc/packages/perl-Mojo-SQLite/Changes + + 3.000 2017-07-20 01:16:50 EDT + - Changed default for max_connections attribute to 1. + - Added support for sharing the database connection cache between multiple + Mojo::SQLite objects. (based on Mojo::Pg 4.0) + - Added parent attribute to Mojo::SQLite. + - Fixed database connection leak with automatic migrations. + - Removed deprecated Mojo::SQLite::PubSub and associated methods and attributes. + SQLite's serverless nature means it does not have the ability to support + client notifications, so it is not possible to implement an efficient + pubsub system as in for example PostgreSQL, Redis, or websockets. + +------------------------------------------------------------------- Old: ---- Mojo-SQLite-2.002.tar.gz New: ---- Mojo-SQLite-3.000.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-Mojo-SQLite.spec ++++++ --- /var/tmp/diff_new_pack.3HMY20/_old 2017-07-21 22:50:41.153838461 +0200 +++ /var/tmp/diff_new_pack.3HMY20/_new 2017-07-21 22:50:41.157837896 +0200 @@ -17,7 +17,7 @@ Name: perl-Mojo-SQLite -Version: 2.002 +Version: 3.000 Release: 0 %define cpan_name Mojo-SQLite Summary: Tiny Mojolicious Wrapper for Sqlite @@ -34,7 +34,7 @@ BuildRequires: perl(DBI) >= 1.627 BuildRequires: perl(Module::Build::Tiny) >= 0.034 BuildRequires: perl(Module::Metadata) -BuildRequires: perl(Mojolicious) >= 7.15 +BuildRequires: perl(Mojolicious) >= 7.32 BuildRequires: perl(SQL::Abstract) >= 1.81 BuildRequires: perl(Test::More) >= 0.88 BuildRequires: perl(URI) >= 1.69 @@ -42,7 +42,7 @@ BuildRequires: perl(URI::file) >= 4.21 Requires: perl(DBD::SQLite) >= 1.50 Requires: perl(DBI) >= 1.627 -Requires: perl(Mojolicious) >= 7.15 +Requires: perl(Mojolicious) >= 7.32 Requires: perl(SQL::Abstract) >= 1.81 Requires: perl(URI) >= 1.69 Requires: perl(URI::db) >= 0.15 @@ -52,7 +52,9 @@ %description Mojo::SQLite is a tiny wrapper around DBD::SQLite that makes at https://www.sqlite.org/ a lot of fun to use with the at https://mojolico.us -real-time web framework. +real-time web framework. Use all at http://sqlite.org/lang.html SQLite has +to offer, generate CRUD queries from data structures, and manage your +database schema with migrations. Database and statement handles are cached automatically, so they can be reused transparently to increase performance. And you can handle connection @@ -84,7 +86,10 @@ Log" journal is enabled for all connections, allowing multiple processes to read and write concurrently to the same database file (but only one can write at a time). You can prevent this mode from being enabled by passing -the option 'no_wal'. See http://sqlite.org/wal.html for more information. +the option 'no_wal', but note that this is incompatible with SQLite +databases that have already had WAL mode enabled. See +http://sqlite.org/wal.html and DBD::SQLite/"journal_mode" for more +information. # Performed concurrently my $pid = fork || die $!; ++++++ Mojo-SQLite-2.002.tar.gz -> Mojo-SQLite-3.000.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/Build.PL new/Mojo-SQLite-3.000/Build.PL --- old/Mojo-SQLite-2.002/Build.PL 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/Build.PL 2017-07-20 07:16:52.000000000 +0200 @@ -84,7 +84,7 @@ "Dan Book <dbook\@cpan.org>" ], "dist_name" => "Mojo-SQLite", - "dist_version" => "2.002", + "dist_version" => "3.000", "license" => "artistic_2", "module_name" => "Mojo::SQLite", "recursive_test_files" => 1, @@ -94,7 +94,7 @@ "DBI" => "1.627", "File::Spec::Functions" => 0, "File::Temp" => 0, - "Mojolicious" => "7.15", + "Mojolicious" => "7.32", "SQL::Abstract" => "1.81", "Scalar::Util" => 0, "URI" => "1.69", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/Changes new/Mojo-SQLite-3.000/Changes --- old/Mojo-SQLite-2.002/Changes 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/Changes 2017-07-20 07:16:52.000000000 +0200 @@ -1,3 +1,14 @@ +3.000 2017-07-20 01:16:50 EDT + - Changed default for max_connections attribute to 1. + - Added support for sharing the database connection cache between multiple + Mojo::SQLite objects. (based on Mojo::Pg 4.0) + - Added parent attribute to Mojo::SQLite. + - Fixed database connection leak with automatic migrations. + - Removed deprecated Mojo::SQLite::PubSub and associated methods and attributes. + SQLite's serverless nature means it does not have the ability to support + client notifications, so it is not possible to implement an efficient + pubsub system as in for example PostgreSQL, Redis, or websockets. + 2.002 2017-06-01 14:16:34 EDT - Add no_wal option to prevent enabling WAL mode on connection. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/MANIFEST new/Mojo-SQLite-3.000/MANIFEST --- old/Mojo-SQLite-2.002/MANIFEST 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/MANIFEST 2017-07-20 07:16:52.000000000 +0200 @@ -16,6 +16,7 @@ examples/blog/lib/Blog/Model/Posts.pm examples/blog/migrations/blog.sql examples/blog/script/blog +examples/blog/t/blog.t examples/blog/templates/layouts/blog.html.ep examples/blog/templates/posts/_form.html.ep examples/blog/templates/posts/create.html.ep @@ -39,5 +40,3 @@ t/sqlite_lite_app.t xt/author/pod-coverage.t xt/author/pod-syntax.t -xt/deprecated/database.t -xt/deprecated/pubsub.t diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/META.json new/Mojo-SQLite-3.000/META.json --- old/Mojo-SQLite-2.002/META.json 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/META.json 2017-07-20 07:16:52.000000000 +0200 @@ -43,7 +43,7 @@ "DBI" : "1.627", "File::Spec::Functions" : "0", "File::Temp" : "0", - "Mojolicious" : "7.15", + "Mojolicious" : "7.32", "SQL::Abstract" : "1.81", "Scalar::Util" : "0", "URI" : "1.69", @@ -66,28 +66,28 @@ "provides" : { "Mojo::SQLite" : { "file" : "lib/Mojo/SQLite.pm", - "version" : "2.002" + "version" : "3.000" }, "Mojo::SQLite::Database" : { "file" : "lib/Mojo/SQLite/Database.pm", - "version" : "2.002" + "version" : "3.000" }, "Mojo::SQLite::Migrations" : { "file" : "lib/Mojo/SQLite/Migrations.pm", - "version" : "2.002" + "version" : "3.000" }, "Mojo::SQLite::PubSub" : { "file" : "lib/Mojo/SQLite/PubSub.pm", - "version" : "2.002", + "version" : "3.000", "x_deprecated" : 1 }, "Mojo::SQLite::Results" : { "file" : "lib/Mojo/SQLite/Results.pm", - "version" : "2.002" + "version" : "3.000" }, "Mojo::SQLite::Transaction" : { "file" : "lib/Mojo/SQLite/Transaction.pm", - "version" : "2.002" + "version" : "3.000" } }, "release_status" : "stable", @@ -103,7 +103,7 @@ }, "x_IRC" : "irc://irc.perl.org/#mojo" }, - "version" : "2.002", + "version" : "3.000", "x_Dist_Zilla" : { "perl" : { "version" : "5.026000" @@ -170,7 +170,7 @@ "class" : "Dist::Zilla::Plugin::Git::Contributors", "config" : { "Dist::Zilla::Plugin::Git::Contributors" : { - "git_version" : "2.5.5", + "git_version" : "2.9.4", "include_authors" : 0, "include_releaser" : 1, "order_by" : "name", @@ -211,7 +211,7 @@ "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.5.5", + "git_version" : "2.9.4", "repo_root" : "." } }, @@ -280,7 +280,7 @@ "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.5.5", + "git_version" : "2.9.4", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { @@ -297,12 +297,12 @@ "branch" : null, "changelog" : "Changes", "signed" : 0, - "tag" : "v2.002", + "tag" : "v3.000", "tag_format" : "v%v", "tag_message" : "v%v" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.5.5", + "git_version" : "2.9.4", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { @@ -345,7 +345,7 @@ "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.5.5", + "git_version" : "2.9.4", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { @@ -365,7 +365,7 @@ "remotes_must_exist" : 1 }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.5.5", + "git_version" : "2.9.4", "repo_root" : "." } }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/META.yml new/Mojo-SQLite-3.000/META.yml --- old/Mojo-SQLite-2.002/META.yml 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/META.yml 2017-07-20 07:16:52.000000000 +0200 @@ -26,30 +26,30 @@ provides: Mojo::SQLite: file: lib/Mojo/SQLite.pm - version: '2.002' + version: '3.000' Mojo::SQLite::Database: file: lib/Mojo/SQLite/Database.pm - version: '2.002' + version: '3.000' Mojo::SQLite::Migrations: file: lib/Mojo/SQLite/Migrations.pm - version: '2.002' + version: '3.000' Mojo::SQLite::PubSub: file: lib/Mojo/SQLite/PubSub.pm - version: '2.002' + version: '3.000' x_deprecated: 1 Mojo::SQLite::Results: file: lib/Mojo/SQLite/Results.pm - version: '2.002' + version: '3.000' Mojo::SQLite::Transaction: file: lib/Mojo/SQLite/Transaction.pm - version: '2.002' + version: '3.000' requires: Carp: '0' DBD::SQLite: '1.50' DBI: '1.627' File::Spec::Functions: '0' File::Temp: '0' - Mojolicious: '7.15' + Mojolicious: '7.32' SQL::Abstract: '1.81' Scalar::Util: '0' URI: '1.69' @@ -61,7 +61,7 @@ bugtracker: https://github.com/Grinnz/Mojo-SQLite/issues homepage: https://github.com/Grinnz/Mojo-SQLite repository: https://github.com/Grinnz/Mojo-SQLite.git -version: '2.002' +version: '3.000' x_Dist_Zilla: perl: version: '5.026000' @@ -113,7 +113,7 @@ class: Dist::Zilla::Plugin::Git::Contributors config: Dist::Zilla::Plugin::Git::Contributors: - git_version: 2.5.5 + git_version: 2.9.4 include_authors: 0 include_releaser: 1 order_by: name @@ -145,7 +145,7 @@ allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: - git_version: 2.5.5 + git_version: 2.9.4 repo_root: . name: '@Author::DBOOK/Git::Check' version: '2.042' @@ -198,7 +198,7 @@ allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: - git_version: 2.5.5 + git_version: 2.9.4 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local @@ -211,11 +211,11 @@ branch: ~ changelog: Changes signed: 0 - tag: v2.002 + tag: v3.000 tag_format: v%v tag_message: v%v Dist::Zilla::Role::Git::Repo: - git_version: 2.5.5 + git_version: 2.9.4 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local @@ -246,7 +246,7 @@ - (?^:^(?:lib|script|bin)/) changelog: Changes Dist::Zilla::Role::Git::Repo: - git_version: 2.5.5 + git_version: 2.9.4 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local @@ -260,7 +260,7 @@ - origin remotes_must_exist: 1 Dist::Zilla::Role::Git::Repo: - git_version: 2.5.5 + git_version: 2.9.4 repo_root: . name: '@Author::DBOOK/Git::Push' version: '2.042' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/README new/Mojo-SQLite-3.000/README --- old/Mojo-SQLite-2.002/README 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/README 2017-07-20 07:16:52.000000000 +0200 @@ -59,7 +59,10 @@ Mojo::SQLite is a tiny wrapper around DBD::SQLite that makes SQLite <https://www.sqlite.org/> a lot of fun to use with the Mojolicious - <https://mojolico.us> real-time web framework. + <https://mojolico.us> real-time web framework. Use all SQL features + <http://sqlite.org/lang.html> SQLite has to offer, generate CRUD + queries from data structures, and manage your database schema with + migrations. Database and statement handles are cached automatically, so they can be reused transparently to increase performance. And you can handle @@ -93,8 +96,10 @@ "Write-Ahead Log" journal is enabled for all connections, allowing multiple processes to read and write concurrently to the same database file (but only one can write at a time). You can prevent this mode from - being enabled by passing the option no_wal. See - http://sqlite.org/wal.html for more information. + being enabled by passing the option no_wal, but note that this is + incompatible with SQLite databases that have already had WAL mode + enabled. See http://sqlite.org/wal.html and "journal_mode" in + DBD::SQLite for more information. # Performed concurrently my $pid = fork || die $!; @@ -131,9 +136,9 @@ This distribution also contains a well-structured example blog application - <https://github.com/kraih/mojo-pg/tree/master/examples/blog> you can - use for inspiration. This application shows how to apply the MVC design - pattern in practice. + <https://github.com/Grinnz/Mojo-SQLite/tree/master/examples/blog> you + can use for inspiration. This application shows how to apply the MVC + design pattern in practice. EVENTS @@ -171,7 +176,7 @@ $sql = $sql->auto_migrate($bool); Automatically migrate to the latest database schema with "migrations", - as soon as the first database connection has been established. + as soon as "db" has been called for the first time. database_class @@ -195,7 +200,7 @@ $sql = $sql->max_connections(3); Maximum number of idle database handles to cache for future use, - defaults to 5. + defaults to 1. migrations @@ -220,9 +225,13 @@ "ATTRIBUTES COMMON TO ALL HANDLES" in DBI and "DRIVER PRIVATE ATTRIBUTES" in DBD::SQLite for more information on available options. - pubsub + parent - This attribute is DEPRECATED. + my $parent = $sql->parent; + $sql = $sql->parent(Mojo::SQLite->new); + + Another Mojo::SQLite object to use for connection management, instead + of establishing and caching our own database connections. METHODS @@ -234,6 +243,7 @@ my $sql = Mojo::SQLite->new; my $sql = Mojo::SQLite->new('file:test.db); my $sql = Mojo::SQLite->new('sqlite:test.db'); + my $sql = Mojo::SQLite->new(Mojo::SQLite->new); Construct a new Mojo::SQLite object and parse connection string with "from_string" if necessary. @@ -292,16 +302,17 @@ $sql = $sql->from_string('file:test.db'); $sql = $sql->from_string('file:///C:/foo/bar.db'); $sql = $sql->from_string('sqlite:C:%5Cfoo%5Cbar.db'); + $sql = $sql->from_string(Mojo::SQLite->new); - Parse configuration from connection string. Connection strings are - parsed as URLs, so you should construct them using a module like - Mojo::URL, URI::file, or URI::db. For portability on non-Unix-like - systems, either construct the URL with the sqlite scheme, or use "new" - in URI::file to construct a URL with the file scheme. A URL with no - scheme will be parsed as a file URL, and file URLs are parsed according - to the current operating system. If specified, the hostname must be - localhost. If the URL has a query string, it will be parsed and applied - to "options". + Parse configuration from connection string or use another Mojo::SQLite + object as "parent". Connection strings are parsed as URLs, so you + should construct them using a module like Mojo::URL, URI::file, or + URI::db. For portability on non-Unix-like systems, either construct the + URL with the sqlite scheme, or use "new" in URI::file to construct a + URL with the file scheme. A URL with no scheme will be parsed as a file + URL, and file URLs are parsed according to the current operating + system. If specified, the hostname must be localhost. If the URL has a + query string, it will be parsed and applied to "options". # Absolute filename $sql->from_string('sqlite:////home/fred/data.db'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/cpanfile new/Mojo-SQLite-3.000/cpanfile --- old/Mojo-SQLite-2.002/cpanfile 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/cpanfile 2017-07-20 07:16:52.000000000 +0200 @@ -4,7 +4,7 @@ requires 'DBD::SQLite' => '1.50'; # for json support requires 'File::Spec::Functions'; requires 'File::Temp'; -requires 'Mojolicious' => '7.15'; +requires 'Mojolicious' => '7.32'; requires 'Scalar::Util'; requires 'SQL::Abstract' => '1.81'; requires 'URI' => '1.69'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/examples/blog/t/blog.t new/Mojo-SQLite-3.000/examples/blog/t/blog.t --- old/Mojo-SQLite-2.002/examples/blog/t/blog.t 1970-01-01 01:00:00.000000000 +0100 +++ new/Mojo-SQLite-3.000/examples/blog/t/blog.t 2017-07-20 07:16:52.000000000 +0200 @@ -0,0 +1,48 @@ +use Mojo::Base -strict; + +use Test::More; + +use Mojo::SQLite; +use Mojo::URL; +use Test::Mojo; + +# Override configuration for testing +my $t = Test::Mojo->new(Blog => {sqlite => ':temp:', secrets => ['test_s3cret']}); +$t->ua->max_redirects(10); + +# No posts yet +$t->get_ok('/')->status_is(200)->text_is('title' => 'Blog') + ->text_is('body > a' => 'New post')->element_exists_not('h2'); + +# Create a new post +$t->get_ok('/posts/create')->status_is(200)->text_is('title' => 'New post') + ->element_exists('form input[name=title]') + ->element_exists('form textarea[name=body]'); +$t->post_ok('/posts' => form => {title => 'Testing', body => 'This is a test.'}) + ->status_is(200)->text_is('title' => 'Testing')->text_is('h2' => 'Testing') + ->text_like('p' => qr/This is a test/); + +# Read the post +$t->get_ok('/')->status_is(200)->text_is('title' => 'Blog') + ->text_is('h2 a' => 'Testing')->text_like('p' => qr/This is a test/); +$t->get_ok('/posts/1')->status_is(200)->text_is('title' => 'Testing') + ->text_is('h2' => 'Testing')->text_like('p' => qr/This is a test/) + ->text_is('body > a' => 'Edit'); + +# Update the post +$t->get_ok('/posts/1/edit')->status_is(200)->text_is('title' => 'Edit post') + ->element_exists('form input[name=title][value=Testing]') + ->text_like('form textarea[name=body]' => qr/This is a test/) + ->element_exists('form input[value=Remove]'); +$t->post_ok( + '/posts/1?_method=PUT' => form => {title => 'Again', body => 'It works.'}) + ->status_is(200)->text_is('title' => 'Again')->text_is('h2' => 'Again') + ->text_like('p' => qr/It works/); +$t->get_ok('/posts/1')->status_is(200)->text_is('title' => 'Again') + ->text_is('h2' => 'Again')->text_like('p' => qr/It works/); + +# Delete the post +$t->post_ok('/posts/1?_method=DELETE')->status_is(200) + ->text_is('title' => 'Blog')->element_exists_not('h2'); + +done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/examples/blog/templates/posts/index.html.ep new/Mojo-SQLite-3.000/examples/blog/templates/posts/index.html.ep --- old/Mojo-SQLite-2.002/examples/blog/templates/posts/index.html.ep 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/examples/blog/templates/posts/index.html.ep 2017-07-20 07:16:52.000000000 +0200 @@ -1,7 +1,7 @@ % layout 'blog', title => 'Blog'; % for my $post (@$posts) { + <h2><%= link_to $post->{title} => show_post => {id => $post->{id}} %></h2> <p> - <h2><%= link_to $post->{title} => show_post => {id => $post->{id}} %></h2> %= $post->{body} </p> % } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Database.pm new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Database.pm --- old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Database.pm 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Database.pm 2017-07-20 07:16:52.000000000 +0200 @@ -1,5 +1,5 @@ package Mojo::SQLite::Database; -use Mojo::Base 'Mojo::EventEmitter'; +use Mojo::Base -base; use Carp qw(croak shortmess); use DBI 'SQL_VARCHAR'; @@ -7,21 +7,15 @@ use Mojo::JSON 'to_json'; use Mojo::SQLite::Results; use Mojo::SQLite::Transaction; -use Mojo::Util qw(deprecated monkey_patch); +use Mojo::Util 'monkey_patch'; use Scalar::Util 'weaken'; -our $VERSION = '2.002'; +our $VERSION = '3.000'; our @CARP_NOT = qw(Mojo::SQLite::Migrations); -use constant DEBUG => $ENV{MOJO_PUBSUB_DEBUG} || 0; - has [qw(dbh sqlite)]; -has notification_poll_interval => sub { - deprecated 'The notification_poll_interval attribute is deprecated and should no longer be used'; - return 0.5; -}; -has results_class => 'Mojo::SQLite::Results'; +has results_class => 'Mojo::SQLite::Results'; for my $name (qw(delete insert select update)) { monkey_patch __PACKAGE__, $name, sub { @@ -49,53 +43,9 @@ sub disconnect { my $self = shift; - $self->_unwatch; $self->dbh->disconnect; } -our $_QUERY_NOTIFICATIONS; - -sub is_listening { - deprecated 'The is_listening method is deprecated and should no longer be used' unless $_QUERY_NOTIFICATIONS; - return !!keys %{shift->{listen} || {}}; -} - -sub listen { - my ($self, $name) = @_; - - deprecated 'The listen method is deprecated and should no longer be used'; - - warn qq{$self listening on channel "$name"\n} if DEBUG; - $self->{listen}{$name}++; - $self->_init_pubsub; - $self->_watch; - $self->dbh->do('insert or ignore into mojo_pubsub_listen - (listener_id, channel) values (?, ?)', undef, $self->{listener_id}, $name); - - return $self; -} - -sub notify { - my ($self, $name, $payload) = @_; - - deprecated 'The notify method is deprecated and should no longer be used'; - - $payload //= ''; - warn qq{$self sending notification on channel "$name": $payload\n} if DEBUG; - $self->_init_pubsub; - - my $dbh = $self->dbh; - $dbh->do('insert into mojo_pubsub_notify (channel, payload) - values (?, ?)', undef, $name, $payload); - my $notify_id = $dbh->{private_mojo_last_insert_id} // croak 'Failed to retrieve notify ID'; - $dbh->do('insert into mojo_pubsub_queue (listener_id, notify_id) - select listener_id, ? from mojo_pubsub_listen where channel=?', undef, $notify_id, $name); - - $self->_notifications; - - return $self; -} - sub ping { shift->dbh->ping } sub query { @@ -131,11 +81,7 @@ $results->{last_insert_id} = $dbh->{private_mojo_last_insert_id}; } - unless ($cb) { # blocking - local $_QUERY_NOTIFICATIONS = 1; # no deprecated message - $self->_notifications; - return $results; - } + return $results unless $cb; # blocking # Still blocking, but call the callback on the next tick $error = $dbh->err ? $dbh->errstr : $errored ? ($error || 'Error running SQLite query') : undef; @@ -149,26 +95,6 @@ return [grep { !$names{$_}++ } @tables]; } -sub unlisten { - my ($self, $name) = @_; - - deprecated 'The unlisten method is deprecated and should no longer be used'; - - warn qq{$self is no longer listening on channel "$name"\n} if DEBUG; - my $dbh = $self->dbh; - if ($name eq '*') { - delete $self->{listen}; - $dbh->do('delete from mojo_pubsub_listen where listener_id=?', undef, $self->{listener_id}); - } else { - delete $self->{listen}{$name}; - $dbh->do('delete from mojo_pubsub_listen where listener_id=? and channel=?', undef, - $self->{listener_id}, $name); - } - $self->_unwatch unless $self->is_listening; - - return $self; -} - sub _bind_params { my $sth = shift; return $sth unless @_; @@ -189,89 +115,6 @@ return $sth; } -sub _cleanup_pubsub { - my $self = shift; - # Delete any stale listeners and their queues - my $dbh = $self->dbh; - my $listener_ids = $dbh->selectcol_arrayref(q{select id from mojo_pubsub_listener - where last_checked < strftime('%s','now','-1 days')}); - if (@$listener_ids) { - warn qq{$self cleaning up stale listeners @$listener_ids\n"} if DEBUG; - my $in_str = join ',', ('?')x@$listener_ids; - $dbh->do("delete from mojo_pubsub_queue where listener_id in ($in_str)", undef, @$listener_ids); - $dbh->do("delete from mojo_pubsub_listen where listener_id in ($in_str)", undef, @$listener_ids); - $dbh->do("delete from mojo_pubsub_listener where id in ($in_str)", undef, @$listener_ids); - } - # Delete any notifications that are no longer queued - my $notify_ids = $dbh->selectcol_arrayref('select n.id from mojo_pubsub_notify as n - left join mojo_pubsub_queue as q on q.notify_id=n.id where q.notify_id is null'); - if (@$notify_ids) { - warn qq{$self cleaning up unqueued notifications @$notify_ids\n} if DEBUG; - my $in_str = join ',', ('?')x@$notify_ids; - $dbh->do("delete from mojo_pubsub_notify where id in ($in_str)", undef, @$notify_ids); - } -} - -sub _init_pubsub { - my $self = shift; - return $self if $self->{init_pubsub} || $self->{init_pubsub}++; - $self->sqlite->migrations->name('pubsub')->from_data->migrate; - $self->_cleanup_pubsub; -} - -sub _notifications { - my $self = shift; - if ($self->is_listening) { - my $dbh = $self->dbh; - $dbh->do(q{update mojo_pubsub_listener set last_checked=strftime('%s','now') - where id=?}, undef, $self->{listener_id}); - my $notifies = $dbh->selectall_arrayref('select n.id, n.channel, n.payload - from mojo_pubsub_notify as n inner join mojo_pubsub_queue as q on q.notify_id=n.id - where q.listener_id=? order by n.id asc', { Slice => {} }, $self->{listener_id}); - if ($notifies and @$notifies) { - do { my @ids = map { $_->{id} } @$notifies; warn qq{$self has received notifications @ids\n} } if DEBUG; - my $in_str = join ',', ('?')x@$notifies; - $dbh->do("delete from mojo_pubsub_queue where listener_id=? and notify_id in ($in_str)", undef, - $self->{listener_id}, map { $_->{id} } @$notifies); - $self->_cleanup_pubsub; - foreach my $notify (@$notifies) { - $self->emit(notification => @{$notify}{qw(channel payload)}) - if exists $self->{listen}{$notify->{channel}}; - } - } - } -} - -sub _unwatch { - my $self = shift; - return $self unless delete $self->{watching}; - warn qq{$self is no longer watching for notifications\n} if DEBUG; - Mojo::IOLoop->remove($self->{pubsub_timer}); - my $pid = delete $self->{listener_pid}; - if ($pid and $pid eq $$) { - local $@; - eval { $self->dbh->do('delete from mojo_pubsub_listener where id=?', undef, delete $self->{listener_id}) }; - } - $self->emit('close') if $self->is_listening; -} - -sub _watch { - my $self = shift; - return $self if $self->{watching} || $self->{watching}++; - warn qq{$self now watching for notifications\n} if DEBUG; - Mojo::IOLoop->remove($self->{pubsub_timer}) if exists $self->{pubsub_timer}; - my $interval = $self->notification_poll_interval; - $self->{pubsub_timer} = Mojo::IOLoop->recurring($interval => sub { - local $@; - $self->_unwatch if !eval { $self->_notifications; 1 } - or !$self->is_listening; - }); - my $dbh = $self->dbh; - $dbh->do('insert into mojo_pubsub_listener default values'); - $self->{listener_id} = $dbh->{private_mojo_last_insert_id} // die 'Unable to retrieve listener ID'; - $self->{listener_pid} = $$; -} - 1; =encoding utf8 @@ -293,30 +136,6 @@ L<Mojo::SQLite::Database> is a container for L<DBD::SQLite> database handles used by L<Mojo::SQLite>. -=head1 EVENTS - -L<Mojo::SQLite::Database> inherits all events from L<Mojo::EventEmitter> and -can emit the following new ones. - -=head2 close - - $db->on(close => sub { - my $db = shift; - ... - }); - -Emitted when the database connection gets closed while waiting for -notifications. - -=head2 notification - - $db->on(notification => sub { - my ($db, $name, $payload) = @_; - ... - }); - -Emitted when a notification has been received. - =head1 ATTRIBUTES L<Mojo::SQLite::Database> implements the following attributes. @@ -331,10 +150,6 @@ # Use DBI utility methods my $quoted = $db->dbh->quote_identifier('foo.bar'); -=head2 notification_poll_interval - -This attribute is L<DEPRECATED|Mojo::SQLite::PubSub/"DESCRIPTION">. - =head2 results_class my $class = $db->results_class; @@ -432,18 +247,6 @@ # "insert into some_table (foo, baz) values ('bar', 'yada')" $db->insert('some_table', {foo => 'bar', baz => 'yada'}); -=head2 is_listening - -This method is L<DEPRECATED|Mojo::SQLite::PubSub/"DESCRIPTION">. - -=head2 listen - -This method is L<DEPRECATED|Mojo::SQLite::PubSub/"DESCRIPTION">. - -=head2 notify - -This method is L<DEPRECATED|Mojo::SQLite::PubSub/"DESCRIPTION">. - =head2 ping my $bool = $db->ping; @@ -530,10 +333,6 @@ # Names of all tables say for @{$db->tables}; -=head2 unlisten - -This method is L<DEPRECATED|Mojo::SQLite::PubSub/"DESCRIPTION">. - =head2 update my $results = $db->update($table, \%fieldvals, \%where); @@ -576,47 +375,3 @@ =head1 SEE ALSO L<Mojo::SQLite> - -=cut - -__DATA__ - -@@ pubsub --- 1 down -drop table mojo_pubsub_listener; -drop table mojo_pubsub_listen; -drop table mojo_pubsub_notify; -drop table mojo_pubsub_queue; - --- 1 up -drop table if exists mojo_pubsub_listener; -drop table if exists mojo_pubsub_listen; -drop table if exists mojo_pubsub_notify; -drop table if exists mojo_pubsub_queue; - -create table mojo_pubsub_listener ( - id integer primary key autoincrement, - last_checked integer not null default (strftime('%s','now')) -); -create index mojo_listener_last_checked_idx on mojo_pubsub_listener (last_checked); - -create table mojo_pubsub_listen ( - listener_id integer not null, - channel text not null, - primary key (listener_id, channel) -); -create index mojo_listen_channel_idx on mojo_pubsub_listen (channel); - -create table mojo_pubsub_notify ( - id integer primary key autoincrement, - channel text not null, - payload text not null default '' -); -create index mojo_notify_channel_idx on mojo_pubsub_notify (channel); - -create table mojo_pubsub_queue ( - listener_id integer not null, - notify_id integer not null, - primary key (listener_id, notify_id) -); -create index mojo_queue_notify_id_idx on mojo_pubsub_queue (notify_id); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Migrations.pm new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Migrations.pm --- old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Migrations.pm 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Migrations.pm 2017-07-20 07:16:52.000000000 +0200 @@ -8,7 +8,7 @@ use constant DEBUG => $ENV{MOJO_MIGRATIONS_DEBUG} || 0; -our $VERSION = '2.002'; +our $VERSION = '3.000'; has name => 'migrations'; has 'sqlite'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/lib/Mojo/SQLite/PubSub.pm new/Mojo-SQLite-3.000/lib/Mojo/SQLite/PubSub.pm --- old/Mojo-SQLite-2.002/lib/Mojo/SQLite/PubSub.pm 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/lib/Mojo/SQLite/PubSub.pm 2017-07-20 07:16:52.000000000 +0200 @@ -1,80 +1,11 @@ package Mojo::SQLite::PubSub; -use Mojo::Base 'Mojo::EventEmitter'; +use Mojo::Base -strict; -use Mojo::JSON qw(from_json to_json); use Mojo::Util 'deprecated'; -use Scalar::Util 'weaken'; -our $VERSION = '2.002'; +our $VERSION = '3.000'; -has [qw(poll_interval sqlite)]; - -sub new { - my $class = shift; - deprecated 'Mojo::SQLite::PubSub is deprecated and should no longer be used'; - return $class->SUPER::new(@_); -} - -sub DESTROY { shift->_cleanup } - -sub json { ++$_[0]{json}{$_[1]} and return $_[0] } - -sub listen { - my ($self, $name, $cb) = @_; - $self->_db->listen($name) unless @{$self->{chans}{$name} ||= []}; - push @{$self->{chans}{$name}}, $cb; - return $cb; -} - -sub notify { $_[0]->_db->notify(_json(@_)) and return $_[0] } - -sub unlisten { - my ($self, $name, $cb) = @_; - my $chan = $self->{chans}{$name}; - @$chan = $cb ? grep { $cb ne $_ } @$chan : (); - $self->_db->unlisten($name) and delete $self->{chans}{$name} unless @$chan; - return $self; -} - -sub _cleanup { - my $self = shift; - $self->{db}->_unwatch; - delete @$self{qw(chans db pid)}; -} - -sub _db { - my $self = shift; - - # Fork-safety - $self->_cleanup unless ($self->{pid} //= $$) eq $$; - - return $self->{db} if $self->{db}; - - my $db = $self->{db} = $self->sqlite->db; - $db->notification_poll_interval($self->poll_interval) if defined $self->poll_interval; - weaken $db->{sqlite}; - weaken $self; - $db->on( - notification => sub { - my ($db, $name, $payload) = @_; - $payload = eval { from_json $payload } if $self->{json}{$name}; - for my $cb (@{$self->{chans}{$name}}) { $self->$cb($payload) } - } - ); - $db->once( - close => sub { - local $@; - delete $self->{db}; - eval { $self->_db }; - } - ); - $db->listen($_) for keys %{$self->{chans}}, 'mojo.pubsub'; - $self->emit(reconnect => $db); - - return $db; -} - -sub _json { $_[1], $_[0]{json}{$_[1]} ? to_json $_[2] : $_[2] } +deprecated 'Mojo::SQLite::PubSub is deprecated and should no longer be used'; 1; @@ -86,12 +17,12 @@ =head1 DESCRIPTION -L<Mojo::SQLite::PubSub> is DEPRECATED. It was originally written as a toy -following the API of L<Mojo::Pg::PubSub>, but as SQLite is serverless and has -no ability to notify clients, it is not possible to implement an efficient -pubsub system as in for example PostgreSQL, Redis, or websockets. Consider -instead using the pubsub facilities of L<Mojo::Pg>, L<Mojo::Redis2>, or -L<Mercury|mercury>. +L<Mojo::SQLite::PubSub> is DEPRECATED and now an empty package. It was +originally written as a toy following the API of L<Mojo::Pg::PubSub>, but as +SQLite is serverless and has no ability to notify clients, it is not possible +to implement an efficient pubsub system as in for example PostgreSQL, Redis, or +websockets. Consider instead using the pubsub facilities of L<Mojo::Pg>, +L<Mojo::Redis2>, or L<Mercury|mercury>. =head1 SEE ALSO diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Results.pm new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Results.pm --- old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Results.pm 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Results.pm 2017-07-20 07:16:52.000000000 +0200 @@ -5,7 +5,7 @@ use Mojo::JSON 'from_json'; use Mojo::Util 'tablify'; -our $VERSION = '2.002'; +our $VERSION = '3.000'; has 'sth'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Transaction.pm new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Transaction.pm --- old/Mojo-SQLite-2.002/lib/Mojo/SQLite/Transaction.pm 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/lib/Mojo/SQLite/Transaction.pm 2017-07-20 07:16:52.000000000 +0200 @@ -3,7 +3,7 @@ use Carp 'croak'; -our $VERSION = '2.002'; +our $VERSION = '3.000'; has 'db'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/lib/Mojo/SQLite.pm new/Mojo-SQLite-3.000/lib/Mojo/SQLite.pm --- old/Mojo-SQLite-2.002/lib/Mojo/SQLite.pm 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/lib/Mojo/SQLite.pm 2017-07-20 07:16:52.000000000 +0200 @@ -8,19 +8,18 @@ use File::Temp; use Mojo::SQLite::Database; use Mojo::SQLite::Migrations; -use Mojo::SQLite::PubSub; -use Scalar::Util 'weaken'; +use Scalar::Util qw(blessed weaken); use SQL::Abstract; use URI; use URI::db; -our $VERSION = '2.002'; +our $VERSION = '3.000'; has abstract => sub { SQL::Abstract->new(name_sep => '.', quote_char => '"') }; has 'auto_migrate'; has database_class => 'Mojo::SQLite::Database'; has dsn => sub { _url_from_file(shift->_tempfile)->dbi_dsn }; -has max_connections => 5; +has max_connections => 1; has migrations => sub { my $migrations = Mojo::SQLite::Migrations->new(sqlite => shift); weaken $migrations->{sqlite}; @@ -35,21 +34,19 @@ sqlite_unicode => 1, }; }; -has pubsub => sub { - my $pubsub = Mojo::SQLite::PubSub->new(sqlite => shift); - weaken $pubsub->{sqlite}; - return $pubsub; -}; +has 'parent'; sub new { @_ > 1 ? shift->SUPER::new->from_string(@_) : shift->SUPER::new } -sub db { $_[0]->database_class->new(dbh => $_[0]->_dequeue, sqlite => $_[0]) } +sub db { $_[0]->database_class->new(dbh => $_[0]->_prepare, sqlite => $_[0]) } sub from_filename { shift->from_string(_url_from_file(shift, shift)) } sub from_string { my ($self, $str) = @_; return $self unless $str; + return $self->parent($str) if blessed $str and $str->isa('Mojo::SQLite'); + my $url = URI->new($str); # Options @@ -96,9 +93,6 @@ $weakdbh->{private_mojo_last_insert_id} = $_[3] if $_[0] == DBD::SQLite::INSERT; }); - # Automatic migrations - ++$self->{migrated} and $self->migrations->migrate - if !$self->{migrated} && $self->auto_migrate; $self->emit(connection => $dbh); return $dbh; @@ -106,11 +100,25 @@ sub _enqueue { my ($self, $dbh) = @_; + + if (my $parent = $self->parent) { return $parent->_enqueue($dbh) } + my $queue = $self->{queue} ||= []; push @$queue, $dbh if $dbh->{Active}; shift @$queue while @$queue > $self->max_connections; } +sub _prepare { + my $self = shift; + + # Automatic migrations + ++$self->{migrated} and $self->migrations->migrate + if !$self->{migrated} && $self->auto_migrate; + + my $parent = $self->parent; + return $parent ? $parent->_prepare : $self->_dequeue; +} + sub _tempfile { catfile(shift->{tempdir} = File::Temp->newdir, 'sqlite.db') } sub _url_from_file { @@ -184,7 +192,9 @@ L<Mojo::SQLite> is a tiny wrapper around L<DBD::SQLite> that makes L<SQLite|https://www.sqlite.org/> a lot of fun to use with the -L<Mojolicious|https://mojolico.us> real-time web framework. +L<Mojolicious|https://mojolico.us> real-time web framework. Use all +L<SQL features|http://sqlite.org/lang.html> SQLite has to offer, generate CRUD +queries from data structures, and manage your database schema with migrations. Database and statement handles are cached automatically, so they can be reused transparently to increase performance. And you can handle connection timeouts @@ -216,7 +226,9 @@ journal is enabled for all connections, allowing multiple processes to read and write concurrently to the same database file (but only one can write at a time). You can prevent this mode from being enabled by passing the option -C<no_wal>. See L<http://sqlite.org/wal.html> for more information. +C<no_wal>, but note that this is incompatible with SQLite databases that have +already had WAL mode enabled. See L<http://sqlite.org/wal.html> and +L<DBD::SQLite/"journal_mode"> for more information. # Performed concurrently my $pid = fork || die $!; @@ -251,7 +263,7 @@ =head1 EXAMPLES This distribution also contains a well-structured example -L<blog application|https://github.com/kraih/mojo-pg/tree/master/examples/blog> +L<blog application|https://github.com/Grinnz/Mojo-SQLite/tree/master/examples/blog> you can use for inspiration. This application shows how to apply the MVC design pattern in practice. @@ -291,7 +303,7 @@ $sql = $sql->auto_migrate($bool); Automatically migrate to the latest database schema with L</"migrations">, as -soon as the first database connection has been established. +soon as L</"db"> has been called for the first time. =head2 database_class @@ -315,7 +327,7 @@ $sql = $sql->max_connections(3); Maximum number of idle database handles to cache for future use, defaults to -C<5>. +C<1>. =head2 migrations @@ -341,9 +353,13 @@ L<DBD::SQLite/"DRIVER PRIVATE ATTRIBUTES"> for more information on available options. -=head2 pubsub +=head2 parent + + my $parent = $sql->parent; + $sql = $sql->parent(Mojo::SQLite->new); -This attribute is L<DEPRECATED|Mojo::SQLite::PubSub/"DESCRIPTION">. +Another L<Mojo::SQLite> object to use for connection management, instead of +establishing and caching our own database connections. =head1 METHODS @@ -355,6 +371,7 @@ my $sql = Mojo::SQLite->new; my $sql = Mojo::SQLite->new('file:test.db); my $sql = Mojo::SQLite->new('sqlite:test.db'); + my $sql = Mojo::SQLite->new(Mojo::SQLite->new); Construct a new L<Mojo::SQLite> object and parse connection string with L</"from_string"> if necessary. @@ -412,15 +429,17 @@ $sql = $sql->from_string('file:test.db'); $sql = $sql->from_string('file:///C:/foo/bar.db'); $sql = $sql->from_string('sqlite:C:%5Cfoo%5Cbar.db'); + $sql = $sql->from_string(Mojo::SQLite->new); -Parse configuration from connection string. Connection strings are parsed as -URLs, so you should construct them using a module like L<Mojo::URL>, -L<URI::file>, or L<URI::db>. For portability on non-Unix-like systems, either -construct the URL with the C<sqlite> scheme, or use L<URI::file/"new"> to -construct a URL with the C<file> scheme. A URL with no scheme will be parsed as -a C<file> URL, and C<file> URLs are parsed according to the current operating -system. If specified, the hostname must be C<localhost>. If the URL has a query -string, it will be parsed and applied to L</"options">. +Parse configuration from connection string or use another L<Mojo::SQLite> +object as L</"parent">. Connection strings are parsed as URLs, so you should +construct them using a module like L<Mojo::URL>, L<URI::file>, or L<URI::db>. +For portability on non-Unix-like systems, either construct the URL with the +C<sqlite> scheme, or use L<URI::file/"new"> to construct a URL with the C<file> +scheme. A URL with no scheme will be parsed as a C<file> URL, and C<file> URLs +are parsed according to the current operating system. If specified, the +hostname must be C<localhost>. If the URL has a query string, it will be parsed +and applied to L</"options">. # Absolute filename $sql->from_string('sqlite:////home/fred/data.db'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/t/00-report-prereqs.dd new/Mojo-SQLite-3.000/t/00-report-prereqs.dd --- old/Mojo-SQLite-2.002/t/00-report-prereqs.dd 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/t/00-report-prereqs.dd 2017-07-20 07:16:52.000000000 +0200 @@ -18,7 +18,7 @@ 'DBI' => '1.627', 'File::Spec::Functions' => '0', 'File::Temp' => '0', - 'Mojolicious' => '7.15', + 'Mojolicious' => '7.32', 'SQL::Abstract' => '1.81', 'Scalar::Util' => '0', 'URI' => '1.69', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/t/database.t new/Mojo-SQLite-3.000/t/database.t --- old/Mojo-SQLite-2.002/t/database.t 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/t/database.t 2017-07-20 07:16:52.000000000 +0200 @@ -88,7 +88,7 @@ # Connection cache { - is $sql->max_connections, 5, 'right default'; + is $sql->max_connections, 1, 'right default'; my @dbhs = map { $_->dbh } $sql->db, $sql->db, $sql->db, $sql->db, $sql->db; is_deeply \@dbhs, [map { $_->dbh } $sql->db, $sql->db, $sql->db, $sql->db, $sql->db], @@ -195,6 +195,26 @@ $sql->unsubscribe('connection'); } +# Shared connection cache +{ + my $sql2 = Mojo::SQLite->new($sql); + is $sql2->parent, $sql, 'right parent'; + my $dbh = $sql->db->dbh; + is $sql->db->dbh, $dbh, 'same database handle'; + is $sql2->db->dbh, $dbh, 'same database handle'; + is $sql->db->dbh, $dbh, 'same database handle'; + is $sql2->db->dbh, $dbh, 'same database handle'; + my $db = $sql->db; + is_deeply $db->query('select 1 as one')->hashes->to_array, [{one => 1}], + 'right structure'; + $dbh = $db->dbh; + $db->disconnect; + $db = $sql2->db; + is_deeply $db->query('select 1 as one')->hashes->to_array, [{one => 1}], + 'right structure'; + isnt $db->dbh, $dbh, 'different database handle'; +} + # Blocking error eval { $sql->db->query('does_not_exist') }; like $@, qr/does_not_exist.*database\.t/s, 'right error'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/t/migrations.t new/Mojo-SQLite-3.000/t/migrations.t --- old/Mojo-SQLite-2.002/t/migrations.t 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/t/migrations.t 2017-07-20 07:16:52.000000000 +0200 @@ -94,7 +94,7 @@ eval { $sql2->migrations->migrate }; like $@, qr/does_not_exist/, 'right error'; is $sql2->migrations->migrate(3)->active, 3, 'active version is 3'; -is $sql2->migrations->migrate(2)->active, 2, 'active version is 3'; +is $sql2->migrations->migrate(2)->active, 2, 'active version is 2'; is $sql->migrations->active, 0, 'active version is still 0'; is $sql->migrations->migrate->active, 10, 'active version is 10'; is_deeply $sql2->db->query('select * from migration_test_three') @@ -104,8 +104,8 @@ is $sql2->migrations->migrate(0)->active, 0, 'active version is 0'; # Migrate automatically -$sql = Mojo::SQLite->new->from_filename($tempfile); -$sql->migrations->name('migrations_test')->from_string(<<EOF); +my $sql3 = Mojo::SQLite->new->from_filename($tempfile); +$sql3->migrations->name('migrations_test')->from_string(<<'EOF'); -- 5 up create table if not exists migration_test_six (foo text); -- 6 up @@ -115,14 +115,24 @@ -- 6 down delete from migration_test_six; EOF -$sql->auto_migrate(1)->db; -is $sql->migrations->active, 6, 'active version is 6'; -is_deeply $sql->db->query('select * from migration_test_six')->hashes, +$sql3->auto_migrate(1)->db; +is $sql3->migrations->active, 6, 'active version is 6'; +is_deeply $sql3->db->query('select * from migration_test_six')->hashes, [{foo => 'works!'}], 'right structure'; -is $sql->migrations->migrate(5)->active, 5, 'active version is 5'; -is_deeply $sql->db->query('select * from migration_test_six')->hashes, [], +is $sql3->migrations->migrate(5)->active, 5, 'active version is 5'; +is_deeply $sql3->db->query('select * from migration_test_six')->hashes, [], 'right structure'; -is $sql->migrations->migrate(0)->active, 0, 'active version is 0'; +is $sql3->migrations->migrate(0)->active, 0, 'active version is 0'; + +# Migrate automatically with shared connection cache +my $sql4 = Mojo::SQLite->new->from_filename($tempfile); +my $sql5 = Mojo::SQLite->new($sql4); +$sql4->auto_migrate(1)->migrations->name('test1')->from_data; +$sql5->auto_migrate(1)->migrations->name('test3')->from_data; +is_deeply $sql5->db->query('select * from migration_test_four') + ->hashes->to_array, [{test => 10}], 'right structure'; +is_deeply $sql5->db->query('select * from migration_test_six')->hashes->to_array, + [], 'right structure'; # Unknown version eval { $sql->migrations->migrate(23) }; @@ -155,7 +165,7 @@ __DATA__ @@ test1 -- 7 up -create table migration_test_four (test integer)); +create table migration_test_four (test integer); -- 10 up insert into migration_test_four values (10); @@ -163,3 +173,7 @@ @@ test2 -- 2 up create table migration_test_five (test integer); + +@@ test3 +-- 2 up +create table migration_test_six (test integer); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/xt/deprecated/database.t new/Mojo-SQLite-3.000/xt/deprecated/database.t --- old/Mojo-SQLite-2.002/xt/deprecated/database.t 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/xt/deprecated/database.t 1970-01-01 01:00:00.000000000 +0100 @@ -1,87 +0,0 @@ -use Mojo::Base -strict; - -BEGIN { $ENV{MOJO_REACTOR} = 'Mojo::Reactor::Poll' } - -use Test::More; -use Mojo::SQLite; -use Mojo::IOLoop; - -# Connected -my $sql = Mojo::SQLite->new; - -# Notifications -{ - my $db = $sql->db->notification_poll_interval(0.1); - ok !$db->is_listening, 'not listening'; - ok $db->listen('dbtest')->is_listening, 'listening'; - my $db2 = $sql->db->notification_poll_interval(0.1)->listen('dbtest'); - my @notifications; - Mojo::IOLoop->delay( - sub { - my $delay = shift; - $db->once(notification => $delay->begin); - $db2->once(notification => $delay->begin); - Mojo::IOLoop->next_tick(sub { $db2->notify(dbtest => 'foo') }); - }, - sub { - my ($delay, $name, $payload, $name2, $payload2) = @_; - push @notifications, [$name, $payload], [$name2, $payload2]; - $db->once(notification => $delay->begin); - $db2->unlisten('dbtest'); - Mojo::IOLoop->next_tick(sub { $sql->db->notify('dbtest') }); - }, - sub { - my ($delay, $name, $payload) = @_; - push @notifications, [$name, $payload]; - $db2->listen('dbtest2')->once(notification => $delay->begin); - Mojo::IOLoop->next_tick(sub { $db2->notify(dbtest2 => 'bar') }); - }, - sub { - my ($delay, $name, $payload) = @_; - push @notifications, [$name, $payload]; - $db2->once(notification => $delay->begin); - my $tx = $db2->begin; - Mojo::IOLoop->next_tick( - sub { - $db2->notify(dbtest2 => 'baz'); - $tx->commit; - } - ); - }, - sub { - my ($delay, $name, $payload) = @_; - push @notifications, [$name, $payload]; - } - )->wait; - ok !$db->unlisten('dbtest')->is_listening, 'not listening'; - ok !$db2->unlisten('*')->is_listening, 'not listening'; - is $notifications[0][0], 'dbtest', 'right channel name'; - is $notifications[0][1], 'foo', 'right payload'; - is $notifications[1][0], 'dbtest', 'right channel name'; - is $notifications[1][1], 'foo', 'right payload'; - is $notifications[2][0], 'dbtest', 'right channel name'; - is $notifications[2][1], '', 'no payload'; - is $notifications[3][0], 'dbtest2', 'right channel name'; - is $notifications[3][1], 'bar', 'no payload'; - is $notifications[4][0], 'dbtest2', 'right channel name'; - is $notifications[4][1], 'baz', 'no payload'; - is $notifications[5], undef, 'no more notifications'; - - # Stop listening for all notifications - ok !$db->is_listening, 'not listening'; - ok $db->listen('dbtest')->listen('dbtest2')->unlisten('dbtest2')->is_listening, - 'listening'; - ok !$db->unlisten('*')->is_listening, 'not listening'; - - # Connection close while listening for notifications - { - ok $db->listen('dbtest')->is_listening, 'listening'; - my $close = 0; - $db->on(close => sub { $close++ }); - $db->dbh->disconnect; - Mojo::IOLoop->start; - is $close, 1, 'close event has been emitted once'; - } -} - -done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojo-SQLite-2.002/xt/deprecated/pubsub.t new/Mojo-SQLite-3.000/xt/deprecated/pubsub.t --- old/Mojo-SQLite-2.002/xt/deprecated/pubsub.t 2017-06-01 20:16:36.000000000 +0200 +++ new/Mojo-SQLite-3.000/xt/deprecated/pubsub.t 1970-01-01 01:00:00.000000000 +0100 @@ -1,177 +0,0 @@ -use Mojo::Base -strict; - -BEGIN { $ENV{MOJO_REACTOR} = 'Mojo::Reactor::Poll' } - -use Test::More; - -use File::Spec::Functions 'catfile'; -use File::Temp; -use Mojo::IOLoop; -use Mojo::JSON 'true'; -use Mojo::SQLite; -use Scalar::Util 'weaken'; - -my $tempdir = File::Temp->newdir; -my $tempfile = catfile($tempdir, 'test.db'); - -my @all_dbs; -my $on_reconnect = sub { push @all_dbs, pop; weaken $all_dbs[-1]; }; - -# Notifications with event loop -{ - my $sql = Mojo::SQLite->new->from_filename($tempfile); - $sql->pubsub->on(reconnect => $on_reconnect); - my ($db, @all, @test); - $sql->pubsub->poll_interval(0.1)->on(reconnect => sub { $db = pop }); - $sql->pubsub->listen( - pstest => sub { - my ($pubsub, $payload) = @_; - push @test, $payload; - if ($payload eq 'stop') { - Mojo::IOLoop->stop; - } else { - Mojo::IOLoop->next_tick(sub { $pubsub->sqlite->db->notify(pstest => 'stop') }); - } - } - ); - is $db->notification_poll_interval, 0.1, 'set notification poll interval'; - $db->on(notification => sub { push @all, [@_[1, 2]] }); - $sql->db->notify(pstest => '♥test♥'); - Mojo::IOLoop->start; - is_deeply \@test, ['♥test♥', 'stop'], 'right messages'; - is_deeply \@all, [['pstest', '♥test♥'], ['pstest', 'stop']], - 'right notifications'; -} - -# JSON -{ - my $sql = Mojo::SQLite->new->from_filename($tempfile)->max_connections(1); - $sql->pubsub->on(reconnect => $on_reconnect); - my (@json, @raw); - $sql->pubsub->poll_interval(0.1)->json('pstest')->listen( - pstest => sub { - my ($pubsub, $payload) = @_; - push @json, $payload; - Mojo::IOLoop->stop if ref $payload eq 'HASH' && $payload->{msg} eq 'stop'; - } - ); - $sql->pubsub->listen( - pstest2 => sub { - my ($pubsub, $payload) = @_; - push @raw, $payload; - } - ); - Mojo::IOLoop->next_tick( - sub { - $sql->db->notify(pstest => 'fail'); - $sql->pubsub->notify('pstest')->notify(pstest => {msg => '♥works♥'}) - ->notify(pstest => [1, 2, 3])->notify(pstest => true) - ->notify(pstest2 => '♥works♥')->notify(pstest => {msg => 'stop'}); - } - ); - Mojo::IOLoop->start; - is_deeply \@json, - [undef, undef, {msg => '♥works♥'}, [1, 2, 3], true, {msg => 'stop'}], - 'right data structures'; - is_deeply \@raw, ['♥works♥'], 'right messages'; -} - -# Unsubscribe -{ - my $sql = Mojo::SQLite->new->from_filename($tempfile); - $sql->pubsub->on(reconnect => $on_reconnect); - my ($db, @all, @test); - $sql->pubsub->poll_interval(0.1)->on(reconnect => sub { $db = pop }); - my $first = $sql->pubsub->listen(pstest => sub { push @test, pop }); - my $second = $sql->pubsub->listen(pstest => sub { push @test, pop }); - $db->on(notification => sub { push @all, [@_[1, 2]] }); - $sql->pubsub->notify('pstest')->notify(pstest => 'first'); - is_deeply \@test, ['', '', 'first', 'first'], 'right messages'; - is_deeply \@all, [['pstest', ''], ['pstest', 'first']], 'right notifications'; - $sql->pubsub->unlisten(pstest => $first)->notify(pstest => 'second'); - is_deeply \@test, ['', '', 'first', 'first', 'second'], 'right messages'; - is_deeply \@all, [['pstest', ''], ['pstest', 'first'], ['pstest', 'second']], - 'right notifications'; - $sql->pubsub->unlisten(pstest => $second)->notify(pstest => 'third'); - is_deeply \@test, ['', '', 'first', 'first', 'second'], 'right messages'; - is_deeply \@all, [['pstest', ''], ['pstest', 'first'], ['pstest', 'second']], - 'right notifications'; - @all = @test = (); - my $third = $sql->pubsub->listen(pstest => sub { push @test, pop }); - my $fourth = $sql->pubsub->listen(pstest => sub { push @test, pop }); - $sql->pubsub->notify(pstest => 'first'); - is_deeply \@test, ['first', 'first'], 'right messages'; - $sql->pubsub->notify(pstest => 'second'); - is_deeply \@test, ['first', 'first', 'second', 'second'], 'right messages'; - $sql->pubsub->unlisten('pstest')->notify(pstest => 'third'); - is_deeply \@test, ['first', 'first', 'second', 'second'], 'right messages'; -} - -# Reconnect while listening -{ - my $sql = Mojo::SQLite->new->from_filename($tempfile); - $sql->pubsub->on(reconnect => $on_reconnect); - my (@dbhs, @test); - $sql->pubsub->poll_interval(0.1)->on(reconnect => sub { push @dbhs, pop->dbh }); - $sql->pubsub->listen(pstest => sub { push @test, pop }); - ok $dbhs[0], 'database handle'; - is_deeply \@test, [], 'no messages'; - { - $sql->pubsub->on( - reconnect => sub { shift->notify(pstest => 'works'); Mojo::IOLoop->stop }); - $dbhs[0]->disconnect; - Mojo::IOLoop->start; - ok $dbhs[1], 'database handle'; - isnt $dbhs[0], $dbhs[1], 'different database handles'; - is_deeply \@test, ['works'], 'right messages'; - } -} - -# Reconnect while not listening -{ - my $sql = Mojo::SQLite->new->from_filename($tempfile); - $sql->pubsub->on(reconnect => $on_reconnect); - my (@dbhs, @test); - $sql->pubsub->poll_interval(0.1)->on(reconnect => sub { push @dbhs, pop->dbh }); - $sql->pubsub->notify(pstest => 'fail'); - ok $dbhs[0], 'database handle'; - is_deeply \@test, [], 'no messages'; - { - $sql->pubsub->on(reconnect => sub { Mojo::IOLoop->stop }); - $dbhs[0]->disconnect; - Mojo::IOLoop->start; - ok $dbhs[1], 'database handle'; - isnt $dbhs[0], $dbhs[1], 'different database handles'; - $sql->pubsub->listen(pstest => sub { push @test, pop }); - $sql->pubsub->notify(pstest => 'works too'); - is_deeply \@test, ['works too'], 'right messages'; - } -} - -# Fork-safety -{ - my $sql = Mojo::SQLite->new->from_filename($tempfile); - $sql->pubsub->on(reconnect => $on_reconnect); - my (@dbhs, @test); - $sql->pubsub->poll_interval(0.1)->on(reconnect => sub { push @dbhs, pop->dbh }); - $sql->pubsub->listen(pstest => sub { push @test, pop }); - ok $dbhs[0], 'database handle'; - $sql->pubsub->notify(pstest => 'first'); - is_deeply \@test, ['first'], 'right messages'; - { - local $$ = -23; - $sql->pubsub->notify(pstest => 'second'); - ok $dbhs[1], 'database handle'; - isnt $dbhs[0], $dbhs[1], 'different database handles'; - is_deeply \@test, ['first'], 'right messages'; - $sql->pubsub->listen(pstest => sub { push @test, pop }); - $sql->pubsub->notify(pstest => 'third'); - ok !$dbhs[2], 'no database handle'; - is_deeply \@test, ['first', 'third'], 'right messages'; - } -} - -# Make sure nothing is listening -$_->unlisten('*') for grep { defined } @all_dbs; - -done_testing();
