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