[glom] Moved some lookup functions into DbUtils and added a test for them.
- From: Murray Cumming <murrayc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glom] Moved some lookup functions into DbUtils and added a test for them.
- Date: Thu, 1 Dec 2011 13:27:21 +0000 (UTC)
commit f94998a4f3f7c1d5b2ac037d3befc59b52969735
Author: Murray Cumming <murrayc murrayc com>
Date: Thu Dec 1 14:23:06 2011 +0100
Moved some lookup functions into DbUtils and added a test for them.
* glom/libglom/db_utils.[h|cc]:
* glom/base_db.[h|cc]: Moved get_fields_for_table(),
get_fields_for_table_one_field(), get_lookup_fields(), and
get_lookup_value() to the DbUtils namespace, taking an extra
Document parameter.
* glom/libglom/document/document.[h|cc]: Moved get_lookup_fields() to
DbUtils too.
* glom/base_db_table_data.cc
* glom/mode_data/box_data.cc
* glom/mode_data/box_data_calendar_related.cc
* glom/mode_data/box_data_details.cc
* glom/mode_data/box_data_list_related.cc
* glom/mode_data/db_adddel/db_adddel.cc
* glom/mode_design/box_db_table_relationships.cc
* glom/mode_design/fields/box_db_table_definition.cc
* glom/mode_design/fields/dialog_fielddefinition.cc
* glom/mode_design/layout/dialog_layout_list_related.cc
* glom/print_layout/canvas_print_layout.cc: Adapted. This shows how
often we call this very inefficient function. It would be better to
just make sure that the document has up-to-date information from the
database and just use the Document's information.
* Makefile_tests.am:
* tests/test_selfhosting_new_then_lookup.cc: Added a new test of
these functions, including retrieval of a lookup value.
ChangeLog | 31 +++
Makefile_tests.am | 6 +
glom/base_db.cc | 184 ++---------------
glom/base_db.h | 29 ---
glom/base_db_table_data.cc | 10 +-
glom/libglom/db_utils.cc | 118 +++++++++++
glom/libglom/db_utils.h | 20 ++
glom/libglom/document/document.cc | 34 +++-
glom/libglom/document/document.h | 10 +
glom/mode_data/box_data.cc | 8 +-
glom/mode_data/box_data_calendar_related.cc | 6 +-
glom/mode_data/box_data_details.cc | 2 +-
glom/mode_data/box_data_list_related.cc | 5 +-
glom/mode_data/db_adddel/db_adddel.cc | 3 +-
glom/mode_design/box_db_table_relationships.cc | 7 +-
glom/mode_design/fields/box_db_table_definition.cc | 5 +-
glom/mode_design/fields/dialog_fielddefinition.cc | 3 +-
.../layout/dialog_layout_list_related.cc | 5 +-
glom/print_layout/canvas_print_layout.cc | 4 +-
tests/test_selfhosting_new_then_lookup.cc | 220 ++++++++++++++++++++
20 files changed, 495 insertions(+), 215 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 75c916b..59f373f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+2011-12-01 Murray Cumming <murrayc murrayc com>
+
+ Moved some lookup functions into DbUtils and added a test for them.
+
+ * glom/libglom/db_utils.[h|cc]:
+ * glom/base_db.[h|cc]: Moved get_fields_for_table(),
+ get_fields_for_table_one_field(), get_lookup_fields(), and
+ get_lookup_value() to the DbUtils namespace, taking an extra
+ Document parameter.
+ * glom/libglom/document/document.[h|cc]: Moved get_lookup_fields() to
+ DbUtils too.
+
+ * glom/base_db_table_data.cc
+ * glom/mode_data/box_data.cc
+ * glom/mode_data/box_data_calendar_related.cc
+ * glom/mode_data/box_data_details.cc
+ * glom/mode_data/box_data_list_related.cc
+ * glom/mode_data/db_adddel/db_adddel.cc
+ * glom/mode_design/box_db_table_relationships.cc
+ * glom/mode_design/fields/box_db_table_definition.cc
+ * glom/mode_design/fields/dialog_fielddefinition.cc
+ * glom/mode_design/layout/dialog_layout_list_related.cc
+ * glom/print_layout/canvas_print_layout.cc: Adapted. This shows how
+ often we call this very inefficient function. It would be better to
+ just make sure that the document has up-to-date information from the
+ database and just use the Document's information.
+
+ * Makefile_tests.am:
+ * tests/test_selfhosting_new_then_lookup.cc: Added a new test of
+ these functions, including retrieval of a lookup value.
+
2011-11-30 Murray Cumming <murrayc murrayc com>
Remove unused parameternamegenerator source file.
diff --git a/Makefile_tests.am b/Makefile_tests.am
index 1516c55..ca2691f 100644
--- a/Makefile_tests.am
+++ b/Makefile_tests.am
@@ -36,6 +36,7 @@ check_PROGRAMS = \
tests/test_selfhosting_new_from_example_strangepath \
tests/test_selfhosting_new_then_report \
tests/test_selfhosting_new_then_image \
+ tests/test_selfhosting_new_then_lookup \
tests/test_selfhosting_new_then_backup_restore \
tests/test_selfhosting_new_then_get_privs \
tests/test_selfhosting_new_then_alter_table \
@@ -63,6 +64,7 @@ TESTS = tests/test_document_load \
tests/test_selfhosting_new_then_report \
tests/test_selfhosting_new_then_backup_restore \
tests/test_selfhosting_new_then_image \
+ tests/test_selfhosting_new_then_lookup \
tests/test_selfhosting_new_then_get_privs \
tests/test_selfhosting_new_then_alter_table \
tests/test_selfhosting_new_then_change_columns \
@@ -185,6 +187,10 @@ tests_test_selfhosting_new_then_image_SOURCES = tests/test_selfhosting_new_then_
tests_test_selfhosting_new_then_image_LDADD = $(tests_ldadd)
tests_test_selfhosting_new_then_image_CPPFLAGS = $(tests_cppflags) $(glom_test_image_defines)
+tests_test_selfhosting_new_then_lookup_SOURCES = tests/test_selfhosting_new_then_lookup.cc $(sources_test_selfhosting_utils)
+tests_test_selfhosting_new_then_lookup_LDADD = $(tests_ldadd)
+tests_test_selfhosting_new_then_lookup_CPPFLAGS = $(tests_cppflags)
+
tests_test_selfhosting_new_then_backup_restore_SOURCES = tests/test_selfhosting_new_then_backup_restore.cc $(sources_test_selfhosting_utils)
tests_test_selfhosting_new_then_backup_restore_LDADD = $(tests_ldadd)
tests_test_selfhosting_new_then_backup_restore_CPPFLAGS = $(tests_cppflags)
diff --git a/glom/base_db.cc b/glom/base_db.cc
index 0fc9ada..936eeed 100644
--- a/glom/base_db.cc
+++ b/glom/base_db.cc
@@ -221,69 +221,6 @@ Base_DB::type_vec_strings Base_DB::util_vecStrings_from_Fields(const type_vec_fi
return vecNames;
}
-Base_DB::type_vec_fields Base_DB::get_fields_for_table(const Glib::ustring& table_name, bool including_system_fields) const
-{
- //Get field definitions from the database:
- type_vec_fields fieldsDatabase = DbUtils::get_fields_for_table_from_database(table_name, including_system_fields);
-
- const Document* pDoc = dynamic_cast<const Document*>(get_document());
- if(!pDoc)
- return fieldsDatabase; //This should never happen.
- else
- {
- type_vec_fields result;
-
- type_vec_fields fieldsDocument = pDoc->get_table_fields(table_name);
-
- //Look at each field in the database:
- for(type_vec_fields::iterator iter = fieldsDocument.begin(); iter != fieldsDocument.end(); ++iter)
- {
- sharedptr<Field> field = *iter;
- const Glib::ustring field_name = field->get_name();
-
- //Get the field info from the database:
- //This is in the document as well, but it _might_ have changed.
- type_vec_fields::const_iterator iterFindDatabase = std::find_if(fieldsDatabase.begin(), fieldsDatabase.end(), predicate_FieldHasName<Field>(field_name));
-
- if(iterFindDatabase != fieldsDatabase.end() ) //Ignore fields that don't exist in the database anymore.
- {
- Glib::RefPtr<Gnome::Gda::Column> field_info_document = field->get_field_info();
-
- //Update the Field information that _might_ have changed in the database.
- Glib::RefPtr<Gnome::Gda::Column> field_info = (*iterFindDatabase)->get_field_info();
-
- //libgda does not tell us whether the field is auto_incremented, so we need to get that from the document.
- field_info->set_auto_increment( field_info_document->get_auto_increment() );
-
- //libgda does not tell us whether the field is auto_incremented, so we need to get that from the document.
- //TODO_gda:field_info->set_primary_key( field_info_document->get_primary_key() );
-
- //libgda does yet tell us correct default_value information so we need to get that from the document.
- field_info->set_default_value( field_info_document->get_default_value() );
-
- field->set_field_info(field_info);
-
- result.push_back(*iter);
- }
- }
-
- //Add any fields that are in the database, but not in the document:
- for(type_vec_fields::iterator iter = fieldsDatabase.begin(); iter != fieldsDatabase.end(); ++iter)
- {
- Glib::ustring field_name = (*iter)->get_name();
-
- //Look in the result so far:
- type_vec_fields::const_iterator iterFind = std::find_if(result.begin(), result.end(), predicate_FieldHasName<Field>(field_name));
-
- //Add it if it is not there:
- if(iterFind == result.end() )
- result.push_back(*iter);
- }
-
- return result;
- }
-}
-
#ifndef GLOM_ENABLE_CLIENT_ONLY
namespace
@@ -600,24 +537,6 @@ sharedptr<LayoutItem_Notebook> Base_DB::offer_notebook(const sharedptr<LayoutIte
}
#endif // !GLOM_ENABLE_CLIENT_ONLY
-sharedptr<Field> Base_DB::get_fields_for_table_one_field(const Glib::ustring& table_name, const Glib::ustring& field_name) const
-{
- //Initialize output parameter:
- sharedptr<Field> result;
-
- if(field_name.empty() || table_name.empty())
- return result;
-
- type_vec_fields fields = get_fields_for_table(table_name);
- type_vec_fields::iterator iter = std::find_if(fields.begin(), fields.end(), predicate_FieldHasName<Field>(field_name));
- if(iter != fields.end()) //TODO: Handle error?
- {
- return *iter;
- }
-
- return sharedptr<Field>();
-}
-
//static:
bool Base_DB::get_field_primary_key_index_for_fields(const type_vec_fields& fields, guint& field_column)
{
@@ -694,6 +613,8 @@ sharedptr<Field> Base_DB::get_field_primary_key_for_table(const Glib::ustring& t
void Base_DB::get_table_fields_to_show_for_sequence_add_group(const Glib::ustring& table_name, const Privileges& table_privs, const type_vec_fields& all_db_fields, const sharedptr<LayoutGroup>& group, Base_DB::type_vecConstLayoutFields& vecFields) const
{
+ const Document* document = dynamic_cast<const Document*>(get_document());
+
//g_warning("Box_Data::get_table_fields_to_show_for_sequence_add_group(): table_name=%s, all_db_fields.size()=%d, group->name=%s", table_name.c_str(), all_db_fields.size(), group->get_name().c_str());
LayoutGroup::type_list_items items = group->get_items();
@@ -710,7 +631,7 @@ void Base_DB::get_table_fields_to_show_for_sequence_add_group(const Glib::ustrin
if(item_field->get_has_relationship_name()) //If it's a field in a related table.
{
//TODO_Performance: get_fields_for_table_one_field() is probably very inefficient
- sharedptr<Field> field = get_fields_for_table_one_field(item_field->get_table_used(table_name), item->get_name());
+ sharedptr<Field> field = DbUtils::get_fields_for_table_one_field(document, item_field->get_table_used(table_name), item->get_name());
if(field)
{
sharedptr<LayoutItem_Field> layout_item = item_field;
@@ -772,14 +693,15 @@ void Base_DB::get_table_fields_to_show_for_sequence_add_group(const Glib::ustrin
Base_DB::type_vecConstLayoutFields Base_DB::get_table_fields_to_show_for_sequence(const Glib::ustring& table_name, const Document::type_list_layout_groups& mapGroupSequence) const
{
+ const Document* pDoc = dynamic_cast<const Document*>(get_document());
+
//Get field definitions from the database, with corrections from the document:
- type_vec_fields all_fields = get_fields_for_table(table_name);
+ type_vec_fields all_fields = DbUtils::get_fields_for_table(pDoc, table_name);
const Privileges table_privs = Privs::get_current_privs(table_name);
//Get fields that the document says we should show:
type_vecConstLayoutFields result;
- const Document* pDoc = dynamic_cast<const Document*>(get_document());
if(pDoc)
{
if(mapGroupSequence.empty())
@@ -1442,12 +1364,16 @@ Base_DB::type_list_const_field_items Base_DB::get_calculation_fields(const Glib:
void Base_DB::do_lookups(const LayoutFieldInRecord& field_in_record, const Gtk::TreeModel::iterator& row, const Gnome::Gda::Value& field_value)
{
+ Document* document = get_document();
+ if(!document)
+ return;
+
//Get values for lookup fields, if this field triggers those relationships:
//TODO_performance: There is a LOT of iterating and copying here.
const Glib::ustring strFieldName = field_in_record.m_field->get_name();
- const type_list_lookups lookups = get_lookup_fields(field_in_record.m_table_name, strFieldName);
+ const Document::type_list_lookups lookups = document->get_lookup_fields(field_in_record.m_table_name, strFieldName);
//std::cout << "debug: " << G_STRFUNC << ": lookups size=" << lookups.size() << std::endl;
- for(type_list_lookups::const_iterator iter = lookups.begin(); iter != lookups.end(); ++iter)
+ for(Document::type_list_lookups::const_iterator iter = lookups.begin(); iter != lookups.end(); ++iter)
{
sharedptr<const LayoutItem_Field> layout_item = iter->first;
@@ -1457,10 +1383,10 @@ void Base_DB::do_lookups(const LayoutFieldInRecord& field_in_record, const Gtk::
const sharedptr<const Field> field_lookup = layout_item->get_full_field_details();
if(field_lookup)
{
- sharedptr<const Field> field_source = get_fields_for_table_one_field(relationship->get_to_table(), field_lookup->get_lookup_field());
+ sharedptr<const Field> field_source = DbUtils::get_fields_for_table_one_field(document, relationship->get_to_table(), field_lookup->get_lookup_field());
if(field_source)
{
- const Gnome::Gda::Value value = get_lookup_value(field_in_record.m_table_name, iter->second /* relationship */, field_source /* the field to look in to get the value */, field_value /* Value of to and from fields */);
+ const Gnome::Gda::Value value = DbUtils::get_lookup_value(document, field_in_record.m_table_name, iter->second /* relationship */, field_source /* the field to look in to get the value */, field_value /* Value of to and from fields */);
const Gnome::Gda::Value value_converted = Conversions::convert_value(value, layout_item->get_glom_type());
@@ -1479,87 +1405,11 @@ void Base_DB::do_lookups(const LayoutFieldInRecord& field_in_record, const Gtk::
}
}
-
-/** Get the fields whose values should be looked up when @a field_name changes, with
- * the relationship used to lookup the value.
- */
-Base_DB::type_list_lookups Base_DB::get_lookup_fields(const Glib::ustring& table_name, const Glib::ustring& field_name) const
-{
- type_list_lookups result;
-
- const Document* document = dynamic_cast<const Document*>(get_document());
- if(document)
- {
- //Examine all fields, not just the the shown fields (m_Fields):
- const type_vec_fields fields = document->get_table_fields(table_name); //TODO_Performance: Cache this?
- //Examine all fields, not just the the shown fields.
- for(type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
- {
- sharedptr<Field> field = *iter;
-
- //Examine each field that looks up its data from a relationship:
- if(field && field->get_is_lookup())
- {
- //Get the relationship information:
- sharedptr<Relationship> relationship = field->get_lookup_relationship();
- if(relationship)
- {
- //If the relationship is triggererd by the specified field:
- if(relationship->get_from_field() == field_name)
- {
- //Add it:
- sharedptr<LayoutItem_Field> item = sharedptr<LayoutItem_Field>::create();
- item->set_full_field_details(field);
- result.push_back( type_pairFieldTrigger(item, relationship) );
- }
- }
- }
- }
- }
-
- return result;
-}
-
void Base_DB::refresh_related_fields(const LayoutFieldInRecord& /* field_in_record_changed */, const Gtk::TreeModel::iterator& /* row */, const Gnome::Gda::Value& /* field_value */)
{
//overridden in Box_Data.
}
-Gnome::Gda::Value Base_DB::get_lookup_value(const Glib::ustring& /* table_name */, const sharedptr<const Relationship>& relationship, const sharedptr<const Field>& source_field, const Gnome::Gda::Value& key_value)
-{
- Gnome::Gda::Value result;
-
- sharedptr<Field> to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), relationship->get_to_field());
- if(to_key_field)
- {
- //Convert the value, in case the from and to fields have different types:
- const Gnome::Gda::Value value_to_key_field = Conversions::convert_value(key_value, to_key_field->get_glom_type());
-
- const Glib::ustring target_table = relationship->get_to_table();
- Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
- Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
- builder->select_add_field(source_field->get_name(), target_table );
- builder->select_add_target(target_table );
- builder->set_where(
- builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
- builder->add_field_id(to_key_field->get_name(), target_table),
- builder->add_expr(value_to_key_field)));
-
- Glib::RefPtr<Gnome::Gda::DataModel> data_model = DbUtils::query_execute_select(builder);
- if(data_model && data_model->get_n_rows())
- {
- //There should be only 1 row. Well, there could be more but we will ignore them.
- result = data_model->get_value_at(0, 0);
- }
- else
- {
- handle_error();
- }
- }
-
- return result;
-}
-
bool Base_DB::get_field_value_is_unique(const Glib::ustring& table_name, const sharedptr<const LayoutItem_Field>& field, const Gnome::Gda::Value& value)
{
bool result = true; //Arbitrarily default to saying it's unique if we can't get any result.
@@ -1702,8 +1552,10 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
// The WHERE clause mentions the first-related table (though by the alias defined in extra_join)
// and we add an extra JOIN to mention the second-related table.
+ Document* document = get_document();
+
Glib::ustring where_clause_to_table_name = relationship->get_to_table();
- sharedptr<Field> where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), relationship->get_to_field());
+ sharedptr<Field> where_clause_to_key_field = DbUtils::get_fields_for_table_one_field(document, relationship->get_to_table(), relationship->get_to_field());
found_set.m_table_name = portal->get_table_used(Glib::ustring() /* parent table - not relevant */);
@@ -1719,7 +1571,7 @@ void Base_DB::set_found_set_where_clause_for_portal(FoundSet& found_set, const s
where_clause_to_table_name = uses_rel_temp->get_sql_join_alias_name();
const Glib::ustring to_field_name = uses_rel_temp->get_to_field_used();
- where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), to_field_name);
+ where_clause_to_key_field = DbUtils::get_fields_for_table_one_field(document, relationship->get_to_table(), to_field_name);
//std::cout << "extra_join=" << found_set.m_extra_join << std::endl;
//std::cout << "extra_join where_clause_to_key_field=" << where_clause_to_key_field->get_name() << std::endl;
diff --git a/glom/base_db.h b/glom/base_db.h
index 5ccb1ad..7436460 100644
--- a/glom/base_db.h
+++ b/glom/base_db.h
@@ -120,22 +120,6 @@ protected:
bool get_relationship_exists(const Glib::ustring& table_name, const Glib::ustring& relationship_name);
- /** Get all the fields for a table, including any from the datasbase that are not yet known in the document.
- *
- * @param table_name The name of the table whose fields should be listed.
- * @param including_system_fields Whether extra non-user-visible fields should be included in the list.
- * @result A list of fields.
- */
- type_vec_fields get_fields_for_table(const Glib::ustring& table_name, bool including_system_fields = false) const;
-
- /** Get a single field definition for a table, even if the field is in the datasbase but not yet known in the document.
- *
- * @param table_name The name of the table whose fields should be listed.
- * @param field_name The name of the field for which to get the definition.
- * @result The field definition.
- */
- sharedptr<Field> get_fields_for_table_one_field(const Glib::ustring& table_name, const Glib::ustring& field_name) const;
-
sharedptr<Field> get_field_primary_key_for_table(const Glib::ustring& table_name) const;
//Methods to be overridden by derived classes:
@@ -258,19 +242,6 @@ protected:
void do_lookups(const LayoutFieldInRecord& field_in_record, const Gtk::TreeModel::iterator& row, const Gnome::Gda::Value& field_value);
- typedef std::pair< sharedptr<LayoutItem_Field>, sharedptr<Relationship> > type_pairFieldTrigger;
- typedef std::list<type_pairFieldTrigger> type_list_lookups;
-
- /** Get the fields whose values should be looked up when @a field_name changes, with
- * the relationship used to lookup the value.
- */
- type_list_lookups get_lookup_fields(const Glib::ustring& table_name, const Glib::ustring& field_name) const;
-
-
- /** Get the value of the @a source_field from the @a relationship, using the @a key_value.
- */
- Gnome::Gda::Value get_lookup_value(const Glib::ustring& table_name, const sharedptr<const Relationship>& relationship, const sharedptr<const Field>& source_field, const Gnome::Gda::Value & key_value);
-
virtual void refresh_related_fields(const LayoutFieldInRecord& field_in_record_changed, const Gtk::TreeModel::iterator& row, const Gnome::Gda::Value& field_value);
diff --git a/glom/base_db_table_data.cc b/glom/base_db_table_data.cc
index edac7b7..aaa51cb 100644
--- a/glom/base_db_table_data.cc
+++ b/glom/base_db_table_data.cc
@@ -67,13 +67,15 @@ Gtk::TreeModel::iterator Base_DB_Table_Data::get_row_selected()
bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Value& primary_key_value)
{
+ Document* document = get_document();
+
sharedptr<const Field> fieldPrimaryKey = get_field_primary_key();
const Glib::ustring primary_key_name = fieldPrimaryKey->get_name();
type_vecConstLayoutFields fieldsToAdd = m_FieldsShown;
if(m_TableFields.empty())
- m_TableFields = get_fields_for_table(m_table_name);
+ m_TableFields = DbUtils::get_fields_for_table(document, m_table_name);
//Add values for all fields, not just the shown ones:
//For instance, we must always add the primary key, and fields with default/calculated/lookup values:
@@ -90,8 +92,6 @@ bool Base_DB_Table_Data::record_new(bool use_entered_data, const Gnome::Gda::Val
}
}
- Document* document = get_document();
-
//Calculate any necessary field values and enter them:
for(type_vecConstLayoutFields::const_iterator iter = fieldsToAdd.begin(); iter != fieldsToAdd.end(); ++iter)
{
@@ -324,7 +324,9 @@ bool Base_DB_Table_Data::add_related_record_for_field(const sharedptr<const Layo
set_entered_field_data(item_from_key, primary_key_value);
//Set it in the database too:
- sharedptr<Field> field_from_key = get_fields_for_table_one_field(relationship->get_from_table(), relationship->get_from_field()); //TODO_Performance.
+ Document* document = get_document();
+ sharedptr<Field> field_from_key = DbUtils::get_fields_for_table_one_field(document,
+ relationship->get_from_table(), relationship->get_from_field()); //TODO_Performance.
if(!field_from_key)
{
std::cerr << G_STRFUNC << ": get_fields_for_table_one_field() failed." << std::endl;
diff --git a/glom/libglom/db_utils.cc b/glom/libglom/db_utils.cc
index 3a9e0b5..07c2224 100644
--- a/glom/libglom/db_utils.cc
+++ b/glom/libglom/db_utils.cc
@@ -940,6 +940,89 @@ type_vec_fields get_fields_for_table_from_database(const Glib::ustring& table_na
return result;
}
+//TODO: This is very inefficient, because it is called so often. Just update the document with whatever is really in the database:
+type_vec_fields get_fields_for_table(const Document* document, const Glib::ustring& table_name, bool including_system_fields)
+{
+ //Get field definitions from the database:
+ type_vec_fields fieldsDatabase = get_fields_for_table_from_database(table_name, including_system_fields);
+
+ if(!document)
+ {
+ std::cerr << G_STRFUNC << ": document is null" << std::endl;
+ return fieldsDatabase; //This should never happen.
+ }
+
+ type_vec_fields result;
+
+ type_vec_fields fieldsDocument = document->get_table_fields(table_name);
+
+ //Look at each field in the database:
+ for(type_vec_fields::iterator iter = fieldsDocument.begin(); iter != fieldsDocument.end(); ++iter)
+ {
+ sharedptr<Field> field = *iter;
+ const Glib::ustring field_name = field->get_name();
+
+ //Get the field info from the database:
+ //This is in the document as well, but it _might_ have changed.
+ type_vec_fields::const_iterator iterFindDatabase =
+ std::find_if(fieldsDatabase.begin(), fieldsDatabase.end(), predicate_FieldHasName<Field>(field_name));
+
+ if(iterFindDatabase != fieldsDatabase.end() ) //Ignore fields that don't exist in the database anymore.
+ {
+ Glib::RefPtr<Gnome::Gda::Column> field_info_document = field->get_field_info();
+
+ //Update the Field information that _might_ have changed in the database.
+ Glib::RefPtr<Gnome::Gda::Column> field_info = (*iterFindDatabase)->get_field_info();
+
+ //libgda does not tell us whether the field is auto_incremented, so we need to get that from the document.
+ field_info->set_auto_increment( field_info_document->get_auto_increment() );
+
+ //libgda does not tell us whether the field is auto_incremented, so we need to get that from the document.
+ //TODO_gda:field_info->set_primary_key( field_info_document->get_primary_key() );
+
+ //libgda does yet tell us correct default_value information so we need to get that from the document.
+ field_info->set_default_value( field_info_document->get_default_value() );
+
+ field->set_field_info(field_info);
+
+ result.push_back(*iter);
+ }
+ }
+
+ //Add any fields that are in the database, but not in the document:
+ for(type_vec_fields::iterator iter = fieldsDatabase.begin(); iter != fieldsDatabase.end(); ++iter)
+ {
+ const Glib::ustring field_name = (*iter)->get_name();
+
+ //Look in the result so far:
+ type_vec_fields::const_iterator iterFind = std::find_if(result.begin(), result.end(), predicate_FieldHasName<Field>(field_name));
+
+ //Add it if it is not there:
+ if(iterFind == result.end() )
+ result.push_back(*iter);
+ }
+
+ return result;
+}
+
+sharedptr<Field> get_fields_for_table_one_field(const Document* document, const Glib::ustring& table_name, const Glib::ustring& field_name)
+{
+ //Initialize output parameter:
+ sharedptr<Field> result;
+
+ if(field_name.empty() || table_name.empty())
+ return result;
+
+ type_vec_fields fields = get_fields_for_table(document, table_name); //TODO_Performance
+ type_vec_fields::iterator iter = std::find_if(fields.begin(), fields.end(), predicate_FieldHasName<Field>(field_name));
+ if(iter != fields.end()) //TODO: Handle error?
+ {
+ return *iter;
+ }
+
+ return sharedptr<Field>();
+}
+
//TODO_Performance: Avoid calling this so often.
//TODO: Put this in libgdamm.
type_vec_strings get_table_names_from_database(bool ignore_system_tables)
@@ -1921,6 +2004,41 @@ void set_fake_connection()
connection_pool->set_fake_connection();
}
+Gnome::Gda::Value get_lookup_value(Document* document, const Glib::ustring& /* table_name */, const sharedptr<const Relationship>& relationship, const sharedptr<const Field>& source_field, const Gnome::Gda::Value& key_value)
+{
+ Gnome::Gda::Value result;
+
+ sharedptr<Field> to_key_field = get_fields_for_table_one_field(document, relationship->get_to_table(), relationship->get_to_field());
+ if(to_key_field)
+ {
+ //Convert the value, in case the from and to fields have different types:
+ const Gnome::Gda::Value value_to_key_field = Conversions::convert_value(key_value, to_key_field->get_glom_type());
+
+ const Glib::ustring target_table = relationship->get_to_table();
+ Glib::RefPtr<Gnome::Gda::SqlBuilder> builder =
+ Gnome::Gda::SqlBuilder::create(Gnome::Gda::SQL_STATEMENT_SELECT);
+ builder->select_add_field(source_field->get_name(), target_table );
+ builder->select_add_target(target_table );
+ builder->set_where(
+ builder->add_cond(Gnome::Gda::SQL_OPERATOR_TYPE_EQ,
+ builder->add_field_id(to_key_field->get_name(), target_table),
+ builder->add_expr(value_to_key_field)));
+
+ Glib::RefPtr<Gnome::Gda::DataModel> data_model = query_execute_select(builder);
+ if(data_model && data_model->get_n_rows())
+ {
+ //There should be only 1 row. Well, there could be more but we will ignore them.
+ result = data_model->get_value_at(0, 0);
+ }
+ else
+ {
+ handle_error();
+ }
+ }
+
+ return result;
+}
+
} //namespace DbUtils
} //namespace Glom
diff --git a/glom/libglom/db_utils.h b/glom/libglom/db_utils.h
index fa97683..c706f57 100644
--- a/glom/libglom/db_utils.h
+++ b/glom/libglom/db_utils.h
@@ -51,6 +51,22 @@ typedef std::vector< sharedptr<Field> > type_vec_fields;
type_vec_fields get_fields_for_table_from_database(const Glib::ustring& table_name, bool including_system_fields = false);
bool get_field_exists_in_database(const Glib::ustring& table_name, const Glib::ustring& field_name);
+/** Get all the fields for a table, including any from the database that are not yet known in the document.
+ *
+ * @param table_name The name of the table whose fields should be listed.
+ * @param including_system_fields Whether extra non-user-visible fields should be included in the list.
+ * @result A list of fields.
+ */
+type_vec_fields get_fields_for_table(const Document* document, const Glib::ustring& table_name, bool including_system_fields = false);
+
+/** Get a single field definition for a table, even if the field is in the datasbase but not yet known in the document.
+ *
+ * @param table_name The name of the table whose fields should be listed.
+ * @param field_name The name of the field for which to get the definition.
+ * @result The field definition.
+ */
+sharedptr<Field> get_fields_for_table_one_field(const Document* document, const Glib::ustring& table_name, const Glib::ustring& field_name);
+
//TODO: Is this used directly?
typedef std::vector<Glib::ustring> type_vec_strings;
type_vec_strings get_table_names_from_database(bool ignore_system_tables = false);
@@ -160,6 +176,10 @@ Glib::ustring build_query_create_group(const Glib::ustring& group, bool superuse
Glib::ustring build_query_add_user_to_group(const Glib::ustring& group, const Glib::ustring& user);
+/** Get the value of the @a source_field from the @a relationship, using the @a key_value.
+ */
+Gnome::Gda::Value get_lookup_value(Document* document, const Glib::ustring& table_name, const sharedptr<const Relationship>& relationship, const sharedptr<const Field>& source_field, const Gnome::Gda::Value & key_value);
+
/** Allow a fake connection, so sqlbuilder_get_full_query() can work.
*/
void set_fake_connection();
diff --git a/glom/libglom/document/document.cc b/glom/libglom/document/document.cc
index b9f1493..a11f3a5 100644
--- a/glom/libglom/document/document.cc
+++ b/glom/libglom/document/document.cc
@@ -4682,6 +4682,38 @@ Glib::ustring Document::restore_backup_file(const Glib::ustring& backup_uri, con
return untarred_uri;
}
-
+
+
+Document::type_list_lookups Document::get_lookup_fields(const Glib::ustring& table_name, const Glib::ustring& field_name) const
+{
+ type_list_lookups result;
+
+ //Examine all fields for this table:
+ const type_vec_fields fields = get_table_fields(table_name); //TODO_Performance: Cache this?
+ for(type_vec_fields::const_iterator iter = fields.begin(); iter != fields.end(); ++iter)
+ {
+ sharedptr<Field> field = *iter;
+
+ //Examine each field that looks up its data from a relationship:
+ if(field && field->get_is_lookup())
+ {
+ //Get the relationship information:
+ sharedptr<Relationship> relationship = field->get_lookup_relationship();
+ if(relationship)
+ {
+ //If the relationship is triggererd by the specified field:
+ if(relationship->get_from_field() == field_name)
+ {
+ //Add it:
+ sharedptr<LayoutItem_Field> item = sharedptr<LayoutItem_Field>::create();
+ item->set_full_field_details(field);
+ result.push_back( type_pairFieldTrigger(item, relationship) );
+ }
+ }
+ }
+ }
+
+ return result;
+}
} //namespace Glom
diff --git a/glom/libglom/document/document.h b/glom/libglom/document/document.h
index db64044..79e2d1a 100644
--- a/glom/libglom/document/document.h
+++ b/glom/libglom/document/document.h
@@ -199,6 +199,16 @@ public:
* so that it is not used anymore in relationships, layouts, reports, etc.
*/
void remove_field(const Glib::ustring& table_name, const Glib::ustring& field_name);
+
+
+ typedef std::pair< sharedptr<LayoutItem_Field>, sharedptr<Relationship> > type_pairFieldTrigger;
+ typedef std::list<type_pairFieldTrigger> type_list_lookups;
+
+ /** Get the fields whose values should be looked up when @a field_name changes, with
+ * the relationship used to lookup the value.
+ */
+ type_list_lookups get_lookup_fields(const Glib::ustring& table_name, const Glib::ustring& field_name) const;
+
typedef std::vector< sharedptr<LayoutGroup> > type_list_layout_groups;
diff --git a/glom/mode_data/box_data.cc b/glom/mode_data/box_data.cc
index bee7bb4..efbb3a6 100644
--- a/glom/mode_data/box_data.cc
+++ b/glom/mode_data/box_data.cc
@@ -24,6 +24,7 @@
#include <libglom/data_structure/glomconversions.h>
#include <glom/utils_ui.h>
#include <libglom/data_structure/layout/layoutitem_field.h>
+#include <libglom/db_utils.h>
#include <libglom/privs.h>
#include <glom/python_embed/glom_python.h>
#include <glom/python_embed/python_ui_callbacks.h>
@@ -171,7 +172,8 @@ void Box_Data::create_layout()
set_unstored_data(false);
//Cache the table information, for performance:
- m_TableFields = get_fields_for_table(m_table_name);
+ const Document* document = dynamic_cast<const Document*>(get_document());
+ m_TableFields = DbUtils::get_fields_for_table(document, m_table_name);
}
bool Box_Data::fill_from_database()
@@ -298,7 +300,7 @@ void Box_Data::fill_layout_group_field_info(const sharedptr<LayoutGroup>& group,
sharedptr<const Relationship> relationship = document->get_relationship(m_table_name, relationship_name);
if(relationship)
{
- sharedptr<Field> field = get_fields_for_table_one_field(relationship->get_to_table(), item->get_name());
+ sharedptr<Field> field = DbUtils::get_fields_for_table_one_field(document, relationship->get_to_table(), item->get_name());
if(field)
{
item_field->set_full_field_details(field);
@@ -313,7 +315,7 @@ void Box_Data::fill_layout_group_field_info(const sharedptr<LayoutGroup>& group,
else
{
//Get the field info:
- sharedptr<Field> field = get_fields_for_table_one_field(m_table_name, item_field->get_name());
+ sharedptr<Field> field = DbUtils::get_fields_for_table_one_field(document, m_table_name, item_field->get_name());
if(field)
{
item_field->set_full_field_details(field); //TODO_Performance: Just use this as the output arg?
diff --git a/glom/mode_data/box_data_calendar_related.cc b/glom/mode_data/box_data_calendar_related.cc
index 37f6248..c752472 100644
--- a/glom/mode_data/box_data_calendar_related.cc
+++ b/glom/mode_data/box_data_calendar_related.cc
@@ -108,7 +108,11 @@ bool Box_Data_Calendar_Related::init_db_details(const Glib::ustring& parent_tabl
}
if(m_portal)
- m_key_field = get_fields_for_table_one_field(LayoutWidgetBase::m_table_name, m_portal->get_to_field_used());
+ {
+ Document* document = get_document();
+ m_key_field = DbUtils::get_fields_for_table_one_field(document,
+ LayoutWidgetBase::m_table_name, m_portal->get_to_field_used());
+ }
else
m_key_field.clear();
diff --git a/glom/mode_data/box_data_details.cc b/glom/mode_data/box_data_details.cc
index 0b509be..df1a3a7 100644
--- a/glom/mode_data/box_data_details.cc
+++ b/glom/mode_data/box_data_details.cc
@@ -735,7 +735,7 @@ void Box_Data_Details::on_flowtable_field_edited(const sharedptr<const LayoutIte
table_name = relationship->get_to_table();
const Glib::ustring to_field_name = relationship->get_to_field();
//Get the key field in the other table (the table that we will change)
- primary_key_field = get_fields_for_table_one_field(table_name, to_field_name); //TODO_Performance.
+ primary_key_field = DbUtils::get_fields_for_table_one_field(document, table_name, to_field_name); //TODO_Performance.
if(primary_key_field)
{
//Get the value of the corresponding key in the current table (that identifies the record in the table that we will change)
diff --git a/glom/mode_data/box_data_list_related.cc b/glom/mode_data/box_data_list_related.cc
index bde1f9c..1af2d61 100644
--- a/glom/mode_data/box_data_list_related.cc
+++ b/glom/mode_data/box_data_list_related.cc
@@ -108,7 +108,10 @@ bool Box_Data_List_Related::init_db_details(const Glib::ustring& parent_table, b
}
if(m_portal)
- m_key_field = get_fields_for_table_one_field(LayoutWidgetBase::m_table_name, m_portal->get_to_field_used());
+ {
+ m_key_field = DbUtils::get_fields_for_table_one_field(get_document(),
+ LayoutWidgetBase::m_table_name, m_portal->get_to_field_used());
+ }
else
m_key_field.clear();
diff --git a/glom/mode_data/db_adddel/db_adddel.cc b/glom/mode_data/db_adddel/db_adddel.cc
index 4453c33..db91b77 100644
--- a/glom/mode_data/db_adddel/db_adddel.cc
+++ b/glom/mode_data/db_adddel/db_adddel.cc
@@ -2150,7 +2150,8 @@ void DbAddDel::user_changed(const Gtk::TreeModel::iterator& row, guint col)
table_name = relationship->get_to_table();
const Glib::ustring to_field_name = relationship->get_to_field();
//Get the key field in the other table (the table that we will change)
- primary_key_field = get_fields_for_table_one_field(table_name, to_field_name); //TODO_Performance.
+ primary_key_field = DbUtils::get_fields_for_table_one_field(document,
+ table_name, to_field_name); //TODO_Performance.
if(primary_key_field)
{
//Get the value of the corresponding key in the current table (that identifies the record in the table that we will change)
diff --git a/glom/mode_design/box_db_table_relationships.cc b/glom/mode_design/box_db_table_relationships.cc
index 205cfd9..ab4ca41 100644
--- a/glom/mode_design/box_db_table_relationships.cc
+++ b/glom/mode_design/box_db_table_relationships.cc
@@ -20,6 +20,7 @@
//#include <gtkmm/builder.h>
#include "box_db_table_relationships.h"
+#include <libglom/db_utils.h>
#include <algorithm>
#include <glibmm/i18n.h>
@@ -90,7 +91,8 @@ bool Box_DB_Table_Relationships::fill_from_database()
Glib::RefPtr<Gnome::Gda::Connection> connection = sharedconnection->get_gda_connection();
//Set combo choices:
- m_AddDel.set_column_choices(m_colFromField, util_vecStrings_from_Fields(get_fields_for_table(m_table_name)));
+ m_AddDel.set_column_choices(m_colFromField, util_vecStrings_from_Fields(
+ DbUtils::get_fields_for_table(document, m_table_name)));
type_vec_strings vecTableNames = document->get_table_names(false /* ignore_system_tables */);
type_vec_strings vecTableNames_ustring(vecTableNames.begin(), vecTableNames.end());
@@ -245,7 +247,8 @@ void Box_DB_Table_Relationships::on_adddel_user_activated(const Gtk::TreeModel::
{
Glib::RefPtr<Gnome::Gda::Connection> connection = sharedconnection->get_gda_connection();
- type_vec_strings vecFields = util_vecStrings_from_Fields(get_fields_for_table(table_name));
+ Document* document = get_document();
+ type_vec_strings vecFields = util_vecStrings_from_Fields(DbUtils::get_fields_for_table(document, table_name));
//This would cause a lot of tedious re-filling:
//m_AddDel.set_column_choices(m_colToField, vecFields);
diff --git a/glom/mode_design/fields/box_db_table_definition.cc b/glom/mode_design/fields/box_db_table_definition.cc
index b770832..c223115 100644
--- a/glom/mode_design/fields/box_db_table_definition.cc
+++ b/glom/mode_design/fields/box_db_table_definition.cc
@@ -432,7 +432,8 @@ sharedptr<Field> Box_DB_Table_Definition::get_field_definition(const Gtk::TreeMo
//Start with original definitions, so that we preserve things like UNSIGNED.
//TODO maybe use document's fieldinfo instead of m_vecFields.
- sharedptr<const Field> field_temp = get_fields_for_table_one_field(m_table_name, strFieldNameBeforeEdit);
+ sharedptr<const Field> field_temp =
+ DbUtils::get_fields_for_table_one_field(pDoc, m_table_name, strFieldNameBeforeEdit);
if(field_temp)
{
Glib::RefPtr<Gnome::Gda::Column> fieldInfo = field_temp->get_field_info()->copy();
@@ -618,7 +619,7 @@ void Box_DB_Table_Definition::fill_fields()
//std::cout << "DEBUG: Box_DB_Table_Definition::fill_fields()" << std::endl;
//Update the fields (also checking the actual database):
- m_vecFields = get_fields_for_table(m_table_name);
+ m_vecFields = DbUtils::get_fields_for_table(get_document(), m_table_name);
}
bool Box_DB_Table_Definition::field_has_null_values(const sharedptr<const Field>& field)
diff --git a/glom/mode_design/fields/dialog_fielddefinition.cc b/glom/mode_design/fields/dialog_fielddefinition.cc
index 5be6478..868bdd7 100644
--- a/glom/mode_design/fields/dialog_fielddefinition.cc
+++ b/glom/mode_design/fields/dialog_fielddefinition.cc
@@ -23,6 +23,7 @@
#include <glom/glade_utils.h>
#include <glom/utils_ui.h>
#include "../../box_db_table.h"
+#include <libglom/db_utils.h>
//#include <libgnome/gnome-i18n.h>
#include <glibmm/i18n.h>
@@ -362,7 +363,7 @@ void Dialog_FieldDefinition::on_combo_lookup_relationship_changed()
if(!to_table.empty())
{
//Get the fields in the other table, and add them to the combo:
- const type_vec_fields fields_in_to_table = get_fields_for_table(to_table);
+ const type_vec_fields fields_in_to_table = DbUtils::get_fields_for_table(document, to_table);
for(type_vec_fields::const_iterator iter = fields_in_to_table.begin(); iter != fields_in_to_table.end(); ++iter)
{
m_pCombo_LookupField->append((*iter)->get_name());
diff --git a/glom/mode_design/layout/dialog_layout_list_related.cc b/glom/mode_design/layout/dialog_layout_list_related.cc
index a3ef120..1098e96 100644
--- a/glom/mode_design/layout/dialog_layout_list_related.cc
+++ b/glom/mode_design/layout/dialog_layout_list_related.cc
@@ -22,6 +22,7 @@
#include <glom/mode_design/layout/dialog_choose_field.h>
#include <glom/mode_design/layout/layout_item_dialogs/dialog_field_layout.h>
#include <libglom/utils.h> //For bold_message().
+#include <libglom/db_utils.h>
#include <glom/utils_ui.h> //For show_ok_dialog().
//#include <libgnome/gnome-i18n.h>
@@ -397,8 +398,8 @@ void Dialog_Layout_List_Related::on_combo_relationship_changed()
//The relationship's to field may not be a unique field, because that would
//prevent the portal from having multiple records.
sharedptr<Field> to_key_field =
- get_fields_for_table_one_field(relationship->get_to_table(),
- relationship->get_to_field());
+ DbUtils::get_fields_for_table_one_field(get_document(),
+ relationship->get_to_table(), relationship->get_to_field());
bool relationship_invalid = false;
if(!to_key_field)
{
diff --git a/glom/print_layout/canvas_print_layout.cc b/glom/print_layout/canvas_print_layout.cc
index 8233104..d6a1433 100644
--- a/glom/print_layout/canvas_print_layout.cc
+++ b/glom/print_layout/canvas_print_layout.cc
@@ -795,7 +795,9 @@ void Canvas_PrintLayout::fill_with_data(const Glib::RefPtr<Goocanvas::Group>& ca
sharedptr<const Relationship> relationship = layoutitem_portal->get_relationship();
if(relationship)
{
- const sharedptr<Field> from_field = get_fields_for_table_one_field(relationship->get_from_table(), relationship->get_from_field());
+ const Document* document = get_document();
+ const sharedptr<Field> from_field = DbUtils::get_fields_for_table_one_field(document,
+ relationship->get_from_table(), relationship->get_from_field());
const Gnome::Gda::Value from_key_value = get_field_value_in_database(from_field, found_set, 0 /* TODO: window */);
fill_with_data_portal(canvas_item, from_key_value);
}
diff --git a/tests/test_selfhosting_new_then_lookup.cc b/tests/test_selfhosting_new_then_lookup.cc
new file mode 100644
index 0000000..93d79a1
--- /dev/null
+++ b/tests/test_selfhosting_new_then_lookup.cc
@@ -0,0 +1,220 @@
+/* Glom
+ *
+ * Copyright (C) 2010 Openismus GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+71 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "tests/test_selfhosting_utils.h"
+#include <libglom/init.h>
+#include <libglom/utils.h>
+#include <libglom/db_utils.h>
+#include <libglom/connectionpool.h>
+#include <libglom/data_structure/glomconversions.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
+#include <glib.h> //For g_assert()
+#include <iostream>
+#include <cstdlib> //For EXIT_SUCCESS and EXIT_FAILURE
+
+static Glom::sharedptr<const Glom::LayoutItem_Field> get_lookup_field(const Glom::Document::type_list_lookups& container, const Glib::ustring& table_name, const Glib::ustring& field_name, Glom::sharedptr<const Glom::Relationship>& relationship)
+{
+ relationship.clear();
+ Glom::sharedptr<const Glom::LayoutItem_Field> result;
+
+ for(Glom::Document::type_list_lookups::const_iterator iter = container.begin(); iter != container.end(); ++iter)
+ {
+ const Glom::sharedptr<const Glom::LayoutItem_Field> layout_item = iter->first;
+ if(!layout_item)
+ return result;
+
+ const Glom::sharedptr<const Glom::Relationship> this_relationship = iter->second;
+ if(!this_relationship)
+ return result;
+
+ if(layout_item->get_table_used(table_name) != table_name)
+ return result;
+
+ if(layout_item->get_name() == field_name)
+ {
+ relationship = this_relationship;
+ return layout_item;
+ }
+ }
+
+ return result;
+}
+
+static bool contains_field(const Glom::Document::type_list_lookups& container, const Glib::ustring& table_name, const Glib::ustring& field_name)
+{
+ Glom::sharedptr<const Glom::Relationship> relationship;
+ return get_lookup_field(container, table_name, field_name, relationship);
+}
+
+static bool test(Glom::Document::HostingMode hosting_mode)
+{
+ Glom::Document document;
+ const bool recreated =
+ test_create_and_selfhost_from_example("example_smallbusiness.glom", document, hosting_mode);
+ if(!recreated)
+ {
+ std::cerr << "Recreation failed." << std::endl;
+ return false;
+ }
+
+ const Glib::ustring table_name = "invoice_lines";
+ Glom::sharedptr<const Glom::Field> primary_key_field = document.get_field_primary_key(table_name);
+ if(!primary_key_field)
+ {
+ std::cerr << "Failure: primary_key_field is empty." << std::endl;
+ return false;
+ }
+
+
+ // Get the fields whose values should be looked up when a field changes:
+ const Glom::Document::type_list_lookups lookups = document.get_lookup_fields(table_name, "product_id");
+ if(lookups.size() != 3)
+ {
+ std::cerr << "Failure: Unexpected number of lookups: " << lookups.size() << std::endl;
+ return false;
+ }
+
+ if(!contains_field(lookups, table_name, "product_price"))
+ {
+ std::cerr << "Failure: Expected lookup field not found." << std::endl;
+ return false;
+ }
+
+ if(!contains_field(lookups, table_name, "product_name"))
+ {
+ std::cerr << "Failure: Expected lookup field not found." << std::endl;
+ return false;
+ }
+
+ if(!contains_field(lookups, table_name, "vat_percentage"))
+ {
+ std::cerr << "Failure: Expected lookup field not found." << std::endl;
+ return false;
+ }
+
+ const Glib::ustring field_name = "product_price";
+ Glom::sharedptr<const Glom::Relationship> relationship;
+ const Glom::sharedptr<const Glom::LayoutItem_Field> layout_field =
+ get_lookup_field(lookups, table_name, field_name, relationship);
+ if(!layout_field)
+ {
+ std::cerr << "Failure: The lookup field is empty." << std::endl;
+ return false;
+ }
+
+ if(!relationship)
+ {
+ std::cerr << "Failure: The lookup relationship is empty." << std::endl;
+ return false;
+ }
+
+ if(relationship->get_to_table() != "products")
+ {
+ std::cerr << "Failure: The relationship's to table is unexpected." << std::endl;
+ return false;
+ }
+
+ if(layout_field->get_table_used(table_name) != table_name)
+ {
+ std::cerr << "Failure: The lookup field's table is unexpected" << std::endl;
+ return false;
+ }
+
+ if(layout_field->get_name() != field_name)
+ {
+ std::cerr << "Failure: The lookup field's name is unexpected." << std::endl;
+ return false;
+ }
+
+ const Glom::sharedptr<const Glom::Field> field = layout_field->get_full_field_details();
+ if(!field)
+ {
+ std::cerr << "Failure: The lookup item's field is empty." << std::endl;
+ return false;
+ }
+
+ if(field->get_name() != field_name)
+ {
+ std::cerr << "Failure: The lookup item's field name is unexpected." << std::endl;
+ return false;
+ }
+
+ if(!field->get_is_lookup())
+ {
+ std::cerr << "Failure: The lookup field is not a lookup." << std::endl;
+ return false;
+ }
+
+ if(relationship != field->get_lookup_relationship())
+ {
+ std::cerr << "Failure: The lookup field's relationship is not expected." << std::endl;
+ return false;
+ }
+
+ //Lookup the value from the related record.
+ //TODO:
+ const Glom::sharedptr<Glom::Field> field_source =
+ document.get_field(relationship->get_to_table(), "price");
+ const Gnome::Gda::Value value = Glom::DbUtils::get_lookup_value(&document,
+ table_name, relationship, field_source, Gnome::Gda::Value(2));
+
+ const GType expected_type =
+ (hosting_mode != Glom::Document::HOSTING_MODE_SQLITE ? GDA_TYPE_NUMERIC : G_TYPE_DOUBLE);
+ if(value.get_value_type() != expected_type)
+ {
+ std::cerr << "Failure: The value has an unexpected type: " <<
+ g_type_name(value.get_value_type()) << std::endl;
+ return false;
+ }
+
+ if(Glom::Conversions::get_double_for_gda_value_numeric(value) != 3.5f)
+ {
+ std::cerr << "Failure: The value has an unexpected value: " << value.to_string() << std::endl;
+ return false;
+ }
+
+ test_selfhosting_cleanup();
+
+ return true;
+}
+
+int main()
+{
+ Glom::libglom_init();
+
+ if(!test(Glom::Document::HOSTING_MODE_POSTGRES_SELF))
+ {
+ std::cerr << "Failed with PostgreSQL" << std::endl;
+ test_selfhosting_cleanup();
+ return EXIT_FAILURE;
+ }
+
+ if(!test(Glom::Document::HOSTING_MODE_SQLITE))
+ {
+ std::cerr << "Failed with SQLite" << std::endl;
+ test_selfhosting_cleanup();
+ return EXIT_FAILURE;
+ }
+
+ Glom::libglom_deinit();
+
+ return EXIT_SUCCESS;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]