This package provides reusable functions to be consumed by the rest of the PhotoDB application.
Note that some of these functions take traditional argument lists which must be in order, while the more complex functions take a hashref of arguments which can be passed in any order. Examples of each function are given.
Prompt the user for an arbitrary value. Has various options for data validation and customisation of the prompt. If the provided input fails validation, or if a blank string is given when required=1 then the prompt is repeated.
my $camera = &prompt({prompt=>'What model is the camera?', required=>1, default=>$$defaults{model}, type=>'text'});
would give a prompt like
What model is the camera? (text) []:
$default Default value that will be used if no input from user. Default empty string.
$default
$prompt Prompt message for the user
$prompt
$type Data type that this input expects, out of text, integer, boolean, date, decimal, time
$type
text
integer
boolean
date
decimal
time
$required Whether this input is required, or whether it can return an empty value. Default 0
$required
0
$showtype Whether to show the user what data type is expected, in parentheses. Default 1
$showtype
1
$showdefault Whether to show the user what the default value is set to, in square brackets. Default 1
$showdefault
$char Character to print at the end of the prompt. Defaults to :
$char
:
The value the user provided
Set up a terminal object for use by PhotoDB
my $term = &term;
None
Terminal object
Validate that a value is a certain data type
my $result = &validate({val => 'hello', type => 'text'});
$val The value to be validated
$val
$type Data type to validate as, out of text, integer, boolean, date, decimal, time. Defaults to text.
Returns 1 if the value passes validation as the requested type, and 0 if it doesn't.
Find PhotoDB config ini file
my $ini = &ini;
File path to the config ini file
Connect to the database, run migrations and return database handle
my $db = &db;
Variable representing the database handle
Run database migrations
&runmigrations($db);
$db DB handle
$db
Nothing
Update an existing record in any table
my $rows = &updaterecord({db=>$db, data=>\%data, table=>'FILM', where=>{film_id=>$film_id}});
$data Hash of new values to update
$data
$table Name of table to update
$table
$where Where clause, formatted for SQL::Abstract
$where
$silent Suppress output
$silent
$log Write an event to the database log. Defaults to 1.
$log
The number of rows updated
Delete an existing record from any table
my $rows = &deleterecord({db=>$db, table=>'FILM', where=>{film_id=>$film_id}});
$table Name of table to delete from
The number of rows deleted
Insert a record into any table
my $id = &newrecord({db=>$db, data=>\%data, table=>'FILM'});
$data reference to hash of new values to insert
$table Name of table to insert into
$silent Suppress user output and don't ask for confirmation. Defaults to 0.
Primary key of inserted row
Print a warning that this command/subcommand is not yet implemented
¬implemented
Print list of available top-level commands
&nocommand(\%handlers);
$handlers reference to hash of handlers from handlers.pm
$handlers
handlers.pm
Print list of available subcommands for a given command
&nosubcommand(\%{$handlers{$command}}, $command);
$command name of command whose subcommands you want
$command
$handlers reference to hash slice of handlers from handlers.pm
List arbitrary choices from the DB and return ID of the selected one
my $id = &listchoices({db=>$db, table=>$table, where=>$where});
$query (legacy) the SQL to generate the list of choices
$query
$type Data type of choice to be made. Defaults to text
$inserthandler function ref to handler that can be used to insert a new row if necessary
$inserthandler
$default ID of default choice
$autodefault if default not set, count number of allowed options and if there's just 1, make it the default
$autodefault
$skipok whether it is ok to return undef if there are no options to choose from
$skipok
undef
$table table to run query against. Part of the SQL::Abstract tuple
$cols columns to select for the ID and the description. Defaults to ('id', 'opt). Part of the SQL::Abstract tuple
$cols
('id', 'opt)
$where where clause passed in as a hash, e.g. {'field'='value'}>. Part of the SQL::Abstract tuple
{'field'=
$keyword keyword to describe the thing being chosen, e.g. camera. Defaults to attempting to figure it out with &keyword
$keyword
camera
&keyword
$required whether this is a required choice, or whether we allow the user to enter an empty input. Defaults to 0
$char character to use to signal that you want to enter a new row, if inserthandler is set. Defaults to +
inserthandler
+
ID of the selected option
Choose from a number of options expressed as an array, and return the index of the chosen option
my @choices = [ { desc => 'Do nothing' }, { desc => 'Also do nothing' }, ]; my $action = &multiplechoice({choices => \@choices});
$choices array of hashes of options
$choices
Integer of the chosen option
Print arbitrary rows from the database as an easy way of displaying data
&printlist({db=>$db, msg=>"prints from negative $neg_id", table=>'info_print', where=>{`Negative ID`=>$neg_id}});
$msg Message to display to user to describe what is being displayed. Shows up as Now showing $msg\n
$msg
Now showing $msg\n
$table Table to select from. Part of the SQL::Abstract tuple
$cols Columns to display. Defaults to (id, opt). Part of the SQL::Abstract tuple
(id, opt)
$where Where clause for the query. Part of the SQL::Abstract tuple
$order Order by clause for the query. Part of the SQL::Abstract tuple
$order
Integer representing the number of rows printed
Return values from an arbitrary column from database as an arrayref
my $existing = &lookupcol({db=>$db, table=>'CAMERA', where=>{camera_id=>$camera_id}});
$query (legacy) bare SQL query to run
$cols columns to select for the ID and the description. Defaults to *. Part of the SQL::Abstract tuple
*
An arrayref containing a hashref of columns and values
Thin out keys with empty values from a sparse hash
$data = &thin($data);
$data Hashref containing data to be thinned
Hashref containing thinned data
Return arbitrary single value from database
my $info = &lookupval({db=>$db, col=>'notes', table=>'FILM', where=>{film_id=>$film_id}});
$col column to select. Part of the SQL::Abstract tuple
$col
Single value from the database
Call a stored procedure from the database
&call({db=>$db, procedure=>'print_unarchive', args=>['123']});
$procedure name of the database stored procedure to call
$procedure
$args arrayref of arguments to pass to the stored procedure
$args
Number of affected rows
Return multiple values from a single database column as an arrayref
my $values = &lookuplist({db=>$db, col=>$column, table=>$table, where{key=>value}});
An arreyref containing a list of values
Return today's date according to the DB
my $todaysdate = &today;
Today's date, formatted YYYY-MM-DD
YYYY-MM-DD
Return an SQL-formatted timestamp for the current time
my $time = &now;
$db Database handle
String containing the current time, formatted YYYY-MM-DD HH:MM:SS
YYYY-MM-DD HH:MM:SS
Translate "friendly" bools to integers so we can accept human input and map it to binary boolean values. y/yes/true/1 map to 1 and n/no/false/0 map to 0. See also &printbool.
my $binarybool = &friendlybool($friendlybool);
$friendlybool string representation of a boolean, e.g. yes, y, true, 1, no, n, false, 0, etc
$friendlybool
yes
y
true
no
n
false
1 if $bool represents a true value and 0 if it represents a false value
$bool
Translate numeric bools to strings for friendly printing of user messages. See also &friendlybool.
my $string = &printbool($bool);
$bool boolean value to rewrite
Returns yes if $bool is true and no if $bool is false.
Write out an initial config file by prompting the user interactively.
&writeconfig($path);
$path path to the config file that should be written
$path
Round a number to any precision
my $rounded = &round($num, 3);
$num Number to round
$num
$pow10 Number of decimal places to round to. Defaults to 0 i.e. round to an integer
$pow10
Rounded number
Pad a string with spaces up to a fixed length, to make it easier to print fixed-width tables
my $paddedstring = &pad('Hello', 8);
$string Text to pad
$string
$totallength Total number of characters to pad to, defaults to 18
$totallength
18
Padded string
Get a negative ID either from the neg ID or the film/frame ID
my $negID = &resolvenegid({db=>$db, string=>'10/4'});
$string String to represent a negative ID, either as an integer or in film/frame format, e.g. 834 or 10/4
834
10/4
Integer negative ID
Select a negative by drilling down
my $id = &chooseneg({db=>$db, oktoreturnundef=>$oktoreturnundef});
$db variable containing database handle as returned by &db
&db
$oktoreturnundef optional boolean to specify whether it is OK to fail to find a negative
$oktoreturnundef
Integer representing the negative ID
Write out a text file in the film scans directory
&annotatefilm({db=>$db, film_id=>$film_id});
$film_id integer variable containing ID of the film to be annotated
$film_id
Figure out the human-readable keyword of an SQL statement, e.g. statements that select from CAMERA or choose_camera would return camera. Selecting from CAMERA_MOUNT or choose_camera_mount would return camera mount. This can be helpful when automating user messages.
CAMERA
choose_camera
CAMERA_MOUNT
choose_camera_mount
camera mount
my $keyword = &keyword($query);
$query an SQL statement, e.g. SELECT * FROM CAMERA;
SELECT * FROM CAMERA;
A human-readable keyword representing the "subject" of the SQL query
Parse lens model name to guess some data about the lens. Either specify which parameter you want to be returned as a string, or expect a hashref of all params to be returned. Currently supports guessing minfocal (minimum focal length), maxfocal (maximum focal length), zoom (whether this is a zoom lens) and aperture (maximum aperture of lens).
minfocal
maxfocal
zoom
aperture
my $aperture = &parselensmodel($model, 'aperture'); my $lensparams = &parselensmodel($model);
$model Model name of the lens
$model
$param The name of the desired parameter. Optional, choose from minfocal, maxfocal, zoom or aperture.
$param
If $param is specified, returns the value of this parameter as a string
If $param is undefined, returns a hashref of all parameters
Unassociate a display lens from a camera by passing in either the camera ID or the lens ID. It is not harmful to pass in both, but it is pointless.
&unsetdisplaylens({db=>$db, camera_id=>$camera_id}); &unsetdisplaylens({db=>$db, lens_id=>$lens_id});
$camera_id ID of camera whose display lens you want to unassociate
$camera_id
$lens_id ID of lens you want to unassociate
$lens_id
Result of SQL update
Print a friendly welcome message
&welcome;
Calculate duration of a shutter speed from its string representation
my $duration = &duration($shutter_speed);
$shutter_speed string containing a representation of a shutter speed, e.g. 1/125, 0.7, 3, or 3"
$shutter_speed
1/125
0.7
3
3"
Numeric representation of the duration of the shutter speed, e.g. 0.05
0.05
This func reads data from PhotoDB and writes EXIF tags to the JPGs that have been scanned from negatives
&tag({db=>$db, where=>$where}); &tag({db=>$db, where=>{film_id=1}}); &tag({db=>$db, where=>{negative_id=100}});
$where hash to specify which scans should be tagged. Tags all scans if not set!
Compare new and old data to find changed keys.
my $diff = &hashdiff(\%old, \%new); my $diff = &hashdiff($old, $new);
$old hashref of old values
$old
$new hashref of new values
$new
Hashref containing values that are new or different.
Record a database event in the log
&logger({db=>$db, type=>$type, message=>$message});
$type Type of log message. Currently ADD or EDIT to reflect database changes.
ADD
EDIT
$message Message to write to the log file
$message
ID of the log message
Select a scan by specifying a filename. Allows user to pick if there are multiple matching filenames.
my $id = &choosescan({db=>$db});
Integer representing the scan ID
Returns filesystem basepath which contains scans
my $basepath = &basepath;
Path to directory which contains scans
Untaint a tainted value
my $untainted = &untaint($tainted);
$tainted Tainted value to untaint
$tainted
Returns the untained string
List all scan files on the filesystem
my @scansondisk = &fsfiles;
Array of file paths of scans found on the filesystem
List all scan files in the database
my @scansindb = &dbfiles;
$db database handle
DBD returns integer zero in scientific format as 0E0. This rewrites it.
$int = &unsci($int);
$int an integer returned by DBD
$int
The same integer as passed in, except with string 0E0 rewritten as integer 0
Search for objects in the database
my $id = &search({ db => $db, table => 'choose_camera', searchterm => $searchterm, choices => [ { desc => 'Do nothing' }, { desc => 'Get camera info', handler => \&camera_info, id=>'camera_id', }, { desc => 'Load a film', handler => \&film_load, id=>'camera_id', }, { desc => 'Sell this camera', handler => \&camera_sell, id=>'camera_id', } ], });
$table name of table or view to search in
$searchterm string to search for in the database
$searchterm
$cols = pair of columns where the first will be returned as the matched ID and the second is the column to be searched in. Defaults to ['id', 'opt']
$where where clause for the search. Defaults to "opt like '%$searchterm%' collate utf8mb4_general_ci"
"opt like '%$searchterm%' collate utf8mb4_general_ci"
$choices arrayref to an array of hashes which represent actions to be taken on a located item. You must provide desc, a description of the action, handler, a function reference to a suitable handler, and id, the name of the parameter to use to pass in the ID located object.
desc
handler
id
ID of located object
Display multi-column SQL views as tabulated data.
&tabulate({db=>$db, view=>$view});
$view name of SQL view to print
$view
$cols columns of view to return. Defaults to *
$where optional WHERE clause
Number of rows displayed
Decode Canon datecodes to discover the year of manufacture. Datecodes are sometimes ambiguous so by passing in the dates that the model was introduced and discontinued, the year of manufacture can be pinned down.
my $manufactured = &canondatecode({datecode=>$datecode, introduced=>$introduced, discontinued=>$discontinued});
$datecode the datecode to decode
$datecode
$introduced year that the model was introduced. Assumes 1800 if not defined.
$introduced
$discontinued year that the model was discontinued. Assumes 2100 if not defined.
$discontinued
Year of manufacture if the decoding was successful, otherwise undef
While entering a negative into a film, prompt the user to select an available shutter speed for the camera in use. If they choose B or T, prompt them for the duration in seconds, and return that instead. Also add it to the SHUTTER_SPEED_AVAILABLE table, marked as a "bulb" speed if necessary.
B
T
SHUTTER_SPEED_AVAILABLE
my $shutter_speed = &choose_shutterspeed({db=>$db, film_id=>$film_id});
$film_id Film ID that we are inserting into, so the camera can be found
String representation of a shutter speed, which is both a valid EXIF representation, and also a valid data object.
84 POD Errors
The following errors were encountered while parsing the POD:
'=item' outside of any '=over'
You forgot a '=back' before '=head4'
You forgot a '=back' before '=head2'
To install App::PhotoDB, copy and paste the appropriate command in to your terminal.
cpanm
cpanm App::PhotoDB
CPAN shell
perl -MCPAN -e shell install App::PhotoDB
For more information on module installation, please visit the detailed CPAN module installation guide.