NAME

Mojo::mysql::Database::Role::LoadDataInfile - Easy load data infile support for Mojo::mysql

STATUS

SYNOPSIS

use Mojo::mysql;
use Mojo::mysql::Database::Role::LoadDataInfile;

my $mysql   = Mojo::mysql->new(...);
my $results = $mysql->db->load_data_infile(
  table => 'people',
  rows => [
    {
      name => 'Bob',
      age  => 23,
    },
    {
      name => 'Alice',
      age  => 25,
    },
  ],
);

print $results->affected_rows . " affected rows\n";

# use promises for non-blocking queries
my $promise = $mysql->db->load_data_infile_p(
  table => 'people',
  rows => [
    {
      name => 'Bob',
      age  => 23,
    },
    {
      name => 'Alice',
      age  => 25,
    },
  ],
);

$promise->then(sub {
  my $results = shift;
  print $results->affected_rows . " affected rows\n";
})->catch(sub {
  my $err = shift;
  warn "Something went wrong: $err";
});


# apply the LoadDataInfile role to your own database_class
use Mojo::mysql::Database::Role::LoadDataInfile database_class => 'MyApp::Database';

$mysql->database_class('MyApp::Database');
my $results = $mysql->db->load_data_infile(...);


# don't auto apply the role to Mojo::mysql::Database and do it yourself
$mysql->db->with_roles('+LoadDataInfile')->load_data_infile(...);

# or

Role::Tiny->apply_roles_to_package('Mojo::mysql::Database', 'Mojo::mysql::Database::Role::LoadDataInfile');

DESCRIPTION

Mojo::mysql::Database::Role::LoadDataInfile is a role that makes synchronous and asynchronous LOAD DATA INFILE queries easy with your "database_class" in Mojo::mysql.

This module currently only supports LOAD DATA LOCAL INFILE, meaning the file used for LOAD DATA INFILE is on the same computer where your code is running, not the database server. Mojo::mysql::Database::Role::LoadDataInfile generates a temporary file for you locally on the computer your code is running on.

IMPORT OPTIONS

database_class

# apply the LoadDataInfile role to your own database_class
use Mojo::mysql::Database::Role::LoadDataInfile database_class => 'MyApp::Database';

$mysql->database_class('MyApp::Database');
my $results = $mysql->db->load_data_infile(...);

"database_class" allows you to apply Mojo::mysql::Database::Role::LoadDataInfile to your own database class instead of the default Mojo::mysql::Database.

METHODS

load_data_infile

my $results = $db->load_data_infile(table => 'people', rows => $rows);
print $results->affected_rows . " affected rows\n";

Execute a blocking LOAD DATA INFILE query and return a Mojo::mysql::Results instance. A temporary file is used to store the data in $rows and then is sent to MySQL. The file is deleted once the query is complete. You can also append a callback to perform a non-blocking operation.

my $results = $db->load_data_infile(table => 'people', rows => $rows, sub {
  my ($db, $err, $results) = @_;

  if ($err) {
      print "LOAD DATA INFILE failed: $err\n";
  } else {
    print $results->affected_rows . " affected rows\n";
  }
});

load_data_infile_p

my $promise = $db->load_data_infile_p(table => 'people', rows => $rows);

Same as "load_data_infile", but performs all operations non-blocking and returns a Mojo::Promise object instead of accepting a callback.

$db->load_data_infile_p(table => 'people', rows => $rows)->then(sub {
  my $results = shift;
  print $results->affected_rows . " affected rows\n";
  ...
})->catch(sub {
  my $err = shift;
  ...
})->wait;

options

These are the options that can be passed to both "load_data_infile" and "load_data_infile_p". Unless stated otherwise, options may be combined.

See LOAD DATA SYNTAX for more information on the below options, and possibly more up-to-date information.

low_priority

$db->load_data_infile(table => 'people', rows => $rows, low_priority => 1);

Adds the LOW_PRIORITY modifier to the query, which means that the execution of the LOAD DATA statement is delayed until no other clients are reading from the table. This affects only storage engines that use only table-level locking (such as MyISAM, MEMORY, and MERGE).

This cannot be true when "concurrent" is true.

concurrent

$db->load_data_infile(table => 'people', rows => $rows, concurrent => 1);

Adds the CONCURRENT modifier to the query, which means that for MyISAM tables that satisfy the condition for concurrent inserts (that is, it contains no free blocks in the middle), other threads can retrieve data from the table while LOAD DATA is executing.

This cannot be true when "low_priority" is true.

replace

