Revision history for Perl extension SPOPS. NOTE: All items with a leading 'SP-###' are issues in the JIRA issue tracking system. Learn more at http://jira.openinteract.org/ 0.87 Tue Jun 1 20:34:44 EDT 2004 * SPOPS/Import.pm: - SP-5: Added property 'extra_metadata' to hold user-defined metadata for an import. * SPOPS/Import/DBI/Data.pm: - SP-5: When running 'assign_raw_data()' store the first element in the raw data in the new 'extra_metadata' property after first removing the data we need from it. * SPOPS/Import/DBI/Delete.pm: - SP-6: Add class for declaring records to delete through the import interface. * SPOPS/Import/DBI/GenericOperation.pm: - SP-6: add parent class for doing update/delete through the import interface. * SPOPS/Import/DBI/Update.pm: - SP-6: Add class for declaring records to update through the import interface. * SPOPS/SQLInterface.pm: - SP-7: Modify db_update() to allow additional data passed in 'value' parameter to be passed to the statement 'execute()' call so you can use placeholders in the WHERE clause of your update. This is a completely backward-compatible modification as the changes are additive and we don't change any parameter without first making a copy. * t/40_ldap.t, t/41_ldap_config.t - Applied patches from Martin Kutter to work on a directory with schema checking enabled. 0.86 Sat May 22 15:33:30 EDT 2004 Individual: * SPOPS/DBI.pm - SP-4: In _execute_multiple_record_query() allow for case-sensitive table names. Thanks to Ray Zimmerman. 0.85 Tue May 11 00:19:22 EDT 2004 Overall: * Small (but important!) fix for hierarchical security Individual: * SPOPS/Secure/Hierarchy.pm: - If there is no hierarchy separator in the value don't go into an infinite loop hoping it will be there someday... 0.84 Mon May 10 21:53:04 EDT 2004 Overall: * Bunch of bugfixes Individual: * SPOPS.pm: - SP-1: Check that the $log is defined before using it in DESTROY. (Thanks to Ray Zimmerman) - SP-2: Update AUTOLOADed '{prop}_clear' method to delete the property rather than set it to undef. (Thanks to Lee Revell) - SP-3: Add 'SPOPS::Tie::StrictField' to imports after weird storable behavior (complained about not finding the necessary tie methods because it doesn't call new() which was dynamically loading the necessary class) (Thanks to Nick Sutterer) - Add note about SPOPSx::Ginsu to SEE ALSO * SPOPS/Secure.pm: - (hack) since we call 'get_security()' explicitly as a class method, pass along the possible object as parameter 'object' so subclasses (like SPOPS::Secure::Hierarchy) can use it * SPOPS/Secure/Hierarchy.pm: - (hack) Allow hierarchy value of non ID field to be used by overriding the ID as the hierarchy value in _get_hierarchy_parameters() and also pull the object from the parameters passed in (earlier SPOPS::Secure hack) * SPOPS/Tie.pm: - SP-2: Modify DELETE to actually delete the property out of the object rather than just setting it to undef. * SPOPS/Tie/StrictField.pm: - SP-3: For efficiency we were storing the fields for each object class as class data in SPOPS::Tie::StrictField; since the script restarted this data was wiped out and the object thought none of its fields were valid, so everything was undef. We now check to see the data are there before doing any fetch/store operations on the tied object. 0.83 Thu Mar 18 21:37:13 EST 2004 Overall: * Fix the sequence usage in SPOPS::DBI::Pg and SPOPS::DBI::Oracle. Fetch the sequence value beforehand instead of inserting the sequence retrieval and getting the value after the insert. 0.82 Mon Mar 15 23:03:29 EST 2004 Overall: * Quick bugfix for SPOPS::DBI users with databases using sequences (like Postgres). Individual: * SPOPS/DBI.pm: - We want to go ahead and fetch the ID after the row has been inserted... 0.81 Mon Mar 15 08:13:46 EST 2004 Overall: * Use Log::Log4perl to do logging/debugging. All internal SPOPS classes, and the code generated by them, has been modified to use it. Previously existing debugging methods (_w and _wm) use log4perl under the hood. A script (eg/modify_debug_to_l4p.pl) is provided for you to convert your own code to log4perl calls. * Modify slightly the default behavior for 'sql_quote()' as defined in SPOPS::SQLInterface. Nobody should notice... * A fistful of bugfixes and minor enhancements. Individual: * SPOPS.pm: - Add a 'initialize_custom()' step to 'new()' to allow subclasses to do customization in the constructor. Thanks Simon! - Replace '_w()' and '_wm()' with calls to log4perl -- this is for backwards compatibility only; you should run eg/modify_debug_to_l4p.pl to get on the bandwagon - Fix bug in AUTOLOAD that didn't create the accessor/mutator + clearing method on a first invocation of '{property}_clear' when you're not using strict field checking. Thanks to Lee Revell (rlrevell@dca.net) for reporting the error and the failure case. - Add new configuration property 'field_raw'; this can hold the actual fields used for the object in their original case. So if your database pulls 'person_ID' as a fieldname you can use both 'person_id' and 'person_ID' as a hash key *and* as a accessor/mutator, even when using strict field checking. Thanks to Simon for pointing this out. * SPOPS/ClassFactory/DefaultBehavior.pm: - Fix a 'return' where the error message was truncated due to commas rather than period being used. Thanks to Simon for the spot. - On class generation: if 'field_raw' isn't defined in the class configuration set it to the original (pre-munged) list of fields. * SPOPS/ClassFactory/DBI.pm: - Fix a 'return' where the error message was truncated due to commas rather than period being used. Thanks to Simon for the spot. * SPOPS/DBI.pm: - Provide better error message from 'id_clause()' when we don't have any type information available. Thanks to Simon Ilyushchenko (simonf@cshl.edu) for the report. - For constructing group queries (fetch_group, fetch_iterator), add the class's table to the 'from' array if it's not already there. This allows you to specify join queries and 'assume' the class table will be added. - In save() only call pre_fetch_id() or post_fetch_id() if an ID is NOT ALREADY DEFINED. - Applied patch from Pawel Gajda to fix lazy loading problem. * SPOPS/DBI/([:driver:]).pm: - Get rid of all driver implementations of 'sql_quote()' since it's defined in SPOPS::SQLinterface and they were all using the same definition anyway. * SPOPS/HashFile.pm: - Don't dereference a hash, gets rid of warning many OI users saw since they upgraded to 5.8... * SPOPS/Loopback.pm: - Add a simple (!) ability for 'fetch_group' to parse the 'where' clause and use options from 'value' to substitute for a placeholder. - Fix extraneous warnings regarding 'pre_fetch_id' and 'post_fetch_id' when using strict field checking. * SPOPS/Manual/Configuration.pm: - Fix configuration typo (using 'publisher_link' instead of 'publisher_book' in links_to configuration). Thanks Simon! * SPOPS/Secure.pm: - Add warnings when our definitions of global_current_user and global_current_groups are found. * SPOPS/SQLInterface.pm: - Add to default 'sql_quote()' a check to see if the $value to be quoted is defined; if not use 'NULL'. Thanks to Simon for the report. Also, document the 'sql_quote()' method and make the new default to use the two-argument form of DBI->quote( $value, $type ). * SPOPS/Tie/StrictField.pm: - Get rid of carp calls on strict field violations, replacing them with log4perl calls. (This means you cannot set a SIG{__WARN__} handler anymore...) * SPOPS/Tool/DateConvert.pm: - When converting FROM an object TO a string (e.g., during a save()), if the given item isn't a reference then just return it, assuming it's a date in the right string format. * SPOPS/Tool/UTFConvert.pm: - Determine at runtime whether we're running in 5.6.0 or less or 5.6.1 or greater and use different encoding/decoding schemes as appropriate. (Thanks to the Arvato folks for providing the post-5.6.1 version...) 0.80 Sat Nov 29 13:17:17 EST 2003 Overall: * Add auto-generated mutators and clearing mutators along with the accessors. * Customize the 'links_to' mechanism for DBI object relationships. Individual: * MANIFEST: - Add eg/My/CommonResources.pm, forgotten from earlier version. Thanks to Simon Ilyushchenko (simonf@cshl.edu) for the report. * SPOPS.pm: - AUTOLOAD-created accessor now also acts as a mutator. I thought it was already doing this but Simon set me straight. - Also generate a '{fieldname}_clear' to act as a clearing mutator (set a field to undef). - Allow SPOPS subclasses to define their own accessor/mutator/clearing mutator methods by overriding '_internal_create_field_methods()'. See docs for details. * SPOPS/ClassFactory/DBI.pm: - Allow 'links_to' declarations to customize the to/from ID fields and alias in addition to the linking table. Thanks to Stathy Touloumis (stathy@edisonaffiliates.com) for the idea. - In 'links_to' generation stage, try to require the linked class before getting its configuration. This allows us to declare the SPOPS class as a superclass of our customized class. * SPOPS/ClassFactory/Default.pm: - In 'has_a' generation stage, try to require the contained class before getting its configuration. This allows us to declare the SPOPS class as a superclass of our customized class. * SPOPS/DBI.pm: - In save() allow the user to pass in an empty arrayref for 'no_insert' and 'no_update' that will override whatever is defined in the object configuration. * SPOPS/Manual/Object.pod: - Modify the accessor/mutator discussion to reflect changed code. * SPOPS/Manual/Relationships.pod: - Add new 'links_to' configuration options. * SPOPS/Secure.pm: - Fix typo in message generated from 'register_security_error()', thanks to Simon for the report. * t/00_base.t: - Test auto-created mutators and clearing mutators. * t/62_export_perl.t: - Fix bug in tests exposed by modified hash key ordering in 5.8+. (Note: use 'is_deeply()'!) 0.79 Sun Sep 7 22:45:07 EDT 2003 Individual: * eg/(lots): - Examples were broken since we added global_current_user|group() to SPOPS::Secure; thanks to Christian Hansen for pointing out the error. * SPOPS.pm: - Made call to global_cache() sync up with what docs say. Thanks to Christian Hansen. - Allow 'display.url_edit' key to be defined in class configuration and be used in the output of 'object_description()' * SPOPS/DBI.pm: - When executing a post-insert fetch (for defaults, etc) ensure that the list of fields to fetch doesn't include any empty/undef fields. * SPOPS/DBI/(Oracle|Sybase).pm: - Changed global_db_handle() (deprecated) to global_datasource_handle. Thanks to Christian Hansen. * SPOPS/Import/DBI/TableTransform/Pg.pm: - Don't use 'SERIAL' anymore and specify why in the POD. * SPOPS/Key/DBI/HandleField.pm: - Wrap the value retrieval in an eval {} so we don't bomb. * SPOPS/Secure.pm: - Fix error in warning text, thanks to Andrew Hurst . * SPOPS/SQLInterface.pm: - Apply patch from Raj Chandran that avoids reading type information if the SQL is already provided. * SPOPS/Tool/DateConvert.pm: - Small doc fix and update 0.78 Wed Jun 11 01:05:57 EDT 2003 Overall: * Fix a couple of annoying warnings Individual: * SPOPS.pm: - Fix extraneous warnings. (Thanks Ray Z!) * SPOPS/Tool/DateConvert.pm: - Don't issue warnings when we aren't given a date to convert. 0.77 Tue Jun 10 10:17:08 EDT 2003 Overall: * Bugfix for code generator and be able to convert to/from DateTime objects Individual: * SPOPS/ClassFactory.pm: - In require_config_classes(), ensure we don't try to 'require' an empty class. - In find_behavior(), fix typo that skipped arrayrefs returned from 'behavior_factory' (ouch!) * SPOPS/Tool/DateConvert.pm: - Added implementation for DateTime 0.76 Sat May 10 15:29:09 EDT 2003 Overall: * A number of small bugfixes and enhancements. Individual: * doc/Manual/Configuration.pod: - Add note about 'name' being a property OR method, and about the coderef option being phased out. * SPOPS.pm: - In object_description(), only pull information from CONFIG->{display} if it's actually a hashref. - In object_description(), the scalar in 'name' can be used to specify a method on the object as well as a property of the object; DEPRECATION NOTICE: the coderef option for 'name' will be phased out eventually. * SPOPS/ClassFactory/DBI.pm: - The created foo_add() and foo_remove() methods when doing a 'links_to' relationship were supposed to take an object, or arrayref of objects, to add/remove. They didn't. Now they do. Thanks to Nick Sutterer for the report. * SPOPS/ClassFactory/DefaultBehavior.pm: - Entries that should be parsed into a hash can now take scalars instead of just arrayrefs. - Ensure that certain configuration entries that require an arrayref can take a scalar * SPOPS/DBI.pm: - After an INSERT, don't refetch the ID value. (How did this work before?) - In fetch_group(), honor the 'skip_security' setting; thanks to Peter Dragon for the tip. * SPOPS/Import.pm: - Documentation updates * SPOPS/Import/Object.pm: - Return the object inserted instead of the data structure on success. - assign_raw_data() should make a copy of the data passed in before ripping it up. * SPOPS/Import/DBI/Table.pm: - Add 'return_only' as property, and if set don't execute the transformed table SQL against a database. * SPOPS/Import/DBI/TableTransform.pm: - Create facade 'transform()' method that includes all transformation methods. - Add factory type aliases to deal with capitalization issues. * SPOPS/Secure.pm: - Add empty implementations for global_user_current() and global_group_current() * SPOPS/Secure/DBI.pm: - Don't die if an ID to check is defined. * SPOPS/Tool/DBI/DiscoverField.pm: - Set 'field' config property to an empty arrayref even if we can't fetch the fields. 0.75 Fri Feb 21 08:41:00 EST 2003 Individual: * SPOPS/Exception/DBI.pm: - Add SQL to error messages if it's available. (SF Bug #542521) * SPOPS/Import/DBI/(Table|TableTransform).pm, SPOPS/Import/DBI/TableTransform/*.pm: - Updated to include the 'datetime' datatype. * SPOPS/Tie.pm: - Updated to deal with problem regarding mixed-case column names and lazy loading. * t/05_exception.t: - Modify DBI stringification test to match change in module. * t/37_dbi_lazy_load.t: - Add test for DBI lazy loading. Thanks to David Hugh-Jones for pointing out a problem with lazy loading and mixed-case column names. 0.74 Sun Jan 5 18:38:12 EST 2003 Individual: * SPOPS/DBI.pm: - Reverse change from 0.73 on field_update(): it now returns true if rows were updated, false if not. * SPOPS/SQLInterface.pm: - Added docs to db_discover_info(), including example * SPOPS/DBI/TypeInfo.pm: - Added 'as_hash()' method to represent the fields and types as a nonblessed hash. * t/30_dbi.t: - Updated field_update tests to deal with true/false values rather than the number of rows returned. * t/35_dbi_type_info.t: - Add tests to ensure new 'as_hash()' method works 0.73 Thu Jan 2 01:48:26 EST 2003 Overall: * Bugfix in SPOPS::DBI->field_update * New tool to maintain bidirectional object links * Lots of small POD fixes throughout many files * Removed some previously deprecated classes Individual: * SPOPS/Configure.pm, SPOPS/Configure/(DBI|Ruleset).pm: - Removed classes that have been marked as deprecated since 0.50. * SPOPS/DBI.pm: - Fix field_update() to return the number of rows updated -- if you call it from an object it will always return 1 if the update succeeded. Thanks to Ray Zimmerman for catch. - In save(), move the (saved) and (changed) flags *before* the post_save_action(); if you don't, any updates you do to the object in the post_save_action will be regarded as another INSERT which will either fail (duplicate primary keys) or throw you into an infinite loop (post_save_action keeps inserting new objects). - In save(), ensure that the field/value parameters are cleared out before we tell SQLInterface what we want to insert/update. * SPOPS/Tool/DBI/MaintainLinkedList.pm: - Add new tool to maintain previous/next links in a particular object so you can always navigate. Links are created on an object insert and reshuffled on an object remove. The tool also creates methods 'next_in_list' and 'previous_in_list' so you don't have to craft them by hand. * t/30_dbi.t: - Add more tests for field_update() * t/36_dbi_linked_list.t: - Create tests for SPOPS::Tool::DBI::MaintainLinkedList 0.72 Fri Dec 20 08:34:44 EST 2002 Overall: * Change all references to use new SPOPS website, SF project, etc. * Small bugfixes Individual: * SPOPS/DBI.pm: - Remove reference to assign_dbi_type_info, since this is done in SPOPS::SQLInterface and SPOPS::DBI::TypeInfo now. * SPOPS/DBI/Sybase.pm: - Change docs to use 'increment_field' rather than 'syb_identity' - Add note about using with DBD::Sybase/FreeTDS/MS SQL Server * SPOPS/DBI/TypeInfo.pm: - Supress warnings when checking to see if we were passed a fake or DBI type. * SPOPS/Exception.pm: - Handle a thrown exception object by detecting it as the first argument and rethrowing it. 0.71 Thu Oct 10 08:01:48 EDT 2002 Overall: * Create SPOPS::DBI::TypeInfo object to hold field type information for a table, and replace all callers to deal with the modified return. I don't anticipate this to be disruptive since this is mostly an internal function. * Modify Import/Export classes to use Class::Factory 1.00 Individual: * Makefile.PL: - Bump up requirement for Class::Factory to 1.00 * SPOPS/ClassFactory/DefaultBehavior.pm: - Modify to use new SPOPS::DBI::TypeInfo class * SPOPS/ClassFactory/DefaultBehavior.pm: - Apply patch from Eric Veldhuyzen to suppress 'Subroutine foo redefined...' messages when creating rulesets. * SPOPS/DBI.pm: - Modify to use new SPOPS::DBI::TypeInfo class - Update 'field_update()' with a more stringent test on the return value from db_update() so we return a true value when appropriate. * SPOPS/DBI/TypeInfo.pm: - Add simple object to hold type information for a table. * SPOPS/Import.pm, SPOPS/Import/DBI/TableTransform.pm, SPOPS/Export.pm: - Remove old Class::Factory method/lexical variable, since it keeps track of these now. * SPOPS/SQLInterface.pm: - Modify to use new SPOPS::DBI::TypeInfo class * SPOPS/Tool/DBI/Datasource.pm: - Don't die if 'username' not defined in connection information. * t/35_dbi_type_info.t: - Add tests for new SPOPS::DBI::TypeInfo object (skip if we're using DBD::SQLite, since it's essentially typeless) * t/dbi_config.pl, t/03_uuid.t, t/40_ldap.t, t/41.ldap.t: - Add message for why we're skipping tests 0.70 Mon Sep 16 16:56:33 EDT 2002 Individual: * Makefile.PL: - Added Time::Piece as dependency. * doc/Manual/Security.pm: - Update with reference to implementation class(es) and other small changes. * eg/My/Security.pm: - Update to use SPOPS::Secure::DBI implementation. * SPOPS.pm: - Add check to as_data_only() so we don't return keys beginning with 'tmp' or '_' * SPOPS/Loopback.pm: - Ensure that fetch_group() always returns objects in the same order (sorted by ID). - Modify internals of how objects are stored. - Add security checks like other SPOPS implementation classes. * SPOPS/Secure.pm: - If groups are found from global_group_current() but not a user not found from global_user_current(), go ahead and use the groups to check security. (Previous behavior was to use neither.) - Fix bug in set_security() which, when setting security for multiple scopes at once, always issued a false warning. - In create_initial_security(), always create at least an entry for WORLD. Default setting for this is NONE, so be sure and specify it in your class. * SPOPS/Secure/DBI.pm: - Add implementation class for security objects. You should now only need to add 'SPOPS::Secure::DBI' to the 'isa' of your security object. * SPOPS/Secure/Hierarchy.pm: - Override create_initial_security() so the default security for WORLD will not inadvetently be created. * SPOPS/Secure/Loopback.pm: - Add testing implementation class for security objects. * SPOPS/Secure/Util.pm: - Utility class with common functions for security object implementations. * t/80_security.t: - Add tests for SPOPS security checking. * t/81_security_hierarchical.t: - Add tests for hierarchical SPOPS security checking. * t/SecurityCommon.pm: - Add base class for SPOPS testing objects to use if they need to track users, groups, security class, etc. 0.69 Wed Sep 11 10:59:30 EDT 2002 Overall: * Add new tool (SPOPS::Tool::DateConvert) to convert a date into a date object on object fetch(). * Add tests for SPOPS::Export implementations and add features to loopback tester. * Other small bugfixes. Individual: * SPOPS.pm: - Add USE_CACHE() and set_global_use_cache() methods, which checks and sets caching for all SPOPS objects in a process. Add docs about caching. * SPOPS/ClassFactory/DefaultBehavior.pm: - In conf_modify_config() - ensure that the 'field' property is an arrayref before derefenecing. * SPOPS/Loopback.pm: - fetch(), fetch_group(), save() and remove() will now interact with simple in-memory storage so we can be a little trickier with testing - Add peek() for testing purposes. - fetch_group() allows simple querying of in-memory storage (only of the type field = value) - Add fetch_iterator() which just wraps the result of fetch_group() in a SPOPS::Iterator::WrapList object * SPOPS/Tool/DateConvert.pm: - Add new tool for converting dates into object (Class::Date or Time::Piece) on fetch and into date string in save. * SPOPS/Tool/DBI/Datasource.pm: - Check for valid info should only ensure that DSN and username are defined. An empty password should be ok. (Thanks to Ray Zimmerman for the bug report.) * SPOPS/Utility.pm: - Modify format for today() to be %Y-%m-%d (Thanks to Swen Thuemmler (swen@mediaways.net) for pointing it out.) * t/41_ldap_inline_config.t: - Create simple test for inlining an LDAP configuration. * t/52_rule_date_convert.t: - Add tests for SPOPS::Tool::DateConvert * t/[60_export_object.t,61_export_xml.t,62_export_perl.t, 63_export_sql.t,64_export_dbdata.t]: - Add tests for various SPOPS::Export implementations 0.68 Wed Aug 28 12:36:31 EDT 2002 Individual: * SPOPS/Utility.pm: - Modify the determine_limit() to always explicitly return a 0 when appropriate. * t/07_utility.t: - Modify the list_process() tests to not depend on the order of the items returned. (Test would work on 5.6.x a-ok, but not on 5.8.x -- thanks for report from the CPAN testers.) 0.67 Tue Aug 27 21:19:14 EDT 2002 Overall: * Fix module versions to eliminate conflicts with CPAN -- everything has been upgraded in CVS to a version 3.0 and with a proper VERSION so we can start from a known good version and have no danger of retrograding. Thanks to merlyn for the friendly notice. (Again.) Individual: * t/07_utility.t: - Add tests for functions in SPOPS::Utility (lesson learned!) 0.66 Mon Aug 26 08:24:45 EDT 2002 Overall: * Quick bugfix release Individual: * SPOPS.pm: - Move 'use SPOPS::Utility' to 'require SPOPS::Utility', after the exporting stuff defined * SPOPS/Utility.pm: - Import the DEBUG and _w constants * doc/Manual/Relationships.pod: - Fixed POD error, thanks to Mike Castle for the report. 0.65 Wed Aug 21 17:12:34 EDT 2002 Overall: - Build process will now run without intervention; DBI and LDAP tests require environment variables being set or running the process manually (perl Makefile.PL MANUAL=1). See 'README' for the environment variables used. - Fixed and added lots of documentation on relationships and multifield primary keys, Thanks to Gert Thiel (thiel@baerkatalog.de) for pointing out deficiencies and inconsistencies. - Added lots of tests - Cleaned up some items from the base SPOPS class Individual: * doc/Manual/Error.pod: - Deleted all content with pointer to SPOPS::Manual::Exception. This doc will be removed in a near future release. * doc/Manual/Object.pod: - Clarified what to use with multifield primary keys. * doc/Manual/Relationships.pod: - Added tons of documentation and examples. Some of it was pulled from other locations, but most is new. * Makefile.PL: - Lots of changes so the build process will run without intervention. You can skip the DBI/LDAP tests or specify the relevant information in environment variables. (See 'README' for the environment variables to use.) This should make acme happy :-) * SPOPS.pm: - Removed the timestamp methods. They never did anything, were marked for removal, and the functionality can be added as a pre_save rule. - Added a set_global_debug() method so we can programmatically set debugging. - Added documentation for set_global_debug() as well as the _w() and _wm() debugging methods. - Remove Storable from ISA and instead create methods 'store', 'retrieve' and 'nstore' which just act as delegates for the Storable methods. - Rename fetch_determine_limit() to SPOPS::Utility->determine_limit() and modify all uses in the library. - All objects returned from new() now have the 'changed' flag explicitly set and the and the 'saved' flag explicitly cleared. - Be able to turn on strict field checking for individual objects (pass a 'strict_field => true' to new()) * SPOPS/ClassFactory/DBI.pm: - Enable fetch() to use either an arrayref or a string with multifield primary keys. Thanks to Gert Thiel for prompting the change. * SPOPS/ClassFactory/DefaultBehavior.pm: - Add brief documentation for the different methods. * SPOPS/DBI.pm: - Update field_update() so it can operate as a class method, and add documentation to match. Thanks to Ray Zimmerman for noting the tangential reference to class method usage in previous docs. - Add SET_DEBUG_FETCH() and SET_DEBUG_SAVE() to programmatically set debugging levels. * SPOPS/SQLInterface.pm: - Add SET_DEBUG_SELECT(), SET_DEBUG_INSERT(), SET_DEBUG_UPDATE() and SET_DEBUG_DELETE() to programmatically set debugging levels. * SPOPS/Tool/CreateOnly.pm: - Issue a die() rather than a warn() on a save/update. * SPOPS/Tool/ReadOnly.pm: - Issue a die() rather than a warn() on a save() or remove() * t/00_base.t: - Add tests for the base SPOPS methods (metadata, constructor, cloning, etc.) * t/20_gdbm.t: - Separate the tests that were combining different tests in one. * t/30_dbi.t: - Add tests for field_update() as a class method * t/32_dbi_inline_config.t: - Add tests for SPOPS::Tool::DBI::Datasource * t/33_dbi_discover_field.t: - Add tests for SPOPS::Tool::DBI::DiscoverField * t/34_dbi_find_defaults.t; - Add tests for SPOPS::Tool::DBI::FindDefaults * t/50_rule_create_only.t: - Add tests for SPOPS::Tool::CreateOnly * t/51_rule_read_only.t: - Add tests for SPOPS::Tool::ReadOnly 0.64 Sun Aug 11 23:08:05 EDT 2002 Individual: * README - Modified standalone script (we moved the tools to SPOPS::Tool) and added Interbase/Firebird to the list of supported databases. * SPOPS/DBI.pm: - Update fetch() to check to see if the ID passed in is defined *and* non-empty. Thanks to Hal Finkel for pointing this out. (SF Bug #572661) * t/30_dbi.t: - Add tests to ensure that trying to fetch an object with a blank ID and with an undef ID returns undef. 0.63 Sat Aug 10 09:30:43 EDT 2002 Overall: * Small fix to t/40_ldap.t to ensure it doesn't run when it's not supposed to 0.62 Fri Aug 9 23:21:08 EDT 2002 Overall: * A few small but useful changes, mostly to SPOPS::DBI and mostly written by someone else. Individual: * SPOPS/DBI.pm: - Added method 'refetch()' to class. This fetches the values for a limited number of fields for a particular object and updates the object. Thanks to Ray Zimmerman for the full implementation and documentation! - Added method 'field_update()' to class. This updates the values for a limited number of fields, or performs an update across several objects at once. Thanks to Ray Zimmerman for the full implementation and documentation! - Added method 'filter_fields()' to class. This ensures that a list of fields or the keys in a hashref are not private and are translated properly using the field map. (This is likely only to be used within the class or subclasses.) - Allow call to 'save()' to pass per-object definitions for 'skip_undef', 'no_insert' and 'no_update' and ensure that 'no_insert' fields are refetched post-insert just like 'sql_defaults' fields are. * SPOPS/LDAP.pm: - Ensure that 'skip_undef' is implemented for both inserts and updates, and allow call to 'save()' to pass per-object definitions for that and for 'no_insert' and 'no_update'. * SPOPS/Tool/CreateOnly.pm: - Simple behavior to ensure that objects can only be created, not updated. * t/30_dbi.t: - Add tests for refetch() and field_update() - Add tests for 'no_insert' and 'no_update' passed along with save() 0.61 Mon May 6 21:44:57 EDT 2002 Overall: * Quick bugfix release: SPOPS::DBI::MySQL quoting fix and warning removed for incorrect EXPORT_OK declaration for SPOPS::Exception::Security Individual: * SPOPS/DBI/MySQL.pm: - Override sql_quote() to use the two-argument form of $dbh->quote(). (Thanks to Ray Zimmerman for the pointer.) * SPOPS/Exception/Security.pm: - Fix typo: $...::EXPORT_OK -> @...::EXPORT_OK. (Thanks to Ray Zimmerman for the spot.) 0.60 Mon May 6 08:45:34 EDT 2002 Overall: * New feature: Initial support for InterBase family of databases (InterBase and FirebirdSQL), using the DBD::InterBase driver. There is one major caveat: if you're using security with your objects, you cannot use the same database handle for security as other objects. (See other notes below.) * New feature: SPOPS::DBI classes can modify the value inserted into the database when calling save() on a new object. See 'insert_alter' documentation in SPOPS::DBI. * Added tools previously in 'eg/' to the main distribution, now found in SPOPS::Tool * Small bugfixes and enhancements. Individual: * Makefile.PL: - Registered InterBase as a valid DBD * doc/Manual/Configuration.pod: - Document new 'insert_alter' configuration item for SPOPS::DBI objects. * doc/Manual/Exceptions.pod: - Document exception shortcuts. * SPOPS/DBI.pm: - Fix bug in perform_lazy_load() so we allow field-mapped fields to be lazy-loaded as well. (Thanks to Bill Heckel for the bug report.) - Fix fetch_count() so it uses a fully-qualified column to select the count. (Thanks to Ray Zimmerman for patch.) - Add id_field_select() to provide a list of fields suitable for a SELECT statement. - Add configuration callback for 'insert_alter' that holds information to transform values on a save() for a new object. - Add apply_insert_alter() that is called on an insert to process the new 'insert_alter' directive. Note that the fieldname entries in the configuration must be in lower-case. - If lazy-loading is turned on, don't try to lazy-load fields beginning with a '_'. Add note and example about this in docs. * SPOPS/ClassFactory.pm: - Fixed error messages (SF Bug #533134) * SPOPS/ClassFactory/DBI.pm: - Add id_field_select() to be generated for multifield primary keys. - Fixed error messages (SF Bug #533134) * SPOPS/DBI/InterBase.pm: - Add support for InterBase family of databases. This was only tested using FirebirdSQL 1.0 running in SuperServer mode on Linux using DBD::InterBase 0.30. This seems to work but is still considered experimental until I learn more about this database or someone who is knowledgable can set me straight. (If you're one of those people, email me at chris@cwinters.com.) * SPOPS/Exception.pm: - In shortcut 'spops_error' changed normal subroutine call to a goto &sub to keep caller stack intact. * SPOPS/Exception/DBI.pm: - Added shortcut 'spops_dbi_error' * SPOPS/Exception/LDAP.pm: - Added shortcut 'spops_ldap_error' * SPOPS/Exception/Security.pm: - Added shortcut 'spops_security_error' * SPOPS/Import/DBI/TableTransform.pm: - Add mappings for 'interbase' and 'firebird' * SPOPS/Import/DBI/TableTransform/InterBase.pm: - Add table transformation strings for InterBase family * SPOPS/SQLInterface.pm: - Modify db_discover_types() to try both $dbh->{Name} and $dbh->{name} for the database name. Thanks to Florian Hellberg for the bug report. - Use 'spops_error' and 'spops_dbi_error' shortcuts for all exceptions * SPOPS/Tool/ReadOnly.pm: - Add tool to make objects read-only. * SPOPS/Tool/UTFConvert.pm: - Add tool to do UTF8 translation to-from a datasource. (See warnings.) * SPOPS/Tool/DBI/DisoverField.pm: - Add tool to do automatic field discovery for DBI-based objects. * SPOPS/Tool/DBI/Datasource.pm: - Add tool to embed DBI datasource connection information in the object configuration. * SPOPS/Tool/DBI/FindDefaults.pm: - Add tool to get field defaults from a particular record. * SPOPS/Tool/LDAP/Datasource.pm: - Add tool to embed LDAP datasource connection information in the object configuration. * t/dbi_config.t: - Registered InterBase type * t/30_dbi.t, t/31_dbi_multifield.t: - Add test for output of new methods id_field_select() - Add more tests (id_clause) - Add test for 'insert_alter' * t/06_ruleset.t, t/SampleRuleset.pm: - Add files for testing rulesets -- very sparse for the moment. 0.59 Mon Mar 18 23:33:06 EST 2002 Overall: * Fix module versions to eliminate conflicts with CPAN -- everything has been upgraded in CVS to a version 2.0 so we can start from a known good version and have no danger of retrograding. Thanks to Merlyn for the friendly notice. 0.58 Thu Mar 14 09:03:35 EST 2002 Overall: * Modified DBI id_clause() quoting (in both single and multifield keys) so it will call ->sql_quote() (in SPOPS::SQLInterface or overridden by the SPOPS DBI driver class) instead of ->quote() directly on the db handle, since some drivers don't know what to do with the extra type information. (Found with latest version -- 0.11 -- of DBD::SQLite.) Individual: * SPOPS/DBI.pm: - Updated id_clause() to call ->sql_quote(). See 'Overall' for notes. * SPOPS/ClassFactory/DBI.pm: - Updated the generated id_clause() for multifield primary keys to call ->sql_quote(). See 'Overall' for notes. 0.57 Sat Feb 23 14:02:22 EST 2002 Overall: * SPOPS now works with Oracle! All tests pass and all the scripts under eg/ work ok as well, but you might consider this support beta until someone who actually knows Oracle takes a look. * SPOPS now works with SQLite! SQLite is an embeddable database, and DBD::SQLite comes with the database source ready to compile. You can use it instead of DBD::Sprite or DBD::CSV -- it is much faster and behaves like a real database. Kudos to the indefatigable Matt Sergant! * Fix tests and (hopefully) Makefile.PL to follow all dependencies properly. Individual: * Makefile.PL: - Add 'Class::Factory' as a dependency * eg/fetch_all.pl: - Display all known objects in eg/ modules * eg/users_groups_oracle.sql, eg/users_groups_clear_oracle.sql: - Data create/clear scripts for Oracle * eg/users_groups_sqlite.pl: - Data create script for SQLite * eg/My/(User|Group|Doodad|Security).pm: - Use named sequences versus relying on default behavior * SPOPS.pm: - Modified clone() to respect false-but-defined values passed in for the new object. Thanks to Ray Zimmerman for the patch. * SPOPS/DBI.pm: - Add 'sql_case_insensitive' to allow drivers to specify a case-insensitive operator. (Default: 'LIKE', which may or may not work for all databases but at least it will not break anything.) - Add docs for the pre_fetch_id() and post_fetch_id() callbacks to get/find ID values on an insert. - The return value from pre_fetch_id() is by default set to no_quote -- the implementer of pre_fetch_id() is responsible for either quoting it or for telling SPOPS::DBI that it is ok to quote it using the normal means. * SPOPS/DBI/Pg.pm: - Specify the '~*' case-insensitive operator - Modify how we fetch/retrieve sequence values. * SPOPS/DBI/Oracle.pm: - Hey, we support Oracle now! (See above) * SPOPS/DBI/SQLite.pm: - Hey, we support SQLite now! (See above) * SPOPS/Exception.pm: - You can now pass as many arguments as you want to throw() -- they will all get concatenated into the exception message unless the last one is a hashref, which will be set to the optional parameter hashref. * SPOPS/Import.pm, SPOPS/Export.pm: - Modify to use Class::Factory * SPOPS/Import/TableTransform/(Oracle|SQLite).pm: - Add table transforms for Oracle and SQLite * SPOPS/Key/(Random|UUID).pm: - Quote the return value from pre_fetch_id() * SPOPS/Secure.pm: - Add a 'require SPOPS::Exception::Security' to bring in the module, but add it after all the constants have been defined so we don't get into a deadlock * t/05_exception.t: - Modify stringification comparison to work properly all the time * t/30_dbi.t, t/31_dbi_multifield.t, t/40_ldap.t: - Only run the END {} if we're running the tests * t/dbi_config.pl: - Add Oracle-specific info 0.56 Tue Jan 15 07:17:02 EST 2002 Overall: * Overhauled the error reporting scheme to use exceptions instead of package variables; as a result, modified all files that used 'die' to indicate error to throw an exception object instead. (Backwards compatibility is maintained by echoing the error information to SPOPS::Error as before.) * Added examples for specifying DBI/LDAP connection information in an object configuration, useful for one-off scripts Individual: * Makefile.PL: - Check to see whether Data::UUID is installed. (Thanks to brian moseley for pointing out the test failure.) - Add Devel::StackTrace as a dependency, as well as the Class::Accessor dependencies * eg/datasource_configure.pl: - Added example of specifying DBI configuration in object configuration * eg/datasource_configure_ldap.pl: - Added example of specifying LDAP configuration in object configuration * eg/My/DBI/DatasourceConfigure.pm: - Added sample behavior to create a 'global_datasource_handle()' for a class to return a DBI handle based on the configuration information in the object. * eg/My/LDAP/DatasourceConfigure.pm: - Added sample behavior to create a 'global_datasource_handle()' for a class to return a LDAP handle based on the configuration information in the object. * SPOPS/DBI.pm: - Fixed fetch() to deal with: fetch( 0 ) properly (use: 'if defined $id' rather than 'if $id') and remove the default set of $id to 0 as well (SF Bug: #500514) * SPOPS/Exception.pm: - Added base class for exceptions in SPOPS (to replace SPOPS::Error with backwards compatibility) * SPOPS/Exception/DBI.pm: - Create exception class for DBI-specific errors * SPOPS/Exception/LDAP.pm: - Create exception class for LDAP-specific errors * SPOPS/Exception/Security.pm: - Create exception class for security errors * SPOPS/Iterator/DBI.pm: - Ensure we can handle ID field intialization properly, add helpful debugging messages and get rid of redundant offset check * SPOPS/Iterator/LDAP.pm: - Add helpful debugging messages and get rid of redundant offset check * SPOPS/Manual/Exceptions.pod: - Add manual section on exceptions. * t/03_uuid_key.t: - Check the build configuration to see if the test should run * t/05_exception.t: - Added tests for exceptions 0.55 Mon Dec 31 00:49:15 EST 2001 Overall: - Added data import and export capabilities to SPOPS - You can now use a UUID (Universally Unique Identifier) as a key Individual: * eg/export_doodads.pl: - Added sample for SPOPS::Export::Object * eg/import_doodads.pl: - Added sample for SPOPS::Import::Object * SPOPS/DBI/Pg.pm: - Fixed item to allow specification of the sequence name in object configuration * SPOPS/Export.pm: - Added factory class and parent to exporting routines * SPOPS/Export/Object.pm: - Added simple class to take existing data and export it to a portable format. * SPOPS/Export/Perl.pm - Added simple class to export SPOPS objects to a raw perl data structure. * SPOPS/Export/SQL.pm - Added simplistic class to export SPOPS objects to a series of SQL INSERT statements. * SPOPS/Export/XML.pm: - Added simplistic class to export SPOPS objects to XML format * SPOPS/Import.pm: - Added factory class and parent to importing routines * SPOPS/Import/DBI/Table.pm: - Added class for importing/translating DBI tables. This should allow you to create a database-neutral schema and have SPOPS translate it dynamically. * SPOPS/Import/DBI/TableTransform.pm: - Added parent factory class for creating transformation objects * SPOPS/Import/DBI/TableTransform/MySQL.pm: - Added transformer for generic tables to MySQL * SPOPS/Import/DBI/TableTransform/Pg.pm: - Added transformer for generic tables to PostgreSQL * SPOPS/Import/DBI/TableTransform/Sybase.pm: - Added transformer for generic tables to Sybase (ASE, ASA and MS SQL) * SPOPS/Import/Object.pm: - Added a simple class to bring into an SPOPS datastore data formatted by something like SPOPS::Export::Object. * SPOPS/Key/Random.pm: - Wrapped the call to $class->CONFIG in an eval {} in case we're not calling this from an SPOPS class/object * SPOPS/Key/UUID.pm: - Created new method for generating keys. The Universally Unique Identifier is a fairly long string whose uniqueness is (more or less) guaranteed -- the docs for Data::UUID say that it's good for millions of keys per second, which is good enough for me :-) (Note: this apprently does not work on Win32 systems; pointers are welcome for either a Perl module or an external program that can do this.) * SPOPS/Loopback.pm: - Created a dummy SPOPS class useful for testing. It runs all the pre/post actions, so you can test out your rules on it as well. * SPOPS/Manual/ImportExport.pod - Added manual section for importing and exporting data. * t/03_uuid_key.t: - Created test for SPOPS::Key::UUID * t/04_random_key.t: - Created test for SPOPS::Key::Random 0.54 Tue Nov 27 07:42:59 EST 2001 Overall: - Fix bug introduced by 0.53 in the clone() method. (Thanks to Ray Zimmerman for spotting.) Individual: * SPOPS.pm: - Modify clone() method to behave as previous -- the multifield-specific behavior is now in a separate method * SPOPS/ClassFactory/DBI.pm: - Generate clone() method for classes using multifield primary keys * t/31_dbi_multifield.t: - Modify clone save() test (#12) to specify one value of the ID in the clone() call and set the other one afterward. 0.53 Sat Nov 24 20:50:32 EST 2001 Overall: - SPOPS::DBI now supports multiple-field primary keys - Small bugfixes Individual: * eg/My/ReadOnly.pm: - Example of how you can create read-only objects in SPOPS. * eg/My/UTFConvert.pm: - Example of converting to/from unicode values for datasources that store unicode (WARNING: This is a demo only, and only works for those 5.6.0 and earlier versions of perl that support 'use utf8') * SPOPS.pm: - Modified how the ID value gets set in initialize() if { id => 'blah' } is passed in -- this modification enables multifield keys to work properly. * SPOPS/ClassFactory/DBI.pm: - Add id_clause() and id() methods to classes using multiple-field primary keys (see below). * SPOPS/DBI.pm: - Fixed the function that gathered up fields to select to ignore putting the table name in front of a field unless it has the 'table.' in front, not just 'table' - Enable multi-field primary keys. All you need to do is specify multiple fields for your id_field: Single field: id_field => 'object_id', Multiple field: id_field => [ 'creation_time', 'created_by' ] SPOPS::DBI will take care of the rest for you. To retrieve a multi-field record, you just need to specify the ID values stringified: # '1005082576' is the creation_time, '45' is the ID of the # user who created it my $obj = My::Object->fetch( '1005082576,45' ); * SPOPS/HashFile.pm: - Always make a backup before doing anything, and keep it around rather than deleting it. * t/dbi_config.pl: - Moved certain information from t/30_dbi.t here and generalized for other DBI tests. * t/30_dbi.t: - Modified to use dbi_config.pl for certain behaviors * t/31_dbi_multifield.t: - Added tests for multi-field primary keys. 0.52 Thu Oct 25 23:19:43 EDT 2001 Overall: - You can now specify defaults for objects so when you instantiate one via new() the values get automatically filled in. There are different ways to set these defaults -- see SPOPS::Manual::Configuration and SPOPS::Manual::CodeGeneration for examples and ideas. - Enhancements to SPOPS::LDAP::Multidatasource - Bugfixes, including one in SPOPS::ClassFactory::DefaultBehavior that broke old apps using rules Individual: * eg/find_defaults_demo.pl: - Self-contained script used to demonstrate how My::DBI::FindDefaults works. * eg/ldap_multidatasource.pl: - Added script to demonstrate (along with eg/My/LDAPConnect.pm) how multiple datasources work with SPOPS::LDAP::MultiDatasource * eg/My/DBI/FindDefaults.pm: - Example of a SPOPS::ClassFactory behavior that retrieves the information from a particular record to use as defaults. * eg/My/LDAPConnect.pm: - Example of an LDAP connection manager that works with multiple datasources. * SPOPS.pm - Enable default values to be set via the object configuration (or dynamically, via ClassFactory) that are used to fill up an object created with new(). You can also use the key 'NOW' to specify the current date/time or a class and method to deal with more complicated tasks. (Accompanying this, modified all implementations -- DBI, LDAP and GDBM -- plus the iterators -- DBI and GDBM -- to pass a 'skip_default_values => 1' when creating a new object to be filled with a fetch() or fetch_group().) * SPOPS/DBI/MySQL.pm: - Added SPOPS::ClassFactory behavior so we can tell MySQL to find defaults for fields. * SPOPS/ClassFactory/DefaultBehavior.pm: - Bugfix: rulesets used to be generated using the method 'ruleset_add'. We now use 'ruleset_factory' since it's more descriptive and consistent with the behavior generation code. However, we forgot to keep the old method enabled for a few versions. Fixed. (Thanks to Peter Beardsley for the report.) * SPOPS/LDAP/MultiDatasource.pm: - Make datasources sticky -- each object should be able to find out where it came from (modified fetch() and fetch_group_all() with this). - Override save() and remove() so that we first grab the right handle (from the datasource put into the object) and pass it along to the method that does the real work. - Create fetch_by_dn() so you can actually store in a group the DNs for objects that reside on multiple servers. (Cool!) Thanks to Andreas Nolte for testing this out. 0.51 Sun Oct 14 20:23:59 EDT 2001 Overall: - Centralized SPOPS documentation started - LDAP bugfixes and additional tests - Other fixes and goodies Individual: * SPOPS/Manual*: - Added first draft of SPOPS manual. Note that much of the documentation was removed from other classes, reworked and placed here. For example, all discussion of configuration keys is now in one place, SPOPS::Manual::Configuration. Some pieces of the manual are fairly complete while others are barren. To start, just do 'perldoc SPOPS::Manual'. * eg/(items from 0.50): - Actually added these to the distribution (doh!) * eg/My/DiscoverField.pm: - Added sample ClassFactory behavior for auto-discovering fields in a DBI datasource and using all of them as object properties. * SPOPS/ClassFactory.pm: - Allow rules-only classes to be specified in the configuration field 'rules_from' in addition to in the 'isa' (used for ClassFactory behaviors). - change require_isa() to require_config_classes(), and enable it to require the 'rules_from' classes as well * SPOPS/ClassFactory/DBI.pm: - Change 'warn' calls when we get an error to 'SPOPS::_w' calls, to fit with everything else - Change generated 'links_to' methods so that we get the database handle from the correct class. (This hasn't been a problem for people because most people use the same datasource to hold related objects. But SPOPS doesn't care!) * SPOPS/ClassFactory/DefaultBehavior.pm: - Allow rules-only classes to be specified in the configuration field 'rules_from' rather than in the 'isa' (used for rulesets) * SPOPS/ClassFactory/LDAP.pm: - Add %alias%_add() and %alias%_remove() calls to the 'has_a' methods. - Move certain parameter-parsing and object-getting functionality from separate generated methods and into a method that gets installed via the 'read_code' slot in the ClassFactory process. * SPOPS/Iterator/(DBI|LDAP).pm: - Fixed off-by-one error when using 'limit' * SPOPS/Iterator/WrapList.pm: - Added simple implementation of SPOPS::Iterator to wrap around an already-existing list of objects. * SPOPS/LDAP.pm: - Modified the save procedures to first fetch the existing object then implement a 'replace' on only the items that SPOPS knows about. - Modified 'fetch()' to work properly with a secured object that is fetched with a filter rather than an ID. - 'fetch_by_dn()' is much more sensible about how it works (it now does a search for all objects below the particular DN and returns the only one that should be there) - Pulled out pre- and post- actions from fetch() so that other methods can use them. - You can force a filter to not be used by passing a true value for the 'no_filter' parameter key to 'fetch' - ensure that _perform_postfetch() looks at the {skip_security} setting before checking security on a 'delay_security_check' (Thanks to Andreas Nolte ) * SPOPS/Secure.pm: - Move security error reporting (putting error info into SPOPS::Error plus the 'die' call) into a separate method so it can be called from elsewhere * t/40_ldap.t: - Add tests for new feature signified by ldap_update_only_changed configuration flag - Add tests for 'has_a' and 'links_to' linking functionality 0.50 Tue Aug 28 16:59:39 EDT 2001 Overall: - You can now use LDAP to store your objects! Also included is SPOPS::LDAP::MultiDatastore, which lets you specify multiple directories to query for objects. Thanks to MSN Marketing Service Nordwest, GmbH, for funding development! - Configuration process has been totally rewritten and renamed (SPOPS::ClassFactory) - Added multivalue and name mapping functions tie interface Individual: * Makefile.PL: - Added support for non-interactive execution ('perl Makefile.PL AUTO' if you have a 'spops_test.conf' file around from a previous test) - Added support for LDAP test definitions * eg/README: - Information about the examples now here * eg/stock_user_group.pl: - Added script to stock the sample user/group/security objects. * eg/users_groups_(mysql|psql|tsql).sql - Added SQL structure files for the sample user/group/security objects. * eg/My/(Common|Group|Security|User).pm: - Define sample user/group/security objects. * SPOPS.pm: - Added (and documented) a few keys to the information returned by the 'object_description' method. - Documented information that is used in object configuration for the tie interface by the 'new()' method. - Modified 'initialize()' to set object values passed to new() - Removed 'global_config()' method and the need for it -- it was only being used for caching and when we tackle that we'll figure out what's necessary. - Moved a number of cache methods from SPOPS/DBI.pm here - Removed the '_idx_data()' method - The 'clone()' method can now clone an object from one class to another given the parameter '_class'. This could be an extremely easy way to copy objects having the same interface from one datastore to another. (See POD for an example.) - Moved the method '_determine_limits()' from SPOPS/DBI.pm here, renaming it 'fetch_determine_limit()' - Added 'behavior_factory' which installs the default behaviors (found in SPOPS::ClassFactory::DefaultBehavior) to subclasses - Added 'as_html' to represent an object as HTML. (Note that the default just wraps 'as_string' in '
' tags. U-G-L-Y. Override
     if you value aesthetics.)

   * SPOPS/ClassFactory.pm:

     - Added new configuration process. Instead of a monolithic
     process this class simply gathers behaviors for a class based on
     its inheritance tree. These behaviors are put into a particular
     slot (type) and run in turn. This is quite extensible and easy to
     customize. See POD for more.

   * SPOPS/ClassFactory/DefaultBehavior.pm:

     - Holds default behaviors run (potentially) by every SPOPS subclass

   * SPOPS/ClassFactory/DBI.pm:

     - Holds implementation-specific behaviors for subclasses of
     SPOPS::DBI

   * SPOPS/ClassFactory/LDAP.pm:

     - Holds implementation-specific behaviors for subclasses for
     SPOPS::LDAP

   * SPOPS/DBI.pm:

     - Moved 'check_action_security()' to SPOPS::Secure

     - Removed 'initialize()' (now inherits from SPOPS.pm); caching
     methods (moved to SPOPS.pm)

     - Moved '_determine_limits()' to SPOPS.pm as
     'fetch_determine_limit()'

     - Added 'behavior_factory' which installs the
     implementation-specific behaviors (found in
     SPOPS::ClassFactory::DBI) to subclasses

   * SPOPS/Initialize.pm:

     - Better documented the process() method and added the ability to
     pass multiple already-formed SPOPS configuration hashrefs at
     once.

     - Modified to work with SPOPS::ClassFactory

   * SPOPS/Iterator/LDAP.pm:

     - Added implementation of SPOPS::Iterator for SPOPS::LDAP

   * SPOPS/LDAP.pm:

     - Added new datastore for SPOPS. You can now save, fetch and
     remove objects from an LDAP datastore as you would a DBI
     datastore.

   * SPOPS/LDAP/MultiDatastore.pm:

     - Add subclass to SPOPS::LDAP - be able to query multiple
     directories at once by using this (instead of SPOPS::LDAP) as a
     parent class and specifying multiple datasources in the object
     configuration.

   * SPOPS/Secure.pm

     - Updated docs and added information about subclassing to create
     custom security.

     - Added method 'check_action_security()' from SPOPS/DBI.pm so
     that other implementation classes can use it and
     non-SPOPS::Secure objects can just call the stub in SPOPS.pm.

   * SPOPS/SQLInterface.pm

     - Patch from Ray Zimmerman to actually return data when you
     specify a return value of 'hash' for db_select().

     - Patch from Ray Zimmerman to return from 'db_insert()',
     'db_update()' and 'db_delete()' the return value from the
     '$sth->execute()' statement. This is an API change but a very
     small one -- if successful the return value should still be true,
     since even if (for instance) an update affects no rows DBI
     returns '0E0' which is numerically zero but evaluates to
     true. Also added note regarding various return values to
     'db_update()' docs.

   * SPOPS/Tie.pm

     - Added functionality for multivalued properties. A single
     property can have non-duplicate, unordered multiple values. This
     is necessary for SPOPS::LDAP. (Documentation included!)

     - Added functionality for field mapping. This allows you to
     retrofit an existing object interface to a table scheme with
     different field names. (Documentation included!)

   * t/*

     - Renamed all tests from 'name.t' to '##_name.t' so we can have
     some control over the order in which they're executed.

     - Added LDAP test suite (40_ldap.t).


0.41  Fri Jul 20 07:00:38 EDT 2001

   Overall:

     - Added iterators to scroll sensibly through resultsets

     - Handful of bugfixes and changes.

     - Removed the previously deprecated SPOPS::DBI::RandomCode; use
     SPOPS::Key::Random instead

     - Added more tests and new testing scheme

   API CHANGES:

     - The return value of 'save()' is now the object itself rather
     than the object's ID. This allows you to perform chained method
     calls like:

       $obj->save()->perform_other_method();

     Or even:

       $film->add_director( 
                 Director->new({ name => 'Peter Jackson' })->save );

   * SPOPS.pm:

     - Document special lazy loading column group '_id_field'

     - Added 'is_saved()' which returns true if the object has been
     saved. (Old method 'saved()' is still there but may be removed at
     a later date.)

     - Moved 'id()' method to be in the auto-generated class.

     - Moved all credits to this file.

   * SPOPS/Configure.pm:

     - Ray Zimmerman  caught a little bug in
     'find_config_class()' that might have prevented
     'SPOPS::Configure::DBI' from getting invoked properly, which
     would have almost certainly led to mass hysteria.

     - Ray Zimmerman also caught a typo in the hasa processing.

     - Cleaned up docs.

     - Moved 'id()' method from SPOPS.pm so a subclass won't get a
     superclass's ID.

   * SPOPS/Configure/DBI.pm:

     - Cleaned up docs.

   * SPOPS/Configure/Ruleset.pm:

     - Cleaned up docs.

   * SPOPS/DBI.pm:

     - Implement special lazy loading column group '_id_field'

     - Added 'fetch_iterator()' method which sets up the information
     for the iterator (runs the query and gets the statement handle)
     and returns it.

     - Fixed wrong call in 'remove()' that was supposed to check
     whether the object had been saved. (Thanks to Ray Zimmerman.)

   * SPOPS/Iterator.pm:

     - Added new class for an Iterator, or an object that allows you
     to step through a resultset one at a time rather than forcing you
     to retrieve the entire thing into memory at once. This class
     defines the interface as well as the state variables and
     methods. Implementing classes only need to implement three
     methods to make it work. See docs (which are pretty complete) for
     more info.

   * SPOPS/Iterator/DBI.pm:

     - Added SPOPS::DBI implementation of iterator.

   * SPOPS/SQLInterface.pm:

     - Allow 'from' to be a scalar in 'db_select()'

     - Add 'group' -- mapping to 'GROUP BY' clause -- as a parameter
     for 'db_select()'


0.40  Sun Jun 10 14:50:20 EDT 2001

Overall: 

   * Modified how debugging works (again). This should be a
     performance gain -- thanks to posts and pointers on a recent
     thread on the mod_perl mailing list (April 2001, "Cutting down on
     the DEBUG bloat...")

   * Initialization is easier: SPOPS::Initialize should take care of
     the details for you. (Thanks to David Boone  for
     asking about this.)

   * PostgreSQL now supported, as are sequences as a key generation
     tool which should open the door for Oracle support.

   * Lazy loading of objects now supported. You can specify a logical
     group of properties and ask that only those be fetched. Your
     database will thank you, as will your memory in a persistent
     environment. See 'LAZY LOADING' in SPOPS.pm for details. (Please
     note that this is a quite new feature and if you have any
     problems and/or feedback, share!) (Tip 'o the hat to Class::DBI
     and Master Schwern for inspiration.)

   * Note: To use strict field checking, you need to set
     'strict_field' in your object configuration to a true value.

Specifics:

   * All modules: (hopefully) fixed version numbering CPAN issues.

   * SPOPS.pm:

     - Implemented (and documented!) the lazy-loading interface.

     - Better documented rulesets (thanks to Ray Zimmerman for
     prodding).

   * SPOPS/Configure.pm

     - The primary method in this class ('process_config()' now uses
     whatever configuration subclass is appropriate. For instance, if
     an SPOPS object has 'SPOPS::DBI' as a parent it will use
     'SPOPS::Configure::DBI'. Generally this just ensures that extra
     capabilities of the configuration subclass get used (like
     'create_relationships()') but it's open-ended enough to allow
     interesting things...

     - Added some inline and POD documentation to clarify matters.

   * SPOPS/Configure/DBI.pm: Thanks to Ray Zimmerman
      for spotting an error in the generated
     '_remove()' subroutine -- it wasn't passing the parameters
     (namely a database handle) through to the 'id_clause()' method
     call.

   * SPOPS/Configure/Ruleset.pm:

     - Fixed error so that an inheritance diamond won't load the same
     rule into the ruleset twice, spotted by Ray Zimmerman
     .

   * SPOPS/DBI.pm

     - Modified fetch_group() to accommodate a 'limit' parameter,
     which allows limit the number of returned objects as well as
     slice that number offset from the beginning. Patch by Rusty
     Foster .

     - Also (inspired by Rusty) modified fetch_group() to retrieve
     entire records rather than just the ID field and submitting that
     to a fetch() call -- security is still checked just like before,
     but since we refactored that action into its own routine we can
     call it from both 'fetch()' and 'fetch_group()'.  This should
     immediately reduce the number of database calls.

     - Added (and documented) a new method fetch_count() which
     executes a query and counts up the number of records it would
     have fetched. This **includes** security restrictions. (Otherwise
     it would be misleading...)

     - Refactored a number of actions from fetch() and fetch_group()
     into separate routines, including _fetch_select_fields() which
     returns the raw fields plus the formatted fields.

     - Added lazy-loading routines meeting the SPOPS interface.

     - fetch_group() will now only prepend the table name to columns
     that aren't formatting select statements (e.g., not to
     "DATE_FORMAT( fieldname, '%a...' )"

     - added docs regarding database handles -- how to create a
     'global_db_handle()' method, etc.

   * SPOPS/DBI/Pg.pm: Added first draft of PostgreSQL DBI
     adapter. It's been tested and seems to work pretty well with
     OpenInteract, which itself is a decent SPOPS test. Uses the
     'SPOPS::Key::DBI::Sequence' class to implement auto-incrementing
     fields.

   * SPOPS/DBI/Sybase.pm: Use the now-standard 'increment_field'
     boolean to see whether we're using an IDENTITY field for key
     generation or not. (Thanks to Harry Danilevsky
      for pointing it out.)

   * SPOPS/Impl/SecurityObj.pm: Lots of refactoring.

   * SPOPS/Key/DBI/Sequence.pm: Added first draft of a sequence key
     generator (found in many databases, including PostgreSQL and
     Oracle). 

   * SPOPS/Secure.pm, SPOPS/Secure/Hierarchy.pm

     - Renamed the field 'oid' to 'object_id' to get around databases
     that use 'oid' as a reserved word (like PostgreSQL).

     - Renamed the field 'level' to 'security_level' to get around
     databases that have 'level' as a reserved word (like
     Sybase). While this is a fairly fundamental change from the
     database schema side of things, people simply using SPOPS as it
     was intended shouldn't feel any changes except for altering the
     table in which the security information is kept. (But that's an
     implementation issue :-)

   * SPOPS/Secure/Hierarchy.pm: Fixed the 'create_root_object' call to
     SPOPS::Secure->set_security() to call the right method with the
     right parameter types. Added some docs.

   * SPOPS/SQLInterface.pm: Documented the value 'sth' for the
     'return' parameter of db_select(). 


0.39 Sun Feb 25 13:50:56 EST 2001

   * SPOPS.pm, SPOPS/Tie.pm, SPOPS/DBI.pm: Created a 'saved' flag
     within the tied hash so that we always know whether a record has
     been retrieved from a data store or not.

   * SPOPS/DBI.pm: Prompted by Christian Lemburg
     : modify check_action_security() to see
     whether the action is an add or not, and if so pass back
     SEC_LEVEL_WRITE since SPOPS relies on your application to ensure
     that a user can create an object. (Should SPOPS implement this?
     Let us know on the openinteract-dev mailing list at
     http://lists.sourceforge.net/lists/listinfo/openinteract-dev)
     Also added documentation to the save() method.

   * SPOPS/DBI.pm, SPOPS/Key/Random.pm, SPOPS/Key/DBI/*.pm: Modified
     how the pre_fetch_id() and post_fetch_id() methods are called --
     instead of passing a db handle/statement handle as the arguments,
     instead put everything in a hashref and read from that. (Prompted
     by the fact that SPOPS/Key/Random.pm was trying to use a DBI
     database handle as the width for the random code to
     generate. Ouch!)

   * SPOPS/Configure.pm: Thanks to questions and notes from Leon
     Brocard , we added documentation for the 'has_a'
     configuration item for an SPOPS object as well as gave developers
     the ability to define a custom alias for the returned object
     alias. For instance, you can do something like:

      user => {
        field    => [ 'user_id', 'group_id', 'email' ],
        id_field => 'user_id',
        class    => 'My::User',
        has_a    => { 'My::Group' => [ { group_id => 'zanybrainy' } ]
        ...,
      },

     and call the 'zanybrainy' method of a C object to get
     back the associated C object. (This is a silly example
     but it means we don't have to rely solely on the clunky
     automatic naming anymore, although it's still there if you want.)

   * SPOPS/DBI/MySQL.pm: post_fetch_id() now first checks to see if
     the 'increment_field' of the class configuration is set to a true
     value and if so retrieves the value from the handle.

     **THIS REQUIRES A CHANGE!!**

     From now on to use AUTO_INCREMENT fields in MySQL and SPOPS, you
     must set:

       'increment_field' => 1

     in the SPOPS configuration file for that class.

   * SPOPS/DBI/Sybase.pm: post_fetch_id() now first checks to see if
     the 'syb_identity' field of the class configuration is set to a
     true value and if so retrieves the value from the handle. This is
     no retrofit issue at all since we already required this.

   * SPOPS/DBI.pm: _save_insert() now retrieves a db handle and
     passes it to both the pre_fetch_id() and post_fetch_id()
     methods as well as the appropriate (insert/update) SQLInterface
     method.

   * SPOPS.pm: added 'Storable' to the ISA list of SPOPS, which means
     that every SPOPS object can now call store(), retrieve() and
     nstore() get serialized in a network-transportable
     format. Cool. Implications of this have yet to shake out,
     however.

     **POSSIBLE INTERFACE CONFLICT!!**

     If you are using a routine with any of the following names:

        store()
        retrieve()
        nstore()

     then you will not be able to use the methods from Storable. If
     you don't plan to use Storable then this is no big deal, but if
     you do then you'll have to rename your class methods.

   * SPOPS/Tie.pm: Functionality for doing field consistency checking
     is now in the new SPOPS/Tie/StrictField.pm, which allows you to
     create an SPOPS object without field restrictions and serialize
     it to a datasource. This might not seem useful at first -- why
     not just serialize a hashref? -- but we can treat all these
     objects the same which will (trust me) be important to you at
     some time or other. You also get builtin serialization and other
     fun stuff for free.

   * SPOPS/Key/Random.pm, SPOPS/Key/DBI/Pool.pm,
     SPOPS/Key/DBI/Identity.pm, SPOPS/Key/DBI/HandleField.pm: Moved
     all key-generation functions to the SPOPS::Key hierarchy. The
     Identity.pm and HandleField.pm came out of SPOPS/DBI/Sybase.pm
     and SPOPS/DBI/MySQL.pm, respectively, and Pool.pm is a rewritten
     SPOPS/DBI/Keypool.pm. SPOPS/DBI/RandomCode.pm was just renamed to
     Random.pm. (Hope that makes sense!) This might cause a little
     pain but we'll see if we can keep backward compatibility.

   * SPOPS.pm, SPOPS/DBI.pm, t/dbi.t: Applied patches from Rick Myers
      to eliminate warnings regarding undefined items
     under -w.

   * SPOPS/GDBM.pm, t/gdbm.t: Applied patches from Rick Myers
      to properly deal with GDBM_WRCREAT permissions
     on new GDBM databases.


0.38  Thu Feb  1 00:54:03 EST 2001

     Modified format of all files in the module to be more
     readable. Also added to SPOPS.pm exportable methods _w (warn) and
     _wm (warn multiple) which provides centralized debugging -- just
     change the DEBUG value in SPOPS.pm to a number (higher for more
     warnings) and all the packages in the modules will spill the
     beans.

     Applied patch from Christian Lemburg (lemburg@aixonix.de) to make
     'parse_into_hash' manipulations work as intended in
     SPOPS/Configure.pm.


0.37  Wed Jan  3 22:53:46 EST 2001

     One small (but important) bugfix: an error in SPOPS::Secure was
     using an object as a classname and instead of putting
     'NS::MyObject' into the 'class' column of the 'sys_security'
     table, it put something like 'NS::MyObject=HASH(0x8b7bb12)'.


0.36  Dec 20, 2000

     SMALL API CHANGE: the return value from the 'fetch_by_object'
     method in the security object class is now undef if there are no
     security objects found and a hashref of security information if
     there are security objects found. Unless you've been subclassing
     SPOPS::Secure (or doing other funky stuff with it) you won't have
     to worry about this.

     Add the option to pass in a 'security_object_class' to any method
     that neeeds it.

     SPOPS/Secure/Hierarchy.pm has now been tested and works with some
     simple cases. More work is needed to make the whole parsing thing
     more flexible (e.g., if you pass a URL you want to only parse
     everything after the hostname:port). Added lots of documentation
     to this as well.

     Updated SPOPS/Impl/SecurityObj.pm sample security object with
     updates from OpenInteract usage. We don't require the thing being
     protected to be an SPOPS object -- you can protect (and check
     on) anything now, as long as you have a consistent categorical
     identifier and a unique identifier for each thing.


0.35  Nov 18, 2000

     Added SPOPS/Secure/Hierarchy.pm for finding security in a
     parent-child relationship, like filesystems. This involved
     exploding out some functionality from the 'get_security()' method
     in SPOPS/Secure.pm so we could create an effective subclass. This
     new security checking style (with the hierarchy) hasn't been
     tested yet, but it's pretty straightforward and should work ok.

     Moved certain functions out of SPOPS.pm and into new file
     'SPOPS/Utility.pm' -- these are ones not really related to data
     persistence but just helpful utilities.

     NOTE: If you're updating to this version you need to put
     'SPOPS::Utility' in your class 'isa' so that you can use the
     methods now(), now_between_dates(), crypt_it(),
     generate_random_code() and list_process().

     COMPATIBILITY WARNING: Renamed the 'fetch_by_obj' method in the
     security object (used in SPOPS/Secure.pm) to
     'fetch_by_object'. This WILL NOT affect you if you're
     just using the interface for SPOPS::Secure. (If you don't know
     what that means, then you don't need to worry about it :)

     (minor note) Changed all instances of RCS keyword '$Header' to
     '$Id' and modified my email from cwinters@intes.net to
     chris@cwinters.com.


0.34  Nov 10, 2000

     Switched some silly documentation stuff in all the files. Changed
     SPOPS/DBI.pm to pass $p to the pre/post action rulesets so that
     the caller can affect the ruleset (e.g., 'full_text_skip =>
     1'). Modified SPOPS::Configure::_read_code_class to be able to
     read in multiple code classes when creating an SPOPS object and
     added some documentation to that file for the 'fetch_by'
     relationship. Modify SPOPS.pm to only respond to AUTOLOAD
     requests when the thing doing the requesting is an object.


0.33  Oct 16, 2000

     Added lots of documentation to individual files; transition to
     'use constant' for debugging values (much gets optimized away at
     compiletime). Ensure we're passing the database handle around in
     all necessary operations using SPOPS/DBI.pm,
     SPOPS/Configure/DBI.pm and SPOPS/SQLInterface.pm; added some
     abstract methods in SPOPS.pm (such as CONFIG) so if subclasses do
     not define them we don't get an error (duh). Add a new feature to
     SPOPS/Configure.pm: define a list of fieldnames in your config
     under the 'fetch_by' key and the system will create a subroutine
     for you to retrieve objects by data contained in that
     field. Updated the README file with some helpful installation
     tips, including a pointer to the bundle file. Also modified most
     (all?) places where we 'eval' code into existence to use a
     localized $SIG{__WARN__} handler to throw out any messages passed
     to STDERR so we can rely on our own error reporting


0.32  Sep 27, 2000

     Added lots of documentation (including a 'README' file) and made
     lots of changes to the configuration classes (SPOPS/Configure.pm
     and SPOPS/Configure/DBI.pm; SPOPS/Configure/Ruleset.pm was
     changed little) -- goal was to make it easier for some (but not
     all) of the methods to be run, if necessary.and modified the
     'create_initial_security' method of SPOPS/Secure.pm to have the
     'code' method of generating initial security be responsible for
     *all* the scopes. Also documented that method.

     Added the 'no_security' configuration setting so that a class can
     decide not to use security even if 'SPOPS::Secure' is in its
     'isa'.

     Added a couple of examples into the 'eg/' directory.


0.31  Sep 26, 2000

     Removed the html encoding/decoding stuff from SPOPS.pm. Cleaned
     up the initial_security stuff in SPOPS/Secure.pm -- better
     comments with examples, better flow, etc. -- cleaned up the
     documentation (formatting), and added a couple of TO DO items.

     Added the necessary information to license SPOPS under the
     Artistic/GPL licenses. Woo-hoo!


0.30  Sep 15, 2000

     More tests, now for DBI. These are pretty simple and don't go
     into security, but they should actually be quite useful to see if
     the database (or rather, the DBD driver) supports the DBI
     name/type inspection. I suspect that most 'modern' databases do
     (or maybe that's just a hope). Also modified Makefile.PL to
     collect information for testing. 

     The hope, was of course, immediately dashed. Current versions of 
     DBD::ASAny (Sybase Adaptive Server Anywhere) do not support
     $sth->{TYPE}. So the planned modifications happened sooner than
     expected. If your database does not support dynamic type
     inspection, you can give simple type names in your configuration
     ('int', 'num', 'char', etc.) and SPOPS will translate them to the
     DBI types for you.


0.29  Sep 14, 2000

     Added the second implementation for storing SPOPS objects:
     SPOPS/GDBM.pm. Tested with Interact::Package objects and so far
     it's working well. Note that we don't deal with security or cache
     checking yet -- I don't think those will be implemented until we
     actually need them. (XP rubs off...). Also added the third
     implementation for storing SPOPS objects: SPOPS/HashFile.pm. Use
     it for reading in a perl hashref dumped (via Data::Dumper) to a
     file. This simply reads in the file and provides key/value access
     for any values you want to access and store. This implementation
     actually uses its own tiehash implementation (packaged in the
     same file) rather than SPOPS/Tie.pm. The XP stuff is definitely
     rubbing off, because I'm starting to test everything. (Gasp!)
     Added the t/ directory for testing and a testing suite for both
     SPOPS/GDBM.pm and for SPOPS/HashFile.pm. DBI tests are going to
     be a little more difficult...


0.28  Sep 11, 2000

     Added the 'object_description' method to SPOPS.pm, since we
     really do not have a generic way to query an object for a general
     description, including a URL where we can get more information, a
     name (general descriptive class of object) and a title
     (information about a specific object). Modify SPOPS/Configure.pm
     so we do not have to specify every single configuration key
     needed for the class -- just those that we have to massage in
     some way (e.g., an arrayref into a hashref) and let the rest just
     get assigned. Let calls to $dbi_obj->save skip the logging and
     security phases if they want. Also modify SPOPS/Configure.pm so
     that we now create every class on the fly and read in the
     subroutines if the configuration states that there is code behind
     the class.


0.27  Aug 28, 2000

     Moved all the ruleset initialization configuration actions to
     SPOPS/Configure/Ruleset.pm. This involved moving the package
     variable and accessor from SPOPS/Configure.pm and moving the
     ruleset constructors from SPOPS/Configure/DBI.pm. Added
     documentation about rulesets into SPOPS.pm; we should probably
     take a lot of that general documentation and put it in its own
     pod. Modified the '$item_remove' eval'd subroutine in
     SPOPS/Configure/DBI.pm to use linking tables by default; it
     should also work with one-to-many relationships that do not use
     linking tables, but we might need to create a different set of
     eval'd subroutines for such relationships. This probably doesn't
     deserve its own 'version', but we need to get this out for
     something :)


0.26  Aug 16, 2000

      Minor changes to reflect that we never need to call a
      global_error_class, and that the cache return has been named to
      'global_cache' from 'global_cache_class'; also ducmented what
      exactly the cache needs to do. Minor shifting around in
      SPOPS/Configure.pm and SPOPS/Configure/DBI.pm as we modified
      configuration stuff in OpenInteract. Modified SPOPS/Tie.pm to
      track 'internal' variables -- first use will be for SPOPS/DBI.pm
      methods to be able to validate data, particularly for 'Grouped'
      objects. Split up 'save()' in SPOPS/DBI.pm into internal methods
      '_save_insert()' and '_save_update()' to make it more
      understandable.

      Moved the 'check_action_security()' method from SPOPS/Secure.pm
      to SPOPS/DBI.pm and put additional functionality in. Now we
      simply pass an object and a required level -- do not wrap it in
      an eval{} and it will throw any necessary errors for you. Added
      the default 'check_security' method to SPOPS.pm so
      non-SPOPS::Secure classes will inherit the 'everything goes'
      security.

      Finally, added some cool functionality to ensure that pre/post
      actions actually mean something. At initialization time, we
      scour the parents of a SPOPS object class for rules to execute
      during these phases. These rules can be simple or complex, and
      they must be exclusive of one another and execute in any order.

      This will allow us to do interesting things with layers of
      meta-information on top of objects. For example, any class
      inheriting from 'SPOPS::Searchable' will submit its information
      to a separate class, which processes it and adds/modifies a
      full-text search engine. Cool stuff :)


0.25  Aug 2, 2000

      Fixed a long-dormant buglet: this entire time, the
      SPOPS/DBI/save method was trying to retrieve the just-set values
      of fields with DEFAULT settings from the database so the object
      could be in sync at all times; turns out that we didn't tell
      SQLInterface to return a single row so we were assigning a
      stringified arrayref (eg: ARRAY(0xADFE21)) to the first value
      and nothing to the others...  Good thing caching isn't activated
      yet :)


0.24  Jul 26, 2000

      Fixed some typos in SPOPS/Configure/DBI.pm in the eval'd
      routines (including one where we were fetching the linked
      objects but not returning them -- duh!); changed how
      SPOPS/Error.pm gets the caller information. Added the ability of
      SPOPS/Configure.pm to put any coderefs where they
      belong. Modified SPOPS/DBI.pm to take the old ID to update by in
      the save() method, so you can update the primary key field and
      still refer to the old ID.


0.23  Jul 15, 2000

      Radically changed how errors are thrown. Every error generated
      by SPOPS now sets the package variables user_msg, system_msg,
      type and (optionally) extra in the brand new module,
      SPOPS::Error. It then dies with the simple scalar user_msg,
      which is what the caller catches. The caller is then responsible
      for retrieving as much information as it needs from the
      SPOPS::Error package. The main reason we're doing this is to
      eliminate problems arising from overriding the CORE::die
      function in perl. Also added some documentation to lots of
      modules. Added the module SPOPS/Impl/User.pm as an example of
      what a SPOPS user object looks like and should do.


0.22  Jul 14, 2000

      Modified a couple items in SPOPS/DBI.pm: the fetch_group()
      method can now take multiple tables and do a join but still
      return a group of objects that match the criteria. To do this we
      also changed the id_clause() method to fully-qualify ID fields
      unless otherwise told. Also changed the alias subroutine in
      SPOPS/Configure/DBI.pm created for links_to relationships to
      *not* qualify the ID field, since we frequently use link tables
      to accomplish this. Also flipped some items around in the has_a
      alias created in SPOPS/Configure.pm. And in a minor item, change
      the die {} idiom to use a preceding "if ( $@ )" clause rather
      than a trailing one, since the latter is too difficult to pick
      out easily. Modify the SPOPS/Configure/DBI.pm _add and _remove
      aliases to take either a single ID or an arrayref of IDs.


0.21  Jun 27, 2000

      Updated to put all internal dependencies (like @ISA) into
      explicit 'use' statements rather than depend on mod_perl or
      something else loading everything else up for us. Modified
      SPOPS/Configure/DBI.pm to wrap the fetch() call for a links_to
      relationship in an eval {} so we don't catch any errors thrown
      with die up top. SPOPS/generate_random_code can now return
      mixed-case codes. Also changed SPOPS/DBI.pm to return undef if a
      particular record simply isn't found -- for some reason, I
      thought this had been in there since the beginning.


0.20  Jun 18, 2000

      Paper bag fix in SPOPS/Secure.pm made by renaming a hash. 


0.19  Jun 18, 2000

       Added and reworked a ton of documentation to SPOPS/DBI.pm; also
       added a super-easy and super-cool feature to its fetch()
       method: every time you ask for an object, the system will also
       give its security level to you, free of charge. Just look in
       the {tmp_security_level} property. Made a tiny change to
       SPOPS/Impl/SecurityObj.pm to ensure that users not logged in do
       not automatically belong to all existing groups :) Put
       modification into SPOPS/DBI/fetch and fetch_group to allow
       method calls to skip security checks to get around a
       chicken-and-egg problem with logging in as the superuser. (Only
       the superuser object can see the superuser object, so how are
       we going to fetch the object to login before we've logged in
       yet? :)


0.18  Jun 14, 2000

       Modified how errors are handled within all SPOPS modules. This
       forced changes throughout a number of modules, but particularly
       SPOPS/DBI.pm, SPOPS/Secure.pm and SPOPS/SQLInterface.pm. Added
       documentation to SPOPS/Tie.pm and modified it to use Carp::carp
       when something tries to access/modify a property that is not in
       the field list. Modified other modules to use Carp::carp when
       reporting nonfatal errors that require some modification from
       the method call. Also modified SPOPS/Tie.pm to take an arrayref
       (versus a hashref) argument for the list of fields it will
       accept.


0.17  Jun 13, 2000

       Modified all parameters to be passed as hashrefs rather than
       hashes. Passing-by-hashref was implemented in more recent
       modules (such as SPOPS/Secure.pm), but was not retrofitted to
       older modules. Finally bit the bullet and did this. More
       testing for object security stuff -- nothing amiss so
       far. Added some configuration options for as_string method to
       make the output look a little nicer and modified SPOPS/AUTOLOAD
       (again) to not warn with an error if it cannot find a value for
       a 'tmp_' variable. Modified the SPOPS/clone() method to force
       the ID field of the new object to be blank.


0.16  Jun 9, 2000

       Fixed SPOPS/Configure.pm to have the alias of the 'has_a'
       subroutine created to match the type of object it 'has' only if
       the ID field is exactly the same; fixed dumb mistake in
       SPOPS/Secure.pm that wasn't differentiating properly between a
       class and an object in ->create_initial_security; made a fairly
       simple patch to SPOPS/Tie.pm which allows you to store
       temporary attributes for the life of the object -- when the
       object is DESTROYed, there go the attribs, and they're not
       saved when the object is cached. Very useful for tracking
       access rights on a per-object basis. We also had to make a
       change to SPOPS/AUTOLOAD so we could call the temporary key as
       a subroutine reference (Template Toolkit does this, somewhat
       annoyingly...). Also tested out object security stuff -- works
       pretty well.


0.15  Jun 8, 2000

        Modified the SQL-generation in SPOPS/Impl/SecurityObj.pm to
        properly fetch WORLD-only requests; if there is no user object
        existing and $class->check_security; is called, we want to
        return only the WORLD permissions (SPOPS/Secure.pm); modified
        the API for object security checking so that only one method
        is called (SPOPS/Secure/check_action_security) and the action
        is passed as the first argument; created the
        SPOPS/Secure/create_initial_security method that allows us to
        initialize an object with security information. Tested
        check_action_security and fixed related API boo-boos in
        SPOPS/DBI.pm. Individual object as well as class-based
        security now seems to be working well, although more testing
        is certainly required :)
        

0.14  Jun 7, 2000

        Allow user to pass information to fetch() method (via both fetch()
        and fetch_group() that overrides configuration for the field_alter
        key (refresher: allows you to set a format on a returned value
        from the database, such as DATE_FORMAT( mydate, '%b %e' )); massive
        changes to SPOPS/Secure.pm to allow it to work with class-only and data
        object security transparently (not a lot of testing yet,
        however); SPOPS/Impl/SecurityObj.pm also had some changes to
        enable it to work with classes


0.13  Jun 5, 2000

        Added SPOPS/Impl/SecurityObj.pm to the distribution as a DBI-based
        SPOPS object representing security; added methods and documentation
        to SPOPS/Secure.pm; modified SPOPS/Configure.pm to allow multiple
        aliases per type in the 'has_a' descriptor.


0.12  May 29, 2000

        Added list_process() method to SPOPS.pm and added the related
        methods to SPOPS::Configure::DBI %alias_to%_remove and 
        %alias_to%_add, which allow us to link together objects without
        actually modifying the objects. For instance, if the alias 
        'group' has defined: links_to => [ 'user' ] the methods would
        be named 'user_add' and 'user_remove' and would add or remove
        one or more users to the group. Also modified all the errors
        thrown in SQLInterface to have the proper type and at least
        some semblance of informative messages.


0.11  May 24, 2000

        Paper bag fix in SPOPS::Tie (changes weren't being tracked and
        therefore updates not saved); paper bag fix in SPOPS::Configure::DBI
        (bad definition for eval'd subroutine created *evil* bug of
        super-rapid memory consumption); added data() method to SPOPS.pm;
        routine created in SPOPS::Configure and eval'd for has_a now
        only tries a fetch if the ID value exists


0.10  May 17, 2000 

        Polishing; things basically work


0.01  May 12, 2000

	    Original version - much of the packages were brought in from elsewhere,
        but a lot of work is needed to extricate them from their
        previous application and to make everything work together and
        feel cohesive.