Move use of Glom.build_sql*() into a new SqlUtils class.
[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.apache.commons.lang3.StringUtils;
25 import org.glom.libglom.Document;
26 import org.glom.libglom.Field;
27 import org.glom.libglom.FieldVector;
28 import org.glom.libglom.Glom;
29 import org.glom.libglom.LayoutGroupVector;
30 import org.glom.libglom.LayoutItem_Portal;
31 import org.glom.libglom.Relationship;
32 import org.glom.libglom.SortClause;
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.SqlUtils;
37 import org.glom.web.server.Utils;
38 import org.glom.web.shared.DataItem;
39 import org.glom.web.shared.TypedDataItem;
40
41 import com.mchange.v2.c3p0.ComboPooledDataSource;
42
43 /**
44  *
45  */
46 public class RelatedListDBAccess extends ListDBAccess {
47         private TypedDataItem foreignKeyValue = null;
48         private LayoutItem_Portal portal = null;
49         private String parentTable = null;
50         private String whereClauseToTableName = null;
51         private Field whereClauseToKeyField = null;
52
53         public RelatedListDBAccess(final Document document, final String documentID, final ComboPooledDataSource cpds,
54                         final String tableName, final String relationshipName) {
55                 super(document, documentID, cpds, tableName);
56
57                 final LayoutItem_Portal portal = getPortal(relationshipName);
58                 if (portal == null) {
59                         Log.error(documentID, tableName, "Couldn't find LayoutItem_Portal \"" + relationshipName + "\" in table \""
60                                         + tableName + "\". " + "Cannot retrive data for the related list.");
61                         return;
62                 }
63
64                 parentTable = tableName;
65                 // Reassign the tableName variable to table that is being used for the related list. This needs to be set before
66                 // getFieldsToShowForSQLQuery().
67                 this.tableName = portal.get_table_used("" /* parent table - not relevant */);
68
69                 // Convert the libglom LayoutGroup object into a LayoutFieldVector suitable for SQL queries.
70                 final LayoutGroupVector tempLayoutGroupVec = new LayoutGroupVector();
71                 tempLayoutGroupVec.add(portal);
72                 fieldsToGet = getFieldsToShowForSQLQuery(tempLayoutGroupVec);
73
74                 /*
75                  * The code from the rest of this method was inspired by code from Glom:
76                  * Base_DB::set_found_set_where_clause_for_portal()
77                  */
78                 final Relationship relationship = portal.get_relationship();
79
80                 // Notice that, in the case that this is a portal to doubly-related records,
81                 // The WHERE clause mentions the first-related table (though by the alias defined in extra_join)
82                 // and we add an extra JOIN to mention the second-related table.
83
84                 whereClauseToTableName = relationship.get_to_table();
85                 whereClauseToKeyField = getFieldInTable(relationship.get_to_field(), whereClauseToTableName);
86
87                 // Add primary key
88                 fieldsToGet.add(getPrimaryKeyLayoutItemField(this.tableName));
89
90                 final Relationship relationshipRelated = portal.get_related_relationship();
91                 if (relationshipRelated != null) {
92                         Log.error(documentID, tableName, "The related relationship " + relationshipRelated.get_name()
93                                         + " is not empty but the related relationship code has not been implemented yet.");
94
95                         // FIXME port this Glom code to Java
96                         // @formatter:off
97                         /*
98                     //Add the extra JOIN:
99                     sharedptr<UsesRelationship> uses_rel_temp = sharedptr<UsesRelationship>::create();
100                     uses_rel_temp->set_relationship(relationship);
101                     found_set.m_extra_join = relationship;
102
103                     //Adjust the WHERE clause appropriately for the extra JOIN:
104                     whereClauseToTableName = uses_rel_temp->get_sql_join_alias_name();
105
106                     const Glib::ustring to_field_name = uses_rel_temp->get_to_field_used();
107                     where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), to_field_name);
108                     std::cout << "extra_join=" << found_set.m_extra_join << std::endl;
109                     std::cout << "extra_join where_clause_to_key_field=" << where_clause_to_key_field->get_name() << std::endl;
110                          */
111                         // @formatter:on
112                 }
113
114                 // set portal field
115                 this.portal = portal;
116
117         }
118
119         public ArrayList<DataItem[]> getData(final int start, final int length, final TypedDataItem foreignKeyValue,
120                         final boolean useSortClause, final int sortColumnIndex, final boolean isAscending) {
121
122                 if (tableName == null || foreignKeyValue == null || foreignKeyValue.isEmpty()) {
123                         return null;
124                 }
125
126                 // Set the foreignKeyValue
127                 this.foreignKeyValue = foreignKeyValue;
128
129                 return getListData("" /* quickFind */, start, length, useSortClause, sortColumnIndex, isAscending);
130         }
131
132         /*
133          * (non-Javadoc)
134          * 
135          * @see org.glom.web.server.ListDBAccess#getExpectedResultSize()
136          */
137         public int getExpectedResultSize(final TypedDataItem foreignKeyValue) {
138
139                 // Set the foreignKeyValue
140                 this.foreignKeyValue = foreignKeyValue;
141
142                 if (fieldsToGet == null || fieldsToGet.size() <= 0 || this.foreignKeyValue == null)
143                         return -1;
144
145                 return getResultSizeOfSQLQuery();
146         }
147
148         /*
149          * (non-Javadoc)
150          * 
151          * @see org.glom.web.server.ListDBAccess#getSelectQuery(org.glom.libglom.LayoutFieldVector,
152          * org.glom.libglom.SortClause)
153          */
154         @Override
155         protected String getSelectQuery(final String quickFind, final SortClause sortClause) {
156                 // TODO: combine this method with getCountQuery() to remove duplicate code
157                 if (portal == null) {
158                         Log.error(documentID, parentTable,
159                                         "The Portal has not been found. Cannot build query for the related list.");
160                         return "";
161                 }
162
163                 if (foreignKeyValue == null || foreignKeyValue.isEmpty()) {
164                         Log.error(documentID, parentTable,
165                                         "The value for the foreign key has not been set. Cannot build query for the related list.");
166                         return "";
167                 }
168
169                 SqlExpr whereClause = new SqlExpr(); // Note that we ignore quickFind.
170                 // only attempt to make a where clause if it makes sense to do so
171                 if (!StringUtils.isEmpty(whereClauseToTableName)) {
172                         final Value gdaForeignKeyValue = Utils.getGlomTypeGdaValueForTypedDataItem(documentID, tableName,
173                                         whereClauseToKeyField.get_glom_type(), foreignKeyValue);
174                         if (gdaForeignKeyValue != null)
175                                 whereClause = Glom.build_simple_where_expression(whereClauseToTableName, whereClauseToKeyField,
176                                                 gdaForeignKeyValue);
177                 }
178
179                 return SqlUtils.build_sql_select_with_where_clause(tableName, fieldsToGet, whereClause, sortClause);
180
181         }
182
183         private Field getFieldInTable(final String fieldName, final String tableName) {
184
185                 if (StringUtils.isEmpty(tableName))
186                         return null;
187
188                 final FieldVector fields = document.get_table_fields(tableName);
189                 for (int i = 0; i < fields.size(); i++) {
190                         final Field field = fields.get(i);
191                         if (fieldName.equals(field.get_name())) {
192                                 return field;
193                         }
194                 }
195
196                 return null;
197         }
198
199         /*
200          * (non-Javadoc)
201          * 
202          * @see org.glom.web.server.ListDBAccess#getCountQuery()
203          */
204         @Override
205         protected String getCountQuery() {
206                 // TODO: combine this method with getSelectQuery() to remove duplicate code
207                 if (portal == null) {
208                         Log.error(documentID, parentTable,
209                                         "The Portal has not been found. Cannot build query for the related list.");
210                         return "";
211                 }
212
213                 if (foreignKeyValue == null || foreignKeyValue.isEmpty()) {
214                         Log.error(documentID, parentTable,
215                                         "The value for the foreign key has not been set. Cannot build query for the related list.");
216                         return "";
217                 }
218
219                 SqlExpr whereClause = new SqlExpr();
220                 // only attempt to make a where clause if it makes sense to do so
221                 if (!whereClauseToTableName.isEmpty() && whereClauseToKeyField != null) {
222                         final Value gdaForeignKeyValue = Utils.getGlomTypeGdaValueForTypedDataItem(documentID, tableName,
223                                         whereClauseToKeyField.get_glom_type(), foreignKeyValue);
224                         if (gdaForeignKeyValue != null)
225                                 whereClause = Glom.build_simple_where_expression(whereClauseToTableName, whereClauseToKeyField,
226                                                 gdaForeignKeyValue);
227                 }
228
229                 return SqlUtils.build_sql_count_select_with_where_clause(tableName, fieldsToGet, whereClause);
230         }
231
232 }