NAME

Relations::Family - DBI/DBD::mysql Relational Query Engine module.

SYNOPSIS

# DBI, Relations::Family Script that creates some queries.

#!/usr/bin/perl

use DBI;
use Relations::Family;

$dsn = "DBI:mysql:finder";

$username = "root";
$password = '';

$dbh = DBI->connect($dsn,$username,$password,{PrintError => 1, RaiseError => 0});

my $family = new Relations::Family($dbh);

$family->add_member(-name     => 'region',
                    -label    => 'Region',
                    -database => 'finder',
                    -table    => 'region',
                    -id_field => 'reg_id',
                    -select   => {'id'    => 'reg_id',
                                 'label' => 'reg_name'},
                    -from     => 'region',
                    -order_by => "reg_name");

$family->add_member(-name     => 'sales_person',
                    -label    => 'Sales Person',
                    -database => 'finder',
                    -table    => 'sales_person',
                    -id_field => 'sp_id',
                    -select   => {'id'    => 'sp_id',
                                 'label' => "concat(f_name,' ',l_name)"},
                    -from     => 'sales_person',
                    -order_by => ["l_name","f_name"]);

$family->add_lineage(-parent_name  => 'region',
                     -parent_field => 'reg_id',
                     -child_name   => 'sales_person',
                     -child_field  => 'reg_id');

$family->set_chosen(-label  => 'Sales Person',
                    -ids    => '2,5,7');

$available = $family->get_available(-label  => 'Region');

print "Found $available->{count} Regions:\n";

foreach $id (@{$available->{ids_arrayref}}) {

  print "Id: $id Label: $available->{labels_hashref}->{$id}\n";

}

$dbh->disconnect();

ABSTRACT

This perl module uses perl5 objects to simplify searching through large, complex MySQL databases, especially those with foreign keys. It uses an object orientated interface, complete with functions to create and manipulate the relational family.

The current version of Relations::Family is available at

http://www.gaf3.com

DESCRIPTION

WHAT IT DOES

With Relations::Family you can create a 'family' of members for querying records. A member could be a table, or it could be a query on a table, like all the different months from a table's date field. Once the members are created, you can specify how those members are related, who's using who as a foreign key lookup, etc.

Once the 'family' is complete, you can select records from one member, and the query all the matching records from another member. For example, say you a product table being used as a lookup for a order items tables, and you want to find all the order items for a certain product. You can select that product's record from the product member, and then get the matching order item records to find all the order items for that product.

CALLING RELATIONS::FAMILY ROUTINES

All standard Relations::Family routines use both an ordered and named argument calling style. This is because some routines have as many as twelve arguments, and the code is easier to understand given a named argument style, but since some people, however, prefer the ordered argument style because its smaller, I'm glad to do that too.

If you use the ordered argument calling style, such as

$family->add_lineage('customer','cust_id','purchase','cust_id');

the order matters, and you should consult the function defintions later in this document to determine the order to use.

If you use the named argument calling style, such as

$famimly->add_lineage(-parent_name  => 'customer',
                      -parent_field => 'cust_id',
                      -child_name   => 'purchase',
                      -child_field  => 'cust_id');

the order does not matter, but the names, and minus signs preceeding them, do. You should consult the function defintions later in this document to determine the names to use.

In the named arugment style, each argument name is preceded by a dash. Neither case nor order matters in the argument list. -name, -Name, and -NAME are all acceptable. In fact, only the first argument needs to begin with a dash. If a dash is present in the first argument, Relations::Family assumes dashes for the subsequent ones.

LIST OF RELATIONS::FAMILY FUNCTIONS

An example of each function is provided in either 'test.pl' and 'demo.pl'.

new

$family = new Relations::Family($abstract);

$family = new Relations::Family(-abstract => $abstract);

Creates creates a new Relations::Family object using a Relations::Abstract object.

add_member

$family->add_member($name,
                    $label,
                    $database,
                    $table,
                    $id_field,
                    $select,
                    $from,
                    $where,
                    $group_by,
                    $having,
                    $order_by,
                    $limit);

$family->add_member(-name     => $name,
                    -label    => $label,
                    -database => $database,
                    -table    => $table,
                    -id_field => $id_field,
                    -select   => $select,
                    -from     => $from,
                    -where    => $where,
                    -group_by => $group_by,
                    -having   => $having,
                    -order_by => $order_by,
                    -limit    => $limit);

$family->add_member(-name     => $name,
                    -label    => $label,
                    -database => $database,
                    -table    => $table,
                    -id_field => $id_field,
                    -query    => $query);

Creates and adds a member to a family. There's three basic groups of arguments in an add_member call. The first group sets how to name the member. The second sets how to configure the member. The third group explains how to create the query to display the member's records for selection.

$name and $label - In the first group, $name and $label set the internal and external identity, so both must be unique to the family. Typically, $name is a short string used for quickly specifying a member when coding with a family, while $label is a longer string used to display the identity of a member to user using the program.

$database, $table and $id_field - In the second group, $database, $table and $id_field set the MySQL properties. The $database and $table variables are the database and table used by the member, while $id_field is the member's table's primary key field. Relations::Family using this info when connecting members to each other during a query.

$select through $limit - These parameters are sent directly to a Relations::Query object, and that object is modified to select distinct by default. In order for the member to function properly you must declase two variables, id and label, in the 'select' part of the query. Ids are the values that connect one member to another. Labels are what's displayed to the user to select. See the the documention for Relations::Query for more info on creating a query object.

$query - Instead of specifying the peices of a query, you can create a query separately, and send it . In my own experience, I often run into a situation where different members have the same query. The minimize code, you can query the query once, then use it many times.

add_lineage

$family->add_lineage($parent_name,
                     $parent_field,
                     $child_name,
                     $child_field);

$family->add_lineage(-parent_name  => $parent_name,
                     -parent_field => $parent_field,
                     -child_name   => $child_name,
                     -child_field  => $child_field);

$family->add_lineage(-parent_label => $parent_label,
                     -parent_field => $parent_field,
                     -child_label  => $child_label,
                     -child_field  => $child_field);

Adds a one-to-many relationhsip to a family. This is used when a member, the child, is using another member, the parent, as a lookup. The parent field is the field in the parent member, usually the primary key, the values of which is is stored in the child member's child_field.

$parent_name or $parent_label - Specifies the parent member by name or label.

$parent_field - Specifies the field in the parent member that holds the values used by the child member's child_field, usually the parent member's primary key.

$child_name or $child_label - Specifies the child member by name or label.

$child_field - Specifies the field in the child member that stores the values of the parent member's field.

add_rivalry

$family->add_rivalry($brother_name,
                     $brother_field,
                     $sister_name,
                     $sister_field);

$family->add_rivalry(-brother_name  => $brother_name,
                     -brother_field => $brother_field,
                     -sister_name   => $sister_name,
                     -sister_field  => $sister_field);

$family->add_rivalry(-brother_label => $brother_label,
                     -brother_field => $brother_field,
                     -sister_label  => $sister_label,
                     -sister_field  => $sister_field);

Adds a one-to-one relationhsip to a family. This is used when a member, there is a one to one relationship between two members. The brother field is the field in the brother member, the values of which is is stored in the sister member's sister_field, or vice vice versa.

$brother_name or $brother_label - Specifies the brother member by name or label.

$brother_field - Specifies the field in the brother member that holds the values used by the sister member's sister_field.

$sister_name or $sister_label - Specifies the sister member by name or label.

$sister_field - Specifies the field in the sister member that stores the values of the brother member's field.

set_chosen

$family->set_chosen($name,
                    $ids,
                    $labels,
                    $match,
                    $group,
                    $filter,
                    $limit);

$family->set_chosen(-name   => $name,
                    -ids    => $ids,
                    -labels => $labels,
                    -match  => $match,
                    -group  => $group,
                    -filter => $filter,
                    -limit  => $limit);

$family->set_chosen(-label  => $label,
                    -ids    => $ids,
                    -labels => $labels,
                    -match  => $match,
                    -group  => $group,
                    -filter => $filter,
                    -limit  => $limit);

Sets the member's records selected by a user, as well as some other goodies to control the selection process.

$name or $label - Specifies the member by name or label.

$ids - The ids selected. Can be a comma delimitted string, or an array.

$labels - The labels selected. Can be a comma delimitted string, an array, or a hash keyed by $ids. It is isn't necessary to send these, unless you want the selected labels returned by get_chosen.

$match - Match any or all. Null or 0 for any, 1 for all. This deals with multiple selections from a member and how that affects matching records from another member. Match any returns records that are connected to any of the selections. Match all returns records that are connected to all the selection.

$group - Group include or exclude. Null or 0 for include, 1 for exclude. This deals with whether to returning matching records or non matching records. Group include returns records connected to the selections. Group exclude returns records not connected to the selections.

$filter - Filter labels. In order to simplify the selection process, you can specify a filter to only show a select group of records from a member for selecting. The filter argument accepts a string, $filter, and places it in the clause "having label like '%$filter%'".

$limit - Limit returned records. In order to simplify the selection process, you can specify a limit clause to only show a certain number of records from a member for selecting. The limit argument accepts a string, $limit, and places it in the clause "limit $limit", so it can be a single number, or two numbers separated by a comma.

get_chosen

$chosen = $family->get_chosen($name);

$chosen = $family->get_chosen(-name => $name);

$chosen = $family->get_chosen(-label => $label);

Returns a member's selected records in a couple different forms, as well as the other goodies to control the selection process.

$name or $label - Specifies the member by name or label.

$chosen - A hash reference of all returned values.

$chosen-{count}> - The number of selected records.

$chosen-{ids_string}> - A comma delimtted string of the ids of the selected records.

$chosen-{ids_arrayref}> - An array reference of the ids of the selected records.

$chosen-{labels_string}> - A comma delimtted string of the labels of the selected records. If no labels were sent to get_chosen, this is not available.

$chosen-{labels_arrayref}> - An array reference of the labels of the selected records. If no labels were sent to get_chosen, this is not available.

$chosen-{labels_hashref}> - A hash reference of the labels of the selected records, keyed by the selected ids. If no labels were sent to get_chosen, this is not available.

$chosen-{match}> - The match argument sent to get_chosen().

$chosen-{group}> - The group argument sent to get_chosen().

$chosen-{filter}> - The filter argument sent to get_chosen().

$chosen-{limit}> - The limit argument sent to get_chosen().

get_available

$available = $family->get_available($name);

$available = $family->get_available(-name => $name);

$available = $family->get_available(-label => $label);

Returns a member's available records, records connected to the currently selected records in other members.

$name or $label - Specifies the member by name or label.

$available - A hash reference of all returned values.

$available-{count}> - The number of available records.

$available-{ids_string}> - A comma delimtted string of the ids of the available records.

$available-{ids_arrayref}> - An array reference of the ids of the available records.

$available-{labels_string}> - A comma delimtted string of the labels of the available records.

$available-{labels_arrayref}> - An array reference of the labels of the available records.

$available-{labels_hashref}> - A hash reference of the labels of the available records, keyed by the available ids.

RELATIONS::FAMILY DEMO - FINDER

Setup

Included with this distribution is demo.pl, which demonstrates all the listed functionality of Relations::Family. You must have MySQL, Perl, DBI, DBD-MySQL, Relations, Relations::Query, Relations::Abstract, and Relations::Family installed.

After installing everything, run demo.pl by typing

perl demo.pl

while in the Relations-Family installation directory.

Overview

This demo revolves around the finder database. This database is for a made up company that sells three different types of products: Toiletry: Soap, Towels, etc., Dining: PLates Cups, etc. and Office: Phones, Faxes, etc. There's a type table for the different types of products, and a product table for the different products. There's also a one-to-many relationship between type to product, because each product is of a specific type.

A similar relationship exists between the sales_person table, which holds all the different sales people, and the region table, which holds the regions for the sales peoples. Each sales person belong to a particular region, so there's a one-to-many relationship fromt he region table to the sales_person table.

If there's sellers, there's buyers. This is the function of the customer table. There is also an account table, for the accounts for each customer. Since each customer has only one account, there is merely a one-to-one relationship between customer and account.

With sellers and buyers, there must be purchases. Enter the purchase table, which holds all the purchases. Since only one customer makes a certain purchase, but one customer could make many purchases, there is a one-to-many relationship from the customer table to the purchase table.

Each purchase contain some number of products at various quantities. This is the role of the item table. One purchase can have multiple items, so there is a one-to-many relationship from the purchase table to the item table.