$db->load_data_infile(table => 'people', rows => $rows, replace => 1);

Adds the REPLACE modifier to the query, which means that rows that have the same value for a primary key or unique index as an existing row will replace the existing row.

This cannot be true when "ignore" is true.

If neither "replace" nor "ignore" is specified, the default is "ignore" since this module uses the LOCAL modifier.

ignore

$db->load_data_infile(table => 'people', rows => $rows, ignore => 1);

Adds the REPLACE modifier to the query, which means that rows that duplicate an existing row on a unique key value are discarded.

This cannot be true when "replace" is true.

If neither "ignore" nor "replace" is specified, the default is "ignore" since this module uses the LOCAL modifier.

partition

$db->load_data_infile(table => 'people', rows => $rows, partition => ['p0', 'p1', 'p2']);

Adds the PARITION clause along with the provided partitions to insert into.

See Partitioned Table Support for more information.

character_set

$db->load_data_infile(table => 'people', rows => $rows, character_set => 'utf8', tempfile_open_mode => '>:encoding(UTF-8)');

Adds the CHARACTER SET clause, which specifies the encoding that MySQL will use to interpret the data.

The default is utf8, which matches with the default of "tempfile_open_mode". If you provide "character_set", you must also provide "tempfile_open_mode". The encodings should match between these two.

tempfile_open_mode

$db->load_data_infile(table => 'people', rows => $rows, character_set => 'utf8', tempfile_open_mode => '>:encoding(UTF-8)');

Sets the mode when opening the temporary file.

The default is ">:encoding(UTF-8)", which matches with the default of "character_set". If you provide "tempfile_open_mode", you must also provide "character_set". The encodings should match between these two.

set

$db->load_data_infile(table => 'people', rows => $rows, set => [
    {insert_time => 'NOW()'},
    {update_time => 'NOW()'},
]);

The SET clause can be used in several different ways, such as to supply values not derived from the input file. It accepts an arrayref of hashes, where the key of each hash is the column to set and the value is the expression to set it to.

See Input Preprocessing for more examples of how "set" can be used.

rows

"rows" correspond to the rows to be inserted. "rows" can be passed either an arrayref of "hashrefs", or an arrayref of "arrayrefs".

hashrefs

my $rows = [
  { name => 'Bob', age => 23 },
  { name => 'Alice', age => 27 },
];
$db->load_data_infile(table => 'people', rows => $rows);

If the items are "hashrefs" and "columns" is not provided, the keys from the first hashref will be used for "columns" and will be used as both the MySQL column names, and the key names to get values from the hashrefs.

arrayrefs

my $rows = [
  ['Bob', 23],
  ['Alice', 27],
];

# columns required when using arrayrefs
my $columns = ['name', 'age'];
$db->load_data_infile(table => 'people', rows => $rows, columns => $columns);

If the items are "arrayrefs", "columns" must be provided, and the order of the column names in columns must match with the order of the values in each arrayref in "rows".

See "columns" for more advance columns options.

columns

"columns" specifies the names of the columns to set in the table. Different values may be provided depending on whether "rows" contains "hashrefs" or "arrayrefs".

rows contains hashrefs

# will use keys of first hashref in $rows for columns if columns is not provided
$db->load_data_infile(table => 'people', rows => $rows);

# strings in $columns will be used as keys to access values of the hashrefs
# and also as the column names in MySQL
my $columns = ['name', 'age'];
$db->load_data_infile(table => 'people', rows => $rows, columns => $columns);

# you can map hash keys to their correpsonding names in the table
my $columns = [
  'name',
  { hash_age => 'column_age' },
];
$db->load_data_infile(table => 'people', rows => $rows, columns => $columns);

If "columns" is not provided, "rows" must contain hashrefs, and the keys of the first hashref will be used as the columns.

You may pass two types of values in "columns" when "hashrefs" are used in "rows":

  • You may pass strings, which will be used as the keys to access the values of the hashrefs and the column names.

  • Or, you may also pass hashes with a single key value pair, where the key is the name of the key in the hash, and the value is the name of the corresponding column in the table:

    { key_name => 'column_name' }

rows contains arrayrefs

# columns must be in the same order as their corresponding values in $rows
my $columns = ['name', 'age'];
$db->load_data_infile(table => 'people', rows => $rows, columns => $columns);

If "rows" contains "arrayrefs", "columns" is required and its values should be in the same order as the corresponding values in the arrayrefs pasesed to "rows".

AUTHOR

Adam Hopkins <srchulo@cpan.org>

COPYRIGHT

Copyright 2019- Adam Hopkins

LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO