Rename PrimaryKeyItem to TypedDataItem.
[online-glom:gwt-glom.git] / src / main / java / org / glom / web / server / database / RelatedListDBAccess.java
1 /*
2  * Copyright (C) 2011 Openismus GmbH
3  *
4  * This file is part of GWT-Glom.
5  *
6  * GWT-Glom is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * GWT-Glom is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with GWT-Glom.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package org.glom.web.server.database;
21
22 import java.util.ArrayList;
23
24 import org.glom.libglom.Document;
25 import org.glom.libglom.Field;
26 import org.glom.libglom.FieldVector;
27 import org.glom.libglom.Glom;
28 import org.glom.libglom.LayoutGroupVector;
29 import org.glom.libglom.LayoutItem_Portal;
30 import org.glom.libglom.Relationship;
31 import org.glom.libglom.SortClause;
32 import org.glom.libglom.SqlBuilder;
33 import org.glom.libglom.SqlExpr;
34 import org.glom.libglom.Value;
35 import org.glom.web.server.Log;
36 import org.glom.web.server.Utils;
37 import org.glom.web.shared.DataItem;
38 import org.glom.web.shared.TypedDataItem;
39
40 import com.mchange.v2.c3p0.ComboPooledDataSource;
41
42 /**
43  * @author Ben Konrath <ben@bagu.org>
44  */
45 public class RelatedListDBAccess extends ListDBAccess {
46         private TypedDataItem foreignKeyValue = null;
47         private LayoutItem_Portal portal = null;
48         private String parentTable = null;
49         private String whereClauseToTableName = null;
50         private Field whereClauseToKeyField = null;
51
52         public RelatedListDBAccess(Document document, String documentID, ComboPooledDataSource cpds, String tableName,
53                         String relationshipName) {
54                 super(document, documentID, cpds, tableName);
55
56                 LayoutItem_Portal portal = getPortal(relationshipName);
57                 if (portal == null) {
58                         Log.error(documentID, tableName, "Couldn't find LayoutItem_Portal \"" + relationshipName + "\" in table \""
59                                         + tableName + "\". " + "Cannot retrive data for the related list.");
60                         return;
61                 }
62
63                 parentTable = tableName;
64                 // Reassign the tableName variable to table that is being used for the related list. This needs to be set before
65                 // getFieldsToShowForSQLQuery().
66                 this.tableName = portal.get_table_used("" /* parent table - not relevant */);
67
68                 // Convert the libglom LayoutGroup object into a LayoutFieldVector suitable for SQL queries.
69                 LayoutGroupVector tempLayoutGroupVec = new LayoutGroupVector();
70                 tempLayoutGroupVec.add(portal);
71                 fieldsToGet = getFieldsToShowForSQLQuery(tempLayoutGroupVec);
72
73                 /*
74                  * The code from the rest of this method was ported from Glom: Base_DB::set_found_set_where_clause_for_portal()
75                  */
76                 Relationship relationship = portal.get_relationship();
77
78                 // Notice that, in the case that this is a portal to doubly-related records,
79                 // The WHERE clause mentions the first-related table (though by the alias defined in extra_join)
80                 // and we add an extra JOIN to mention the second-related table.
81
82                 whereClauseToTableName = relationship.get_to_table();
83                 whereClauseToKeyField = getFieldInTable(relationship.get_to_field(), relationship.get_to_table());
84
85                 Relationship relationshipRelated = portal.get_related_relationship();
86                 if (relationshipRelated != null) {
87                         Log.error(documentID, tableName, "The related relationship " + relationshipRelated.get_name()
88                                         + " is not empty but the related relationship code has not been implemented yet.");
89
90                         // FIXME port this Glom code to Java
91                         // @formatter:off
92                         /* 
93                     //Add the extra JOIN:
94                     sharedptr<UsesRelationship> uses_rel_temp = sharedptr<UsesRelationship>::create();
95                     uses_rel_temp->set_relationship(relationship);
96                     found_set.m_extra_join = relationship;
97
98                     //Adjust the WHERE clause appropriately for the extra JOIN:
99                     whereClauseToTableName = uses_rel_temp->get_sql_join_alias_name();
100
101                     const Glib::ustring to_field_name = uses_rel_temp->get_to_field_used();
102                     where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), to_field_name);
103                     std::cout << "extra_join=" << found_set.m_extra_join << std::endl;
104                     std::cout << "extra_join where_clause_to_key_field=" << where_clause_to_key_field->get_name() << std::endl;
105                     */
106                     // @formatter:on
107                 }
108
109                 // set portal field
110                 this.portal = portal;
111
112         }
113
114         public ArrayList<DataItem[]> getData(int start, int length, TypedDataItem foreignKeyValue, boolean useSortClause,
115                         int sortColumnIndex, boolean isAscending) {
116
117                 if (tableName == null || foreignKeyValue == null || foreignKeyValue.isEmpty()) {
118                         return null;
119                 }
120
121                 // Set the foreignKeyValue
122                 this.foreignKeyValue = foreignKeyValue;
123
124                 return getListData(start, length, useSortClause, sortColumnIndex, isAscending);
125         }
126
127         /*
128          * (non-Javadoc)
129          * 
130          * @see org.glom.web.server.ListDBAccess#getExpectedResultSize()
131          */
132         public int getExpectedResultSize(TypedDataItem foreignKeyValue) {
133
134                 // Set the foreignKeyValue
135                 this.foreignKeyValue = foreignKeyValue;
136
137                 if (fieldsToGet == null || fieldsToGet.size() <= 0 || this.foreignKeyValue == null)
138                         return -1;
139
140                 return getResultSizeOfSQLQuery();
141         }
142
143         /*
144          * (non-Javadoc)
145          * 
146          * @see org.glom.web.server.ListDBAccess#getSelectQuery(org.glom.libglom.LayoutFieldVector,
147          * org.glom.libglom.SortClause)
148          */
149         @Override
150         protected String getSelectQuery(SortClause sortClause) {
151
152                 if (portal == null) {
153                         Log.error(documentID, parentTable,
154                                         "The Portal has not been found. Cannot build query for the related list.");
155                         return "";
156                 }
157
158                 if (foreignKeyValue == null || foreignKeyValue.isEmpty()) {
159                         Log.error(documentID, parentTable,
160                                         "The value for the foreign key has not been set. Cannot build query for the related list.");
161                         return "";
162                 }
163
164                 SqlExpr whereClause = new SqlExpr();
165                 // only make attempt to make a where clause if it makes sense to do so
166                 if (!whereClauseToTableName.isEmpty() && whereClauseToKeyField != null) {
167                         Value gdaForeignKeyValue = Utils.getGdaValueForPrimaryKey(documentID, tableName,
168                                         whereClauseToKeyField.get_glom_type(), foreignKeyValue);
169                         if (gdaForeignKeyValue != null)
170                                 whereClause = Glom.build_simple_where_expression(whereClauseToTableName, whereClauseToKeyField,
171                                                 gdaForeignKeyValue);
172                 }
173
174                 Relationship extraJoin = new Relationship(); // Ignored.
175                 SqlBuilder builder = Glom.build_sql_select_with_where_clause(tableName, fieldsToGet, whereClause, extraJoin,
176                                 sortClause);
177                 return Glom.sqlbuilder_get_full_query(builder);
178
179         }
180
181         private Field getFieldInTable(String fieldName, String tableName) {
182
183                 if (tableName.isEmpty() || fieldName.isEmpty())
184                         return null;
185
186                 FieldVector fields = document.get_table_fields(tableName);
187                 for (int i = 0; i < fields.size(); i++) {
188                         Field field = fields.get(i);
189                         if (fieldName.equals(field.get_name())) {
190                                 return field;
191                         }
192                 }
193
194                 return null;
195         }
196
197         /*
198          * (non-Javadoc)
199          * 
200          * @see org.glom.web.server.ListDBAccess#getCountQuery()
201          */
202         @Override
203         protected String getCountQuery() {
204
205                 if (portal == null) {
206                         Log.error(documentID, parentTable,
207                                         "The Portal has not been found. Cannot build query for the related list.");
208                         return "";
209                 }
210
211                 if (foreignKeyValue == null || foreignKeyValue.isEmpty()) {
212                         Log.error(documentID, parentTable,
213                                         "The value for the foreign key has not been set. Cannot build query for the related list.");
214                         return "";
215                 }
216
217                 SqlExpr whereClause = new SqlExpr();
218                 // only make attempt to make a where clause if it makes sense to do so
219                 if (!whereClauseToTableName.isEmpty() && whereClauseToKeyField != null) {
220                         Value gdaForeignKeyValue = Utils.getGdaValueForPrimaryKey(documentID, tableName,
221                                         whereClauseToKeyField.get_glom_type(), foreignKeyValue);
222                         if (gdaForeignKeyValue != null)
223                                 whereClause = Glom.build_simple_where_expression(whereClauseToTableName, whereClauseToKeyField,
224                                                 gdaForeignKeyValue);
225                 }
226
227                 SqlBuilder builder = Glom.build_sql_select_with_where_clause(tableName, fieldsToGet, whereClause);
228                 SqlBuilder countBuilder = Glom.build_sql_select_count_rows(builder);
229                 return Glom.sqlbuilder_get_full_query(countBuilder);
230
231         }
232
233 }