A product is the item purchased at different quantities, and a product can be in multiple purchases. Thus, there is a one-to-many relationship from the product table to the item table.

Finally, zero or more sales people can get credit for a purchase, so there is many-to-many relationship between the sales_person and purchase tables. This relationship is handled by the pur_sp table, so there is a one-to-many relatiionship from the purchase table to the pur_sp table and a one-to-many relationship from the sales_person table to the pur_sp table.

Family's role in this is true to it's name sake: It brings all of this into one place, and allows table to connect to one another. A member in the finder family is created for each table in the finder database, and a lineage (for one-to-many's) or a rivalry (for one-to-one's) for relationship.

With Family, you can select records from one member and find all the connecting records in other members. For example, to see all the products made by a purchase, you'd go to the purchase member, and select the purchase in question, and then go to the product's member. The avaiable records in product would be all the product on that purchase.

Usage

To run the demo, make sure you've followed the setup instructions, and go to the directory in which you've placed demo.pl and finder.pm. Run demo.pl like a regular perl script.

The demo starts with a numbered listing of all the members of the finder family. To view available records from a member and/or make selections, type in the member's number and hit return.

The first thing you'll be asked is if you want to choose available. This narrows down the current selected members of a list by the available records for a list. Enter 'Y' for yes, and 'N' for no. It defaults to 'N' so a blank is the same as no.

You'll then get two questions regarding the presentation of a member's records. I'll go into both here.

Limit is for displaying only a certain number of avaiable records at a time. It's fed into a MySQL limit clause so it can be one number, or two separated by a comma. To just see X number of rows from the begining, just enter X. To see X number of rows starting at Y, enter Y,X.

Filter is for filtering avaialable records for display. It takes a string, and only returns member's avaiable records that have the entered string in their label. Just enter the text to filter by.

You'll then get a numbered listing of all the available records for that member, as well as the match, group, ignore, limit and filter settings for that member.

Next, you'll get some questions regarding which records are to be selectecd, and how those selections are to be used (or not used!). I'll go into them here.

Selections are the records you want to choose. To choose records type each number in, separating with commas.

Match is whether you want other lists to match any of your multiple selections from this member or all of them. 0 for many, 1 for all.

Group is whether you want to include what was selected in this member, or exclude was selected, in matching other member's records. 0 for include, 1 for exclude.

Finally, you'll be asked if you want to do this again. 'Y' for yes, 'N' for no. It defaults to 'Y', so just press return for yes. If you choose yes, you'll get a list of members, go through the selection/viewing process again.

Examples

All together, this database can be used to figure out a bunch of stuff. Here's some ways to query certain records. With each example, it's best to restart demo.pl for scratch (exit and rerun).

Limit and Filter - There are 17 Sales Persons in the database. Though this isn't terribly many, you can lower the number sales people displayed at one time with Family two different ways, by limitting or by filtering. Here's examples for both.

First, let's look at all the sales people - From the members list, select 7 for Sales Person. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 17 available records:

(2)  Mimi Butterfield
(12) Jennie Dryden
(6)  Dave Gropenhiemer
(14) Karen Harner
(1)  John Lockland
(4)  Frank Macena
(13) Mike Nicerby
(5)  Joyce Parkhurst
(17) Calvin Peterson
(8)  Fred Pirozzi
(16) Mya Protaste
(9)  Sally Rogers
(15) Jose Salina
(3)  Sheryl Saunders
(11) Ravi Svenka
(10) Jane Wadsworth
(7)  Hank Wishings

These are all the sales people. - No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Now, let's just look at the first 5 sales peoeple. - From the members list, select 7 for Sales Person. - Don't choose available. (or just hit return) - Set limit to 5. - No filter. (or just hit return) - There should be 5 available records:

(2)  Mimi Butterfield
(12) Jennie Dryden
(6)  Dave Gropenhiemer
(14) Karen Harner
(1)  John Lockland

These are the first 5 sales people - No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

How 'bout the last 5 sales people. - From the members list, select 7 for Sales Person. - Don't choose available. (or just hit return) - Set limit to 12,5. - No filter. (or just hit return) - There should be 5 available records:

(15) Jose Salina
(3)  Sheryl Saunders
(11) Ravi Svenka
(10) Jane Wadsworth
(7)  Hank Wishings

These are the last 5 sales people. Limit started at the 12th record, and allowed the next 5 records. - No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Finaly, let's find all the sales people that have the letter 'y' in the first or last name. - From the members list, select 7 for Sales Person. - Don't choose available, and no limit. (or just hit return) - Set filter to y. - There should be 6 available records:

(12) Jennie Dryden
(13) Mike Nicerby
(5)  Joyce Parkhurst
(16) Mya Protaste
(9)  Sally Rogers
(3)  Sheryl Saunders

These are all the people with the letter 'y' in their first or last name. - No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply N, to 'Again?' (to quit)

The Selections Effect - A purchase contains one or more products, and you can see which product were purchased on a purchased order by selected a record from the purcahse member, and viewing the avaiable records of the product member. Varney solutions made a purchase on jan 4th, 2001, and we'd like to see what they bought.

First, let's see all the products. - From the members list, select 3 for Product. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 13 available records:

(6)  Answer Machine
(13) Bowls
(9)  Copy Machine
(12) Cups
(10) Dishes
(8)  Fax
(7)  Phone
(11) Silverware
(4)  Soap
(3)  Soap Dispenser
(5)  Toilet Paper
(1)  Towel Dispenser
(2)  Towels

These are all the products. - No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Let's pick a purchase to view the products from. - From the members list, select 5 for Purchase. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 8 available records:

(6)  Last Night Diner - May 9th, 2001
(3)  Harry's Garage - April 21st, 2001
(7)  Teskaday Print Shop - April 7th, 2001
(4)  Simply Flowers - March 10th, 2001
(2)  Harry's Garage - February 8th, 2001
(8)  Varney Solutions - January 4th, 2001
(1)  Harry's Garage - December 7th, 2000
(5)  Last Night Diner - November 3rd, 2000

- From the available records, select 8 for Varney Solutions' Purchase. - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Now, we'll check out all the products on that purchase. - From the members list, select 3 for Product. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 4 available records:

(6)  Answer Machine
(9)  Copy Machine
(8)  Fax
(7)  Phone

These are the products purchased by Varney in January. - No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply N, to 'Again?' (to quit)

Matching Multiple - You can also lookup purchases by products. Furthermore you can look purcahses up by selecting many products, and finding purchases that have any of the selected products. You can even find purchases that contain all the selected products.

First, let's see all the purchases. - From the members list, select 5 for Purchase. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 8 available records:

(6)  Last Night Diner - May 9th, 2001
(3)  Harry's Garage - April 21st, 2001
(7)  Teskaday Print Shop - April 7th, 2001
(4)  Simply Flowers - March 10th, 2001
(2)  Harry's Garage - February 8th, 2001
(8)  Varney Solutions - January 4th, 2001
(1)  Harry's Garage - December 7th, 2000
(5)  Last Night Diner - November 3rd, 2000

- No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Now, we'll check out all the products, select a few, and set matching to any so we can purchases that have any (Soap or Soap Dispenser). - From the members list, select 3 for Product. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 13 available records:

(6)  Answer Machine
(13) Bowls
(9)  Copy Machine
(12) Cups
(10) Dishes
(8)  Fax
(7)  Phone
(11) Silverware
(4)  Soap
(3)  Soap Dispenser
(5)  Toilet Paper
(1)  Towel Dispenser
(2)  Towels

These are all the products. - From the available records, select 4,3 for Soap, and Soap Dispenser - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Now, we'll see which purchase contain either Soap or Soap Dispenser. - From the members list, select 5 for Purchase. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 3 available records:

(3)  Harry's Garage - April 21st, 2001
(2)  Harry's Garage - February 8th, 2001
(1)  Harry's Garage - December 7th, 2000

- No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Now, we'll check out all the products, select a few, and set matching to all so we can purchases that have all (Soap and Soap Dispenser). - From the members list, select 3 for Product. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 13 available records, Soap and Soap Dispenser *'ed,

  (6)  Answer Machine
  (13) Bowls
  (9)  Copy Machine
  (12) Cups
  (10) Dishes
  (8)  Fax
  (7)  Phone
  (11) Silverware
* (4)  Soap
* (3)  Soap Dispenser
  (5)  Toilet Paper
  (1)  Towel Dispenser
  (2)  Towels

These are all the products, with Soap and Soap Dispenser already selected. - From the available records, select 4,3 for Soap, and Soap Dispenser - Match = 1 (means 'any') - Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Now, we'll see which purchase contain both Soap and Soap Dispenser. - From the members list, select 5 for Purchase. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 1 available record:

(1)  Harry's Garage - December 7th, 2000

This is the only purchase that contains both Soap and Soap Dispenser. - No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply N, to 'Again?' (to quit)

Group Inclusion/Exclusion - Sometimes you'd like to find all records the records not connected to your selections from a particular member. Say you wanted to check up on all the orders from customers, except the Harry's Garage, who would have already let you know if there was a problem.

First, let's see all the purchases. - From the members list, select 5 for Purchase. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 8 available records:

(6)  Last Night Diner - May 9th, 2001
(3)  Harry's Garage - April 21st, 2001
(7)  Teskaday Print Shop - April 7th, 2001
(4)  Simply Flowers - March 10th, 2001
(2)  Harry's Garage - February 8th, 2001
(8)  Varney Solutions - January 4th, 2001
(1)  Harry's Garage - December 7th, 2000
(5)  Last Night Diner - November 3rd, 2000

- No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply Y, to 'Again?' (to select another member)

Let's pick a customer to not view the purchases from. - From the members list, select 1 for Customer. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 5 available records:

(1)  Harry's Garage
(4)  Last Night Diner
(3)  Simply Flowers
(5)  Teskaday Print Shop
(2)  Varney Solutions

- From the available records, select 1 for Harry's Garage. - Match = 0 (or just hit return) - Group = 1 (means 'exclude') - Reply Y, to 'Again?' (to select another member)

Now, we'll check out all the purchases not from Harry's Garage. - From the members list, select 5 for Purchase. - Don't choose available, no limit, and no filter. (or just hit return) - There should be 5 available records:

(6)  Last Night Diner - May 9th, 2001
(7)  Teskaday Print Shop - April 7th, 2001
(4)  Simply Flowers - March 10th, 2001
(8)  Varney Solutions - January 4th, 2001
(5)  Last Night Diner - November 3rd, 2000

- No Selections (or just hit return) - Match = 0, Group = 0 (or just hit return) - Reply N, to 'Again?' (to quit)

OTHER RELATED WORK

Relations

This perl library contains functions for dealing with databases. It's mainly used as the the foundation for all the other Relations modules. It may be useful for people that deal with databases in Perl as well.

Relations::Abstract

A DBI/DBD::mysql Perl module. Meant to save development time and code space. It takes the most common (in my experience) collection of DBI calls to a MySQL databate, and changes them to one liner calls to an object.

Relations::Query

An Perl object oriented form of a SQL select query. Takes hash refs, array refs, or strings for different clauses (select,where,limit) and creates a string for each clause. Also allows users to add to existing clauses. Returns a string which can then be sent to a MySQL DBI handle.

Relations.Admin.inc.php

Some generalized PHP classes for creating Web interfaces to relational databases. Allows users to add, view, update, and delete records from different tables. It has functionality to use tables as lookup values for records in other tables.

Relations::Family

A Perl query engine for relational databases. It queries members from any table in a relational database using members selected from any other tables in the relational database. This is especially useful with complex databases; databases with many tables and many connections between tables.

Relations::Display

An Perl module creating GD::Graph objects from database queries. It takes in a query through a Relations::Query object, along with information pertaining to which field values from the query results are to be used in creating the graph title, x axis label and titles, legend label (not used on the graph) and titles, and y axis data. Returns a GD::Graph object built from from the query.

Relations::Choice

An Perl CGI interface for Relations::Family, Reations::Query, and Relations::Display. It creates complex (too complex?) web pages for selecting from the different tables in a Relations::Family object. It also has controls for specifying the grouping and ordering of data with a Relations::Query object, which is also based on selections in the Relations::Family object. That Relations::Query can then be passed to a Relations::Display object, and a graph or table will be displayed. A working model already exists in a production enviroment. I'd like to streamline it, and add some more functionality before releasing it to the world. Shooting for early mid Summer 2001.