DBIx-Class-Schema-Config-0.001014000755001750001750 014073436536 16207 5ustar00symkatsymkat000000000000README100644001750001750 63414073436536 17133 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014This archive contains the distribution DBIx-Class-Schema-Config, version 0.001014: Manage connection credentials for DBIx::Class::Schema This software is copyright (c) 2011-2021 by Kaitlyn Parkhurst. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. This README file was generated by Dist::Zilla::Plugin::Readme v6.017. Changes100644001750001750 760414073436536 17572 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.0010140.1.14: - Allow Mojo::Pg-like postgresql:// links for schema connect. - Switch from Module::Install to Dist::Zilla. 0.1.13: - Add '.' to @INC so Module::Install continues to work, this time for real. 0.1.12: - Add '.' to @INC so Module::Install continues to work. 0.1.11: - Using dbh_maker in a hash to connect() will not result in connect() passing through your arguments after merging into a single hash. - Using a code ref for the first argument will now result in connect() passing through your arguments as-is. - README.pod symlink replaces pod2markdown use (YAY!) - namespace::clean used to prevent methods from leaking - Merge functionality replaced with Hash::Merge - Additional attributes passed to connect() will now overwrite the loaded configuration file. - Removed Test::MockObject as a dependency - Improved caching layer to prevent stale cache - Changed tests to use the correct password attribute - Updated Documentation 0.1.10: - Introduce a public config() getter to allow access to the loaded Config::Any object. 0.1.9: - Fix perl 5.17 hash randomisation breakage (RT#83309) 0.1.8: - Added class accessor config_files to use Config::Any's load_files method and reduce stat() calls for those who like that kind of thing. - Moved the Config::Any parser to its own private function. - DBIX_CONFIG_DIR environment allows run-time injection of a directory that contains a dbic.* file. 0.1.7: - Use File::HomeDir instead of env, thanks @ Christian Walde - CHANGELOG -> Changes - BSD License -> Perl License - README.pod -> Readme.md - Contributor Addition (Christian Walde) 0.1.6: - Once more with feeling. 0.1.5: - Re-release due to broken MANIFEST.skip and outdated README.pod 0.1.4: - Config::Any added as a requirement - Tests now use the included .perl format (No more YAML::XS requirement) - Tests changed to support DBIx::Class 0.80123 - Document Changes - Linked to tutorial - Added CONTRIBUTOR section - Thanks mst and ribasushi for the constant reviews! - Pushed to CPAN as a stable release 0.1.3: - connect() now handles passing through valid-looking DBI connect structures. - _make_config now checks for $user and $pass to be hashrefs, this adds support for structures like ->connect( 'CONFIG', { hostname => 'db.foo.com' } ); - Added tests to 01_*.t to ensure the new signatures work correctly. - Updated tests in 06_*.t to use ->connect ('CONFIG', { dbname => ":memory:" ) to be more clear, as opposed to riding ->{user} - Updated documentation to reflect the changes to the code, namely the hashref as the second argument, and the statements referring to load_credentials having responsibility to return normal DBI connect structures. - Config::Any is only loaded when it's needed. 0.1.2: - Makefile.PL depends on DBD::SQLite not DBD::SQLite3 - _make_config has a less annoying return - connection() no longer tries to block ->load_credentials, it is load_credential's responsablity to to check for credentials it should allow to fall through. - Added accessor on_credential_load, it provides access to the config structure that load_credentials creates, and expects it as the return. It can be used to make changes to the credentials, such as decrypting passwords from the config file. - A new Schema base was created for testing on_credential_load - New tests added for on_credential_load 0.1.1: - Replace SUPER:: with next::method - Don't call load_credentials unless we're actually going to load some - Move Config::Any into load_credentials to be lazy - Allow handling of a normal hashref, no ->{options} (Should make handling cleaner) - Add Testing schema for integration tests 0.1.0: - Inital Version META.yml100644001750001750 164214073436536 17544 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014--- abstract: 'Manage connection credentials for DBIx::Class::Schema' author: - 'Kaitlyn Parkhurst ' build_requires: DBIx::Class: '0.08100' Data::Dumper: '0' Test::More: '0.42' lib: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.017, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: DBIx-Class-Schema-Config requires: Config::Any: '0.23' DBD::SQLite: '0' DBIx::Class: '0.08100' DBIx::Class::Schema: '0' File::HomeDir: '0' Hash::Merge: '0' Storable: '0' Test::More: '0.42' URI: '0' base: '0' namespace::clean: '0' perl: '5.005' strict: '0' warnings: '0' version: '0.001014' x_generated_by_perl: v5.32.1 x_serialization_backend: 'YAML::Tiny version 1.73' x_spdx_expression: 'Artistic-1.0-Perl OR GPL-1.0-or-later' MANIFEST100644001750001750 140314073436536 17417 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.017. Changes MANIFEST META.yml Makefile.PL README lib/DBIx/Class/Schema/Config.pm t/00_load.t t/01_pass_through.t t/02_load_credentials.t t/03_config_paths.t t/04_integration_test.t t/05_integration_plugin.t t/06_on_credential_load.t t/07_integration_config_files.t t/08_integration_env.t t/09_no_modify_config.t t/etc/config.perl t/etc/dbic.perl t/lib/DBIx/Class/Schema/Config/ConfigFiles.pm t/lib/DBIx/Class/Schema/Config/ConfigFiles/Hash.pm t/lib/DBIx/Class/Schema/Config/ENV.pm t/lib/DBIx/Class/Schema/Config/ENV/Hash.pm t/lib/DBIx/Class/Schema/Config/Plugin.pm t/lib/DBIx/Class/Schema/Config/Plugin/Hash.pm t/lib/DBIx/Class/Schema/Config/Test.pm t/lib/DBIx/Class/Schema/Config/Test/Hash.pm t000755001750001750 014073436536 16373 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.00101400_load.t100644001750001750 37414073436536 20122 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; my @want_modules = qw/ DBI DBIx::Class Hash::Merge namespace::clean DBIx::Class::Schema DBIx::Class::Schema::Config /; use_ok( $_ ) for @want_modules; done_testing(); Makefile.PL100644001750001750 332514073436536 20245 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.017. use strict; use warnings; use 5.005; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "Manage connection credentials for DBIx::Class::Schema", "AUTHOR" => "Kaitlyn Parkhurst ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "DBIx-Class-Schema-Config", "LICENSE" => "perl", "MIN_PERL_VERSION" => "5.005", "NAME" => "DBIx::Class::Schema::Config", "PREREQ_PM" => { "Config::Any" => "0.23", "DBD::SQLite" => 0, "DBIx::Class" => "0.08100", "DBIx::Class::Schema" => 0, "File::HomeDir" => 0, "Hash::Merge" => 0, "Storable" => 0, "Test::More" => "0.42", "URI" => 0, "base" => 0, "namespace::clean" => 0, "strict" => 0, "warnings" => 0 }, "TEST_REQUIRES" => { "DBIx::Class" => "0.08100", "Data::Dumper" => 0, "Test::More" => "0.42", "lib" => 0 }, "VERSION" => "0.001014", "test" => { "TESTS" => "t/*.t" } ); my %FallbackPrereqs = ( "Config::Any" => "0.23", "DBD::SQLite" => 0, "DBIx::Class" => "0.08100", "DBIx::Class::Schema" => 0, "Data::Dumper" => 0, "File::HomeDir" => 0, "Hash::Merge" => 0, "Storable" => 0, "Test::More" => "0.42", "URI" => 0, "base" => 0, "lib" => 0, "namespace::clean" => 0, "strict" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); etc000755001750001750 014073436536 17146 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/tdbic.perl100644001750001750 45214073436536 21054 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/etc{ "TEST" => { "dsn" => "dbi:SQLite:dbname=:memory:", "user" => "", "password" => "", }, "PLUGIN" => { "dsn" => "dbi:SQLite:dbname=%s", "user" => "", "password" => "", }, } config.perl100644001750001750 45214073436536 21420 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/etc{ "TEST" => { "dsn" => "dbi:SQLite:dbname=:memory:", "user" => "", "password" => "", }, "PLUGIN" => { "dsn" => "dbi:SQLite:dbname=%s", "user" => "", "password" => "", }, } 01_pass_through.t100644001750001750 520414073436536 21727 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use DBIx::Class::Schema::Config; my $tests = [ { put => { dsn => 'dbi:mysql:somedb', user => 'username', password => 'password', }, get => { dsn => 'dbi:mysql:somedb', user => 'username', password => 'password', }, title => "Hashref connections work.", }, { put => [ 'dbi:mysql:somedb', 'username', 'password' ], get => { dsn => 'dbi:mysql:somedb', user => 'username', password => 'password', }, title => "Array connections work.", }, { put => [ 'DATABASE' ], get => { dsn => 'DATABASE', user => undef, password => undef }, title => "DSN gets the first element name.", }, { put => [ 'dbi:mysql:somedb', 'username', 'password', { PrintError => 1 } ], get => { dsn => 'dbi:mysql:somedb', user => 'username', password => 'password', PrintError => 1, }, title => "Normal option hashes pass through.", }, { put => [ 'DATABASE', 'USERNAME', { hostname => 'hostname' } ], get => { dsn => 'DATABASE', user => 'USERNAME', hostname => 'hostname' }, title => "Ensure (string, string, hashref) format works correctly.", }, { put => [ 'DATABASE', 'USERNAME', 'PASSWORD', { hostname => 'hostname' } ], get => { dsn => 'DATABASE', user => 'USERNAME', password => 'PASSWORD', hostname => 'hostname' }, title => "Ensure (string, string, string, hashref) format works correctly.", }, { put => [ 'DATABASE', 'U', 'P', { foo => "bar" }, { hostname => 'hostname' } ], get => { dsn => 'DATABASE', user => 'U', password => 'P', foo => "bar", hostname => 'hostname' }, title => "Ensure (string, string, string, hashref, hashref) format works correctly.", }, { put => [ 'postgresql://username:password@hostname/minion' ], get => { dsn => 'postgresql://username:password@hostname/minion', user => undef, password => undef, }, title => "Mojo-like postgresql:// lines pass through.", }, ]; for my $test ( @$tests ) { is_deeply( DBIx::Class::Schema::Config->_make_connect_attrs( ref $test->{put} eq 'ARRAY' ? @{$test->{put}} : $test->{put} ), $test->{get}, $test->{title} ); } done_testing; 03_config_paths.t100644001750001750 71414073436536 21650 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use base 'DBIx::Class::Schema::Config'; use File::HomeDir; is_deeply( __PACKAGE__->config_paths, [ './dbic', File::HomeDir->my_home . "/.dbic", "/etc/dbic" ], "_config_paths looks sane."); __PACKAGE__->config_paths( [ ( './this', '/var/www/that' ) ] ); is_deeply( __PACKAGE__->config_paths, [ './this', '/var/www/that' ], "_config_paths can be modified."); done_testing; 08_integration_env.t100644001750001750 401314073436536 22420 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use lib 't/lib'; # Tests above t/ use lib 'lib'; # Tests inside t/ # This test requires that the environment # variable is set at the DB's compile time, # as it would if you ran # $ DBIX_CONFIG_DIR="t/etc/" prove t/08* BEGIN { $ENV{'DBIX_CONFIG_DIR'} = "t/etc/"; require DBIx::Class::Schema::Config::ENV; DBIx::Class::Schema::Config::ENV->import(); } # Using a config file. ok my $Schema1 = DBIx::Class::Schema::Config::ENV->connect('TEST'), "Can connect to the Test Schema."; ok $Schema1->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema1->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema1->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of array. ok my $Schema2 = DBIx::Class::Schema::Config::ENV->connect('dbi:SQLite:dbname=:memory:', '', ''), "Can connect to the Test Schema."; ok $Schema2->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema2->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema2->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of hash ok my $Schema3 = DBIx::Class::Schema::Config::ENV->connect({ dsn => 'dbi:SQLite:dbname=:memory:' }), "Can connect to the Test Schema."; ok $Schema3->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema3->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema3->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; done_testing; 09_no_modify_config.t100644001750001750 321114073436536 22535 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use DBIx::Class::Schema::Config; { package Config::Any; $INC{"Config/Any.pm"} = __FILE__; sub load_stems { return [ { 'some_file' => { SOME_DATABASE => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'MyUser', password => 'MyPass', }, AWESOME_DB => { dsn => 'dbi:mysql:dbname=epsilon', user => 'Bravo', password => 'ShiJulIanDav', }, OPTIONS => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Happy', password => 'User', TRACE_LEVEL => 5, } }, }, { 'some_other_file' => { SOME_DATABASE => { dsn => 'dbi:mysql:dbname=acronym', user => 'YawnyPants', password => 'WhyDoYouHateUs?', }, }, } ] } } ok my $ref = DBIx::Class::Schema::Config->config; is_deeply( $ref, "Config::Any"->load_stems, "Loaded correct data set." ); is $ref->[0]->{some_file} = undef, undef, "Changed reference returned by config."; is_deeply( DBIx::Class::Schema::Config->config, "Config::Any"->load_stems, "Changes to a ref of ::config's return does not change future invocations." ); done_testing; 04_integration_test.t100644001750001750 707114073436536 22612 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use lib 't/lib'; # Tests above t/ use lib 'lib'; # Tests inside t/ use DBIx::Class::Schema::Config::Test; # Using a config file. my $expected_config = [ { 't/etc/config.perl' => { 'TEST' => { 'password' => '', 'dsn' => 'dbi:SQLite:dbname=:memory:', 'user' => '' }, 'PLUGIN' => { 'password' => '', 'dsn' => 'dbi:SQLite:dbname=%s', 'user' => '' } } } ]; is_deeply(DBIx::Class::Schema::Config::Test->config, $expected_config, 'config from class accessor matches as expected - loaded before connect'); ok my $Schema1 = DBIx::Class::Schema::Config::Test->connect('TEST'), "Can connect to the Test Schema."; ok $Schema1->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema1->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema1->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of array. ok my $Schema2 = DBIx::Class::Schema::Config::Test->connect('dbi:SQLite:dbname=:memory:', '', ''), "Can connect to the Test Schema."; ok $Schema2->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema2->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema2->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of hash ok my $Schema3 = DBIx::Class::Schema::Config::Test->connect({ dsn => 'dbi:SQLite:dbname=:memory:' }), "Can connect to the Test Schema."; ok $Schema3->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema3->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema3->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of code reference. ok my $Schema4 = DBIx::Class::Schema::Config::Test->connect( sub { DBI->connect( 'dbi:SQLite:dbname=:memory:', undef, undef, { RaiseError => 1 } ) } ), "Can connect to the Test Schema."; ok $Schema4->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema4->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema4->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # dbh_maker functions as one would expect. ok my $Schema5 = DBIx::Class::Schema::Config::Test->connect({ dbh_maker => sub { DBI->connect( 'dbi:SQLite:dbname=:memory:', undef, undef, { RaiseError => 1 } ) }, }), "Can connect to the Test Schema."; ok $Schema5->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema5->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema5->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; done_testing; 02_load_credentials.t100644001750001750 1625614073436536 22547 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use DBIx::Class::Schema::Config; { package Config::Any; $INC{"Config/Any.pm"} = __FILE__; sub load_stems { return [ { 'some_file' => { SOME_DATABASE => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'MyUser', password => 'MyPass', }, AWESOME_DB => { dsn => 'dbi:mysql:dbname=epsilon', user => 'Bravo', password => 'ShiJulIanDav', }, OPTIONS => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Happy', password => 'User', TRACE_LEVEL => 5, } }, }, { 'some_other_file' => { SOME_DATABASE => { dsn => 'dbi:mysql:dbname=acronym', user => 'YawnyPants', password => 'WhyDoYouHateUs?', }, }, } ] } } my $tests = [ { put => { dsn => 'SOME_DATABASE', user => '', password => '' }, get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'MyUser', password => 'MyPass', }, title => "Get DB info from hashref.", }, { put => [ 'SOME_DATABASE' ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'MyUser', password => 'MyPass', }, title => "Get DB info from array.", }, { put => { dsn => 'AWESOME_DB' }, get => { dsn => 'dbi:mysql:dbname=epsilon', user => 'Bravo', password => 'ShiJulIanDav', }, title => "Get DB from hashref without user and pass.", }, { put => [ 'dbi:mysql:dbname=foo', 'username', 'password' ], get => { dsn => 'dbi:mysql:dbname=foo', user => 'username', password => 'password', }, title => "Pass through of normal ->connect as array.", }, { put => { dsn => 'dbi:mysql:dbname=foo', user => 'username', password => 'password' }, get => { dsn => 'dbi:mysql:dbname=foo', user => 'username', password => 'password', }, title => "Pass through of normal ->connect as hashref.", }, { put => [ 'OPTIONS' ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Happy', password => 'User', TRACE_LEVEL => 5, }, title => "Default loading", }, { put => [ 'OPTIONS', undef, undef, { TRACE_LEVEL => 10 } ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Happy', password => 'User', TRACE_LEVEL => 10, }, title => "Override of replaced key works.", }, { put => [ 'OPTIONS', undef, undef, { TRACE_LEVEL => 10, MAGIC => 1 } ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Happy', password => 'User', TRACE_LEVEL => 10, MAGIC => 1, }, title => "Override for non-replaced key works.", }, { put => [ 'OPTIONS', { TRACE_LEVEL => 10, MAGIC => 1 } ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Happy', password => 'User', TRACE_LEVEL => 10, MAGIC => 1, }, title => "Override for non-replaced key works, without undefing", }, { put => [ 'OPTIONS', "Foobar", undef, { TRACE_LEVEL => 10 } ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Foobar', password => 'User', TRACE_LEVEL => 10, }, title => "Overriding the username works.", }, { put => [ 'OPTIONS', "Foobar", { TRACE_LEVEL => 10 } ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Foobar', password => 'User', TRACE_LEVEL => 10, }, title => "Overriding the username works without undefing password.", }, { put => [ 'OPTIONS', undef, "Foobar", { TRACE_LEVEL => 10 } ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'Happy', password => 'Foobar', TRACE_LEVEL => 10, }, title => "Overriding the password works.", }, { put => [ 'OPTIONS', "BleeBaz", "Foobar", { TRACE_LEVEL => 10 } ], get => { dsn => 'dbi:SQLite:dbfile=:memory:', user => 'BleeBaz', password => 'Foobar', TRACE_LEVEL => 10, }, title => "Overriding the user and password works.", }, # Mojo-like postgresql connection lines. { put => [ 'postgresql://username:password@hostname:5433/minion' ], get => { dsn => 'dbi:Pg:dbname=minion;host=hostname;port=5433', user => 'username', password => 'password', }, title => "Mojo-like postgresql:// connect line, with port.", }, { put => [ 'postgresql://username:password@hostname/minion' ], get => { dsn => 'dbi:Pg:dbname=minion;host=hostname', user => 'username', password => 'password', }, title => "Mojo-like postgresql:// connect line.", }, { put => [ 'postgresql://:password@hostname/minion' ], get => { dsn => 'dbi:Pg:dbname=minion;host=hostname', user => '', password => 'password', }, title => "Mojo-like postgresql:// connect line, no user.", }, { put => [ 'postgresql://username:@hostname/minion' ], get => { dsn => 'dbi:Pg:dbname=minion;host=hostname', user => 'username', password => '', }, title => "Mojo-like postgresql:// connect line, no password.", }, { put => [ 'postgresql://username@hostname/minion' ], get => { dsn => 'dbi:Pg:dbname=minion;host=hostname', user => 'username', password => '', }, title => "Mojo-like postgresql:// connect line, ambiguous user@ is username.", }, { put => [ 'postgresql://hostname/minion' ], get => { dsn => 'dbi:Pg:dbname=minion;host=hostname', user => '', password => '', }, title => "Mojo-like postgresql:// connect line, no credentials.", }, ]; for my $test ( @$tests ) { is_deeply( DBIx::Class::Schema::Config->load_credentials( DBIx::Class::Schema::Config->_make_connect_attrs( ref $test->{put} eq 'ARRAY' ? @{$test->{put}} : $test->{put}) ), $test->{get}, $test->{title} ); } done_testing; 06_on_credential_load.t100644001750001750 115314073436536 23032 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use lib 't/lib'; # Tests above t/ use lib 'lib'; # Tests inside t/ use DBIx::Class::Schema::Config::Plugin; use Data::Dumper; # Using a config file, with a plugin changing the DSN. ok my $Schema = DBIx::Class::Schema::Config::Plugin->connect('PLUGIN', { dbname => ':memory:' }), "Connection to a plugin-modified schema works."; my $expect = [ { password => '', user => '', dsn => 'dbi:SQLite:dbname=:memory:' } ]; is_deeply $Schema->storage->connect_info, $expect, "Expected schema changes happened."; done_testing; 05_integration_plugin.t100644001750001750 344314073436536 23131 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use lib 't/lib'; # Tests above t/ use lib 'lib'; # Tests inside t/ use DBIx::Class::Schema::Config::Plugin; # Using a config file. ok my $Schema1 = DBIx::Class::Schema::Config::Plugin->connect('TEST'), "Can connect to the Test Schema."; ok $Schema1->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema1->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema1->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of array. ok my $Schema2 = DBIx::Class::Schema::Config::Plugin->connect('dbi:SQLite:dbname=:memory:', '', ''), "Can connect to the Test Schema."; ok $Schema2->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema2->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema2->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of hash ok my $Schema3 = DBIx::Class::Schema::Config::Plugin->connect({ dsn => 'dbi:SQLite:dbname=:memory:' }), "Can connect to the Test Schema."; ok $Schema3->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema3->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema3->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; done_testing; 07_integration_config_files.t100644001750001750 346714073436536 24272 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t#!/usr/bin/perl use warnings; use strict; use Test::More; use lib 't/lib'; # Tests above t/ use lib 'lib'; # Tests inside t/ use DBIx::Class::Schema::Config::ConfigFiles; # Using a config file. ok my $Schema1 = DBIx::Class::Schema::Config::ConfigFiles->connect('TEST'), "Can connect to the Test Schema."; ok $Schema1->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema1->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema1->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of array. ok my $Schema2 = DBIx::Class::Schema::Config::ConfigFiles->connect('dbi:SQLite:dbname=:memory:', '', ''), "Can connect to the Test Schema."; ok $Schema2->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema2->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema2->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; # Pass through of hash ok my $Schema3 = DBIx::Class::Schema::Config::ConfigFiles->connect({ dsn => 'dbi:SQLite:dbname=:memory:' }), "Can connect to the Test Schema."; ok $Schema3->storage->dbh->do( "CREATE TABLE hash ( key text, value text )" ), "Can create table against the raw dbh."; ok $Schema3->resultset('Hash')->create( { key => "Dr", value => "Spaceman" } ), "Can write to the Test Schema."; is $Schema3->resultset('Hash')->find( { key => 'Dr' }, { key => 'key_unique' } )->value, 'Spaceman', "Can read from the Test Schema."; done_testing; Schema000755001750001750 014073436536 21731 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/lib/DBIx/ClassConfig.pm100644001750001750 3376314073436536 23670 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/lib/DBIx/Class/Schemapackage DBIx::Class::Schema::Config; use 5.005; use warnings; use strict; use base 'DBIx::Class::Schema'; use File::HomeDir; use Storable qw( dclone ); use Hash::Merge qw( merge ); use namespace::clean; use URI; our $VERSION = '0.001014'; # 0.1.14 $VERSION = eval $VERSION; sub connection { my ( $class, @info ) = @_; if ( ref($info[0]) eq 'CODE' ) { return $class->next::method( @info ); } my $attrs = $class->_make_connect_attrs(@info); # We will not load credentials for someone who uses dbh_maker, # however we will pass their request through. return $class->next::method( $attrs ) if defined $attrs->{dbh_maker}; # Take responsibility for passing through normal-looking # credentials. $attrs = $class->load_credentials($attrs) unless $attrs->{dsn} =~ /^dbi:/i; return $class->next::method( $attrs ); } sub coerce_credentials_from_mojolike { my ( $class, $attrs ) = @_; (my $in = $attrs->{dsn}) =~ s/^postgresql/http/; my $url = URI->new( $in ); my $db = ($url->path_segments)[1]; my $dsn = defined $db ? "dbi:Pg:dbname=$db" : 'dbi:Pg:'; $dsn .= ";host=" . $url->host if $url->host; $dsn .= ";port=" . $url->port if $url->port and $url->port != 80; $attrs->{dsn} = $dsn; # Set user & password, default to '', # then use $url->userinfo, like so: # # user@ -> username, '' # user:@ -> username, '' # :password@ -> '', password ($attrs->{user}, $attrs->{password}) = ('', ''); if ( $url->userinfo ) { my ( $user, $password ) = split /:/, $url->userinfo, 2; $attrs->{user} = $user; $attrs->{password} = $password || ''; } return $attrs; } # Normalize arguments into a single hash. If we get a single hashref, # return it. # Check if $user and $pass are hashes to support things like # ->connect( 'CONFIG_FILE', { hostname => 'db.foo.com' } ); sub _make_connect_attrs { my ( $class, $dsn, $user, $pass, $dbi_attr, $extra_attr ) = @_; return $dsn if ref $dsn eq 'HASH'; return { dsn => $dsn, %{ref $user eq 'HASH' ? $user : { user => $user }}, %{ref $pass eq 'HASH' ? $pass : { password => $pass }}, %{$dbi_attr || {} }, %{ $extra_attr || {} } }; } # Cache the loaded configuration. sub config { my ( $class ) = @_; if ( ! $class->_config ) { $class->_config( $class->_load_config ); } return dclone( $class->_config ); } sub _load_config { my ( $class ) = @_; require Config::Any; # Only loaded if we need to load credentials. # If we have ->config_files, we'll use those and load_files # instead of the default load_stems. my %cf_opts = ( use_ext => 1 ); return @{$class->config_files} ? Config::Any->load_files({ files => $class->config_files, %cf_opts }) : Config::Any->load_stems({ stems => $class->config_paths, %cf_opts }); } sub load_credentials { my ( $class, $connect_args ) = @_; # Handle mojo-like postgres:// urls return $class->coerce_credentials_from_mojolike($connect_args) if $connect_args->{dsn} =~ /^postgresql:/i; # While ->connect is responsible for returning normal-looking # credential information, we do it here as well so that it can be # independently unit tested. return $connect_args if $connect_args->{dsn} =~ /^dbi:/i; return $class->filter_loaded_credentials( $class->_find_credentials( $connect_args, $class->config ), $connect_args ); } # This will look through the data structure returned by Config::Any # and return the first instance of the database credentials it can # find. sub _find_credentials { my ( $class, $connect_args, $ConfigAny ) = @_; for my $cfile ( @$ConfigAny ) { for my $filename ( keys %$cfile ) { for my $database ( keys %{$cfile->{$filename}} ) { if ( $database eq $connect_args->{dsn} ) { return $cfile->{$filename}->{$database}; } } } } } sub get_env_vars { return $ENV{DBIX_CONFIG_DIR} . "/dbic" if exists $ENV{DBIX_CONFIG_DIR}; return (); } # Intended to be sub-classed, the default behavior is to # overwrite the loaded configuration with any specified # configuration from the connect() call, with the exception # of the DSN itself. sub filter_loaded_credentials { my ( $class, $new, $old ) = @_; local $old->{password}, delete $old->{password} unless $old->{password}; local $old->{user}, delete $old->{user} unless $old->{user}; local $old->{dsn}, delete $old->{dsn}; return merge( $old, $new ); }; __PACKAGE__->mk_classaccessor('config_paths'); __PACKAGE__->mk_classaccessor('config_files'); __PACKAGE__->mk_classaccessor('_config'); __PACKAGE__->config_paths([( get_env_vars(), './dbic', File::HomeDir->my_home . '/.dbic', '/etc/dbic')]); __PACKAGE__->config_files([ ] ); 1; =encoding UTF-8 =head1 NAME DBIx::Class::Schema::Config - Credential Management for DBIx::Class =head1 DESCRIPTION DBIx::Class::Schema::Config is a subclass of DBIx::Class::Schema that allows the loading of credentials & configuration from a file. The actual code itself would only need to know about the name used in the configuration file. This aims to make it simpler for operations teams to manage database credentials. A simple tutorial that compliments this documentation and explains converting an existing DBIx::Class Schema to use this software to manage credentials can be found at L =head1 SYNOPSIS /etc/dbic.yaml MY_DATABASE: dsn: "dbi:Pg:host=localhost;database=blog" user: "TheDoctor" password: "dnoPydoleM" TraceLevel: 1 package My::Schema use warnings; use strict; use base 'DBIx::Class::Schema::Config'; __PACKAGE__->load_namespaces; package My::Code; use warnings; use strict; use My::Schema; my $schema = My::Schema->connect('MY_DATABASE'); # arbitrary config access from anywhere in your $app my $level = My::Schema->config->{TraceLevel}; =head1 CONFIG FILES This module will load the files in the following order if they exist: =over 4 =item * C<$ENV{DBIX_CONFIG_DIR}> . '/dbic', C<$ENV{DBIX_CONFIG_DIR}> can be configured at run-time, for instance: DBIX_CONFIG_DIR="/var/local/" ./my_program.pl =item * ./dbic.* =item * ~/.dbic.* =item * /etc/dbic.* =back The files should have an extension that L recognizes, for example /etc/dbic.B. NOTE: The first available credential will be used. Therefore I in ~/.dbic.yaml will only be looked at if it was not found in ./dbic.yaml. If there are duplicates in one file (such that DATABASE is listed twice in ~/.dbic.yaml,) the first configuration will be used. =head1 CHANGE CONFIG PATH Use C<__PACKAGE__-Econfig_paths([( '/file/stub', '/var/www/etc/dbic')]);> to change the paths that are searched. For example: package My::Schema use warnings; use strict; use base 'DBIx::Class::Schema::Config'; __PACKAGE__->config_paths([( '/var/www/secret/dbic', '/opt/database' )]); The above code would have I and I searched, in that order. As above, the first credentials found would be used. This will replace the files originally searched for, not add to them. =head1 USE SPECIFIC CONFIG FILES If you would rather explicitly state the configuration files you want loaded, you can use the class accessor C instead. package My::Schema use warnings; use strict; use base 'DBIx::Class::Schema::Config'; __PACKAGE__->config_files([( '/var/www/secret/dbic.yaml', '/opt/database.yaml' )]); This will check the files, C, and C in the same way as C, however it will only check the specific files, instead of checking for each extension that L supports. You MUST use the extension that corresponds to the file type you are loading. See L for information on supported file types and extension mapping. =head1 ACCESSING THE CONFIG FILE The config file is stored via the C<__PACKAGE__-Econfig> accessor, which can be called as both a class and instance method. =head1 OVERRIDING The API has been designed to be simple to override if you have additional needs in loading DBIC configurations. =head2 Mojo::Pg-Like Connection Strings Calls to connect with L-like URIs are supported. my $schema = My::Schema->connect( 'postgresql://username:password@localhost/dbname' ); =head2 Overriding Connection Configuration Simple cases where one wants to replace specific configuration tokens can be given as extra parameters in the ->connect call. For example, suppose we have the database MY_DATABASE from above: MY_DATABASE: dsn: "dbi:Pg:host=localhost;database=blog" user: "TheDoctor" password: "dnoPydoleM" TraceLevel: 1 If you’d like to replace the username with “Eccleston” and we’d like to turn PrintError off. The following connect line would achieve this: $Schema->connect(“MY_DATABASE”, “Eccleston”, undef, { PrintError => 0 } ); The name of the connection to load from the configuration file is still given as the first argument, while other arguments may be given exactly as you would for any other call to C. Historical Note: This class accepts numerous ways to connect to DBIC that would otherwise not be valid. These connection methods are discouraged but tested for and kept for compatibility with earlier versions. For valid ways of connecting to DBIC please see L =head2 filter_loaded_credentials Override this function if you want to change the loaded credentials before they are passed to DBIC. This is useful for use-cases that include decrypting encrypted passwords or making programmatic changes to the configuration before using it. sub filter_loaded_credentials { my ( $class, $loaded_credentials, $connect_args ) = @_; ... return $loaded_credentials; } C<$loaded_credentials> is the structure after it has been loaded from the configuration file. In this case, C<$loaded_credentials-E{user}> eq B and C<$loaded_credentials-E{dsn}> eq B. C<$connect_args> is the structure originally passed on C<-Econnect()> after it has been turned into a hash. For instance, C<-Econnect('DATABASE', 'USERNAME')> will result in C<$connect_args-E{dsn}> eq B and C<$connect_args-E{user}> eq B. Additional parameters can be added by appending a hashref, to the connection call, as an example, C<-Econnect( 'CONFIG', { hostname =E "db.foo.com" } );> will give C<$connect_args> a structure like C<{ dsn =E 'CONFIG', hostname =E "db.foo.com" }>. For instance, if you want to use hostnames when you make the initial connection to DBIC and are using the configuration primarily for usernames, passwords and other configuration data, you can create a config like the following: DATABASE: dsn: "DBI:mysql:database=students;host=%s;port=3306" user: "WalterWhite" password: "relykS" In your Schema class, you could include the following: package My::Schema use warnings; use strict; use base 'DBIx::Class::Schema::Config'; sub filter_loaded_credentials { my ( $class, $loaded_credentials, $connect_args ) = @_; if ( $loaded_credentials->{dsn} =~ /\%s/ ) { $loaded_credentials->{dsn} = sprintf( $loaded_credentials->{dsn}, $connect_args->{hostname}); } } __PACKAGE__->load_classes; 1; Then the connection could be done with C<$Schema-Econnect('DATABASE', { hostname => 'my.hostname.com' });> See L for more complex changes that require changing how the configuration itself is loaded. =head2 load_credentials Override this function to change the way that L loads credentials. The function takes the class name, as well as a hashref. If you take the route of having C<-Econnect('DATABASE')> used as a key for whatever configuration you are loading, I would be C<$config-E{dsn}> Some::Schema->connect( "SomeTarget", "Yuri", "Yawny", { TraceLevel => 1 } ); Would result in the following data structure as $config in C: { dsn => "SomeTarget", user => "Yuri", password => "Yawny", TraceLevel => 1, } Currently, load_credentials will NOT be called if the first argument to C<-Econnect()> looks like a valid DSN. This is determined by match the DSN with C. The function should return the same structure. For instance: package My::Schema use warnings; use strict; use base 'DBIx::Class::Schema::Config'; use LWP::Simple; use JSON # Load credentials from internal web server. sub load_credentials { my ( $class, $config ) = @_; return decode_json( get( "http://someserver.com/v1.0/database?key=somesecret&db=" . $config->{dsn} )); } __PACKAGE__->load_classes; =head1 AUTHOR Kaitlyn Parkhurst (SymKat) Isymkat@symkat.comE> ( Blog: L ) =head1 CONTRIBUTORS =over 4 =item * Matt S. Trout (mst) Imst@shadowcat.co.ukE> =item * Peter Rabbitson (ribasushi) Iribasushi@cpan.orgE> =item * Christian Walde (Mihtaldu) Iwalde.christian@googlemail.comE> =item * Dagfinn Ilmari Mannsåker (ilmari) Iilmari@ilmari.orgE> =item * Matthew Phillips (mattp) Imattp@cpan.orgE> =back =head1 COPYRIGHT AND LICENSE This library is free software and may be distributed under the same terms as perl itself. =head1 AVAILABILITY The latest version of this software is available at L =cut Config000755001750001750 014073436536 23401 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/SchemaENV.pm100644001750001750 21514073436536 24505 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Configpackage DBIx::Class::Schema::Config::ENV; use strict; use warnings; use base 'DBIx::Class::Schema::Config'; __PACKAGE__->load_classes; 1; Test.pm100644001750001750 30314073436536 24772 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Configpackage DBIx::Class::Schema::Config::Test; use strict; use warnings; use base 'DBIx::Class::Schema::Config'; __PACKAGE__->config_paths( [ ( 't/etc/config' ) ] ); __PACKAGE__->load_classes; 1; Plugin.pm100644001750001750 60414073436536 25315 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Configpackage DBIx::Class::Schema::Config::Plugin; use strict; use warnings; use base 'DBIx::Class::Schema::Config'; __PACKAGE__->config_paths( [ ( 't/etc/config' ) ] ); sub filter_loaded_credentials { my ( $class, $new, $orig ) = @_; if ( $new->{dsn} =~ /\%s/ ) { $new->{dsn} = sprintf($new->{dsn}, $orig->{dbname}); } return $new; } __PACKAGE__->load_classes; 1; ENV000755001750001750 014073436536 24031 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/ConfigHash.pm100644001750001750 74214073436536 25375 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Config/ENVpackage DBIx::Class::Schema::Config::ENV::Hash; use strict; use warnings; use base 'DBIx::Class'; __PACKAGE__->load_components("Core"); __PACKAGE__->table("hash"); __PACKAGE__->add_columns( "key", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, "value", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, ); __PACKAGE__->add_unique_constraint("key_unique", ["key"]); 1; Test000755001750001750 014073436536 24320 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/ConfigHash.pm100644001750001750 74314073436536 25665 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Config/Testpackage DBIx::Class::Schema::Config::Test::Hash; use strict; use warnings; use base 'DBIx::Class'; __PACKAGE__->load_components("Core"); __PACKAGE__->table("hash"); __PACKAGE__->add_columns( "key", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, "value", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, ); __PACKAGE__->add_unique_constraint("key_unique", ["key"]); 1; ConfigFiles.pm100644001750001750 31714073436536 26250 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Configpackage DBIx::Class::Schema::Config::ConfigFiles; use strict; use warnings; use base 'DBIx::Class::Schema::Config'; __PACKAGE__->config_files( [ ( 't/etc/config.perl' ) ] ); __PACKAGE__->load_classes; 1; Plugin000755001750001750 014073436536 24637 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/ConfigHash.pm100644001750001750 74514073436536 26206 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Config/Pluginpackage DBIx::Class::Schema::Config::Plugin::Hash; use strict; use warnings; use base 'DBIx::Class'; __PACKAGE__->load_components("Core"); __PACKAGE__->table("hash"); __PACKAGE__->add_columns( "key", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, "value", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, ); __PACKAGE__->add_unique_constraint("key_unique", ["key"]); 1; ConfigFiles000755001750001750 014073436536 25571 5ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/ConfigHash.pm100644001750001750 75214073436536 27136 0ustar00symkatsymkat000000000000DBIx-Class-Schema-Config-0.001014/t/lib/DBIx/Class/Schema/Config/ConfigFilespackage DBIx::Class::Schema::Config::ConfigFiles::Hash; use strict; use warnings; use base 'DBIx::Class'; __PACKAGE__->load_components("Core"); __PACKAGE__->table("hash"); __PACKAGE__->add_columns( "key", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, "value", { data_type => "text", default_value => undef, is_nullable => 0, size => undef, }, ); __PACKAGE__->add_unique_constraint("key_unique", ["key"]); 1;