1 /*
2 * $Source$
3 * $Revision$
4 *
5 * Copyright (C) 2000 William Chesters
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * William Chesters <williamc At paneris.org>
42 * http://paneris.org/~williamc
43 * Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44 */
45
46 package org.melati.poem;
47
48 import org.melati.poem.util.Cache;
49
50 import java.util.Enumeration;
51 import java.util.List;
52 import java.io.PrintStream;
53 import java.sql.ResultSet;
54 import java.sql.SQLException;
55
56 /**
57 * A table.
58 *
59 * @since 14-Apr-2008
60 */
61 public interface Table<P extends Persistent> {
62 /**
63 * The database to which the table is attached.
64 * @return the db
65 */
66 Database getDatabase();
67
68 /**
69 * Initialise the table.
70 */
71 void init();
72 /**
73 * Do stuff immediately after table initialisation.
74 * <p>
75 * This base method clears the column info caches and adds a listener
76 * to the column info table to maintain the caches.
77 * <p>
78 * It may be overridden to perform other actions. For example to
79 * ensure required rows exist in tables that define numeric ID's for
80 * codes.
81 *
82 * @see #notifyColumnInfo(ColumnInfo)
83 * @see #clearColumnInfoCaches()
84 */
85 void postInitialise();
86
87 /**
88 * Create the (possibly overridden) TableInfo if it has not yet been created.
89 */
90 void createTableInfo();
91 /**
92 * The table's programmatic name. Identical with its name in the DSD (if the
93 * table was defined there) and in its <TT>tableinfo</TT> entry.
94 * This will normally be the same as the name in the RDBMS itself, however that name
95 * may be translated to avoid DBMS specific name clashes.
96 *
97 * @return the table name, case as defined in the DSD
98 * @see org.melati.poem.dbms.Dbms#melatiName(String)
99 */
100 String getName();
101
102 /**
103 * @return table name quoted using the DBMS' specific quoting rules.
104 */
105 String quotedName();
106
107 /**
108 * The human-readable name of the table. POEM itself doesn't use this, but
109 * it's available to applications and Melati's generic admin system as a
110 * default label for the table and caption for its records.
111 * @return The human-readable name of the table
112 */
113 String getDisplayName();
114
115 /**
116 * A brief description of the table's function. POEM itself doesn't use
117 * this, but it's available to applications and Melati's generic admin system
118 * as a default label for the table and caption for its records.
119 * @return the brief description
120 */
121 String getDescription();
122
123 /**
124 * The category of this table. POEM itself doesn't use
125 * this, but it's available to applications and Melati's generic admin system
126 * as a default label for the table and caption for its records.
127 *
128 * @return the category
129 */
130 TableCategory getCategory();
131
132 /**
133 * @return the {@link org.melati.poem.TableInfo} for this table
134 */
135 TableInfo getInfo();
136
137 /**
138 * The troid (<TT>id</TT>) of the table's entry in the <TT>tableinfo</TT>
139 * table. It will always have one (except during initialisation, which the
140 * application programmer will never see).
141 *
142 * @return id in TableInfo metadata table
143 */
144 Integer tableInfoID();
145
146 /**
147 * The table's column with a given name. If the table is defined in the DSD
148 * under the name <TT><I>foo</I></TT>, there will be an
149 * application-specialised <TT>Table</TT> subclass, called
150 * <TT><I>Foo</I>Table</TT> (and available as <TT>get<I>Foo</I>Table</TT>
151 * from the application-specialised <TT>Database</TT> subclass) which has
152 * extra named methods for accessing the table's predefined <TT>Column</TT>s.
153 *
154 * @param nameP name of column to get
155 * @return column of that name
156 * @throws org.melati.poem.NoSuchColumnPoemException if there is no column with that name
157 */
158 Column<?> getColumn(String nameP) throws NoSuchColumnPoemException;
159
160 /**
161 * All the table's columns.
162 *
163 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
164 * @see org.melati.poem.Column
165 */
166 Enumeration<Column<?>> columns();
167
168 /**
169 * A list of all the table's columns.
170 */
171 List<Column<?>> getColumns();
172
173 /**
174 * @return the number of columns in this table.
175 */
176 int getColumnsCount();
177
178 /**
179 * @param columnInfoID the Id for the Column table
180 * @return the Column with a TROID equal to columnInfoID
181 */
182 Column<?> columnWithColumnInfoID(int columnInfoID);
183
184 /**
185 * The table's troid column. Every table in a POEM database must have a
186 * troid (table row ID, or table-unique non-nullable integer primary key),
187 * often but not necessarily called <TT>id</TT>, so that it can be
188 * conveniently `named'.
189 *
190 * @return the id column
191 * @see #getObject(Integer)
192 */
193 Column<Integer> troidColumn();
194
195 /**
196 * @return The table's deleted-flag column, if any.
197 */
198 Column<Boolean> deletedColumn();
199
200 /**
201 * The table's primary display column, the Troid column if not set.
202 * This is the column used to represent records from the table
203 * concisely in reports or whatever. It is determined
204 * at initialisation time by examining the <TT>Column</TT>s
205 * <TT>getPrimaryDisplay()</TT> flags.
206 *
207 * @return the table's display column, or <TT>null</TT> if it hasn't got one
208 *
209 * see Column#setColumnInfo
210 * @see org.melati.poem.ReferencePoemType#_stringOfCooked
211 * @see org.melati.poem.DisplayLevel#primary
212 */
213 Column<?> displayColumn();
214
215 /**
216 * @param column the display column to set
217 */
218 void setDisplayColumn(Column<?> column);
219
220 /**
221 * In a similar manner to the primary display column, each table can have
222 * one primary criterion column.
223 * <p>
224 * The Primary Criterion is the main grouping field of the table,
225 * ie the most important non-unique type field.
226 * <p>
227 * For example the Primary Criterion for a User table might be Nationality.
228 *
229 * @return the search column, if any
230 * @see org.melati.poem.Searchability
231 */
232 Column<?> primaryCriterionColumn();
233
234 /**
235 * @param column the search column to set
236 */
237 void setSearchColumn(Column<?> column);
238
239 /**
240 * If the troidColumn has yet to be set then returns an empty string.
241 *
242 * @return comma separated list of the columns to order by
243 */
244 String defaultOrderByClause();
245
246 /**
247 * Clear caches.
248 */
249 void clearColumnInfoCaches();
250
251 /**
252 * Clears columnInfo caches, normally a no-op.
253 *
254 * @param infoP the possibly null ColumnInfo meta-data persistent
255 */
256 void notifyColumnInfo(ColumnInfo infoP);
257
258 /**
259 * Return columns at a display level in display order.
260 *
261 * @param level the {@link org.melati.poem.DisplayLevel} to select
262 * @return an Enumeration of columns at the given level
263 */
264 Enumeration<Column<?>> displayColumns(DisplayLevel level);
265
266 /**
267 * @param level the {@link org.melati.poem.DisplayLevel} to select
268 * @return the number of columns at a display level.
269 */
270 int displayColumnsCount(DisplayLevel level);
271
272 /**
273 * The table's columns for detailed display in display order.
274 *
275 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
276 * @see org.melati.poem.Column
277 * @see #displayColumns(org.melati.poem.DisplayLevel)
278 * @see org.melati.poem.DisplayLevel#detail
279 */
280 Enumeration<Column<?>> getDetailDisplayColumns();
281
282 /**
283 * @return the number of columns at display level <tt>Detail</tt>
284 */
285 int getDetailDisplayColumnsCount();
286
287 /**
288 * The table's columns designated for display in a record, in display order.
289 *
290 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
291 * @see org.melati.poem.Column
292 * @see #displayColumns(org.melati.poem.DisplayLevel)
293 * @see org.melati.poem.DisplayLevel#record
294 */
295 Enumeration<Column<?>> getRecordDisplayColumns();
296
297 /**
298 * @return the number of columns at display level <tt>Record</tt>
299 */
300 int getRecordDisplayColumnsCount();
301
302 /**
303 * The table's columns designated for display in a record summary, in display
304 * order.
305 *
306 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
307 * @see org.melati.poem.Column
308 * @see #displayColumns(org.melati.poem.DisplayLevel)
309 * @see org.melati.poem.DisplayLevel#summary
310 */
311 Enumeration<Column<?>> getSummaryDisplayColumns();
312
313 /**
314 * @return the number of columns at display level <tt>Summary</tt>
315 */
316 int getSummaryDisplayColumnsCount();
317
318 /**
319 * The table's columns designated for use as search criteria, in display
320 * order.
321 *
322 * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
323 * @see org.melati.poem.Column
324 */
325 Enumeration<Column<?>> getSearchCriterionColumns();
326
327 /**
328 * @return the number of columns which are searchable
329 */
330 int getSearchCriterionColumnsCount();
331
332 /**
333 * Use this for DDL statements, ie those which alter the structure of the db.
334 * Postgresql in particular does not like DDL statements being executed within a transaction.
335 *
336 * @param sql the SQL DDL statement to execute
337 * @throws org.melati.poem.StructuralModificationFailedPoemException
338 */
339 void dbModifyStructure(String sql)
340 throws StructuralModificationFailedPoemException;
341
342 /**
343 * Constraints are not used in POEM, but you might want to use them if
344 * exporting the db or using schema visualisation tools.
345 */
346 void dbAddConstraints();
347
348 /**
349 * When deleting a table and used in tests.
350 */
351 void invalidateTransactionStuffs();
352
353 /**
354 * @param transaction possibly null if working with the committed transaction
355 * @param persistent the Persistent to load
356 */
357 void load(PoemTransaction transaction, Persistent persistent);
358
359 /**
360 * The Transaction cannot be null, as this is trapped in
361 * #deleteLock(SessionToken).
362 * @param troid id of row to delete
363 * @param transaction a non-null transaction
364 */
365 void delete(Integer troid, PoemTransaction transaction);
366
367 /**
368 * @param transaction our PoemTransaction
369 * @param p the Persistent to write
370 */
371 void writeDown(PoemTransaction transaction, Persistent p);
372
373 /**
374 * Invalidate table cache.
375 *
376 * NOTE Invalidated cache elements are reloaded when next read
377 */
378 void uncache();
379
380 /**
381 * @param maxSize new maximum size
382 */
383 void trimCache(int maxSize);
384
385 /**
386 * @return the Cache Info object
387 */
388 Cache.Info getCacheInfo();
389
390 /**
391 * Add a {@link org.melati.poem.TableListener} to this Table.
392 */
393 void addListener(TableListener listener);
394
395 /**
396 * Notify the table that one if its records is about to be changed in a
397 * transaction. You can (with care) use this to support cacheing of
398 * frequently-used facts about the table's records.
399 *
400 * @param transaction the transaction in which the change will be made
401 * @param persistent the record to be changed
402 */
403 void notifyTouched(PoemTransaction transaction, Persistent persistent);
404
405 /**
406 * @return the Transaction serial
407 */
408 long serial(PoemTransaction transaction);
409
410 /**
411 * Lock this record.
412 */
413 void readLock();
414
415 /**
416 * The object from the table with a given troid.
417 *
418 * @param troid Every record (object) in a POEM database must have a
419 * troid (table row ID, or table-unique non-nullable
420 * integer primary key), often but not necessarily called
421 * <TT>id</TT>, so that it can be conveniently `named' for
422 * retrieval by this method.
423 *
424 * @return A <TT>Persistent</TT> of the record with the given troid;
425 * or, if the table was defined in the DSD under the name
426 * <TT><I>foo</I></TT>, an application-specialised subclass
427 * <TT><I>Foo</I></TT> of <TT>Persistent</TT>. In that case, there
428 * will also be an application-specialised <TT>Table</TT> subclass,
429 * called <TT><I>Foo</I>Table</TT> (and available as
430 * <TT>get<I>Foo</I>Table</TT> from the application-specialised
431 * <TT>Database</TT> subclass), which has a matching method
432 * <TT>get<I>Foo</I>Object</TT> for obtaining the specialised object
433 * under its own type. Note that no access checks are done at this
434 * stage: you may not be able to do anything with the object handle
435 * returned from this method without provoking a
436 * <TT>PoemAccessException</TT>.
437 *
438 * @exception org.melati.poem.NoSuchRowPoemException
439 * if there is no row in the table with the given troid
440 *
441 * @see org.melati.poem.Persistent#getTroid()
442 */
443 P getObject(Integer troid) throws NoSuchRowPoemException;
444
445 /**
446 * The object from the table with a given troid. See previous.
447 *
448 * @param troid the table row id
449 * @return the Persistent
450 * @throws org.melati.poem.NoSuchRowPoemException if not found
451 * @see #getObject(Integer)
452 */
453 Persistent getObject(int troid) throws NoSuchRowPoemException;
454
455 /**
456 * The from clause has been added as an argument because it is
457 * inextricably linked to the when clause, but the default is
458 * {@link #quotedName()}.
459 *
460 * It is the programmer's responsibility to ensure that the where clause
461 * is suitable for the target DBMS.
462 *
463 * @param fromClause Comma separated list of table names or null for default.
464 * @param whereClause SQL fragment
465 * @param orderByClause Comma separated list
466 * @param includeDeleted Flag as to whether to include soft deleted records
467 * @param excludeUnselectable Whether to append unselectable exclusion SQL
468 * TODO Should work within some kind of limit
469 * @return an SQL SELECT statement put together from the arguments and
470 * default order by clause.
471 */
472 String selectionSQL(String fromClause, String whereClause,
473 String orderByClause, boolean includeDeleted,
474 boolean excludeUnselectable);
475
476 /**
477 * It is the programmer's responsibility to ensure that the where clause
478 * is suitable for the target DBMS.
479 *
480 * @return an {@link java.util.Enumeration} of Troids satisfying the criteria.
481 */
482 Enumeration<Integer> troidSelection(String whereClause, String orderByClause,
483 boolean includeDeleted,
484 PoemTransaction transaction);
485
486 /**
487 *
488 * @see #troidSelection(String, String, boolean, org.melati.poem.PoemTransaction)
489 * @param criteria Represents selection criteria possibly on joined tables
490 * @param transaction A transaction or null for
491 * {@link org.melati.poem.PoemThread#transaction()}
492 * @return a selection of troids given arguments specifying a query
493 */
494 Enumeration<Integer> troidSelection(Persistent criteria, String orderByClause,
495 boolean includeDeleted,
496 boolean excludeUnselectable,
497 PoemTransaction transaction);
498
499 /**
500 * @param flag whether to remember or forget
501 */
502 void rememberAllTroids(boolean flag);
503
504 /**
505 * @param limit the limit to set
506 */
507 void setCacheLimit(Integer limit);
508
509 /**
510 * A <TT>SELECT</TT>ion of troids of objects from the table meeting given
511 * criteria.
512 *
513 * It is the programmer's responsibility to ensure that the where clause
514 * is suitable for the target DBMS.
515 *
516 * If the orderByClause is null, then the default order by clause is applied.
517 * If the orderByClause is an empty string, ie "", then no ordering is
518 * applied.
519 *
520 * @param whereClause an SQL snippet
521 * @param orderByClause an SQL snippet
522 * @param includeDeleted whether to include deleted records, if any
523 *
524 * @return an <TT>Enumeration</TT> of <TT>Integer</TT>s, which can be mapped
525 * onto <TT>Persistent</TT> objects using <TT>getObject</TT>;
526 * or you can just use <TT>selection</TT>
527 *
528 * @see #getObject(Integer)
529 * @see #selection(String, String, boolean)
530 */
531 Enumeration<Integer> troidSelection(String whereClause, String orderByClause,
532 boolean includeDeleted)
533 throws SQLPoemException;
534
535 /**
536 * All the objects in the table.
537 *
538 * @return An <TT>Enumeration</TT> of <TT>Persistent</TT>s, or, if the table
539 * was defined in the DSD under the name <TT><I>foo</I></TT>, of
540 * application-specialised subclasses <TT><I>Foo</I></TT>. Note
541 * that no access checks are done at this stage: you may not be able
542 * to do anything with some of the object handles in the enumeration
543 * without provoking a <TT>PoemAccessException</TT>. If the table
544 * has a <TT>deleted</TT> column, the objects flagged as deleted will
545 * be passed over.
546 * @see Selectable#selection()
547 */
548 Enumeration<P> selection() throws SQLPoemException;
549
550 /**
551 * A <TT>SELECT</TT>ion of objects from the table meeting given criteria.
552 * This is one way to run a search against the database and return the
553 * results as a series of typed POEM objects.
554 *
555 * It is the programmer's responsibility to ensure that the where clause
556 * is suitable for the target DBMS.
557 *
558 * @param whereClause SQL <TT>SELECT</TT>ion criteria for the search:
559 * the part that should appear after the
560 * <TT>WHERE</TT> keyword
561 *
562 * @return An <TT>Enumeration</TT> of <TT>Persistent</TT>s, or, if the table
563 * was defined in the DSD under the name <TT><I>foo</I></TT>, of
564 * application-specialised subclasses <TT><I>Foo</I></TT>. Note
565 * that no access checks are done at this stage: you may not be able
566 * to do anything with some of the object handles in the enumeration
567 * without provoking a <TT>PoemAccessException</TT>. If the table
568 * has a <TT>deleted</TT> column, the objects flagged as deleted will
569 * be passed over.
570 *
571 * @see org.melati.poem.Column#selectionWhereEq(Object)
572 */
573 Enumeration<P> selection(String whereClause)
574 throws SQLPoemException;
575
576 /**
577 * Get an object satisfying the where clause.
578 * It is the programmer's responsibility to use this in a
579 * context where only one result will be found, if more than one
580 * actually exist only the first will be returned.
581 *
582 * It is the programmer's responsibility to ensure that the where clause
583 * is suitable for the target DBMS.
584 *
585 * @param whereClause SQL <TT>SELECT</TT>ion criteria for the search:
586 * the part that should appear after the
587 * <TT>WHERE</TT> keyword
588 * @return the first item satisfying criteria
589 */
590 Persistent firstSelection(String whereClause);
591
592 /**
593 * A <TT>SELECT</TT>ion of objects from the table meeting given criteria,
594 * possibly including those flagged as deleted.
595 *
596 * If the orderByClause is null, then the default order by clause is applied.
597 * If the orderByClause is an empty string, ie "", then no ordering is
598 * applied.
599 *
600 * It is the programmer's responsibility to ensure that the where clause
601 * is suitable for the target DBMS.
602 *
603 * @param includeDeleted whether to return objects flagged as deleted
604 * (ignored if the table doesn't have a
605 * <TT>deleted</TT> column)
606 * @return a ResultSet as an Enumeration
607 * @see #selection(String)
608 */
609 Enumeration<P> selection(String whereClause, String orderByClause,
610 boolean includeDeleted)
611 throws SQLPoemException;
612
613 /**
614 * Return a selection of rows given an exemplar.
615 *
616 * @param criteria Represents selection criteria possibly on joined tables
617 * @return an enumeration of like objects
618 * @see #selection(String, String, boolean)
619 */
620 Enumeration<P> selection(Persistent criteria)
621 throws SQLPoemException;
622
623 /**
624 * Return a selection of rows given arguments specifying a query.
625 *
626 * @see #selection(String, String, boolean)
627 * @param criteria Represents selection criteria possibly on joined tables
628 * @param orderByClause Comma separated list
629 * @return an enumeration of like objects with the specified ordering
630 */
631 Enumeration<P> selection(Persistent criteria, String orderByClause)
632 throws SQLPoemException;
633
634 /**
635 * Return a selection of rows given arguments specifying a query.
636 *
637 * @see #selection(String, String, boolean)
638 * @param criteria Represents selection criteria possibly on joined tables
639 * @param orderByClause Comma separated list
640 * @param excludeUnselectable Whether to append unselectable exclusion SQL
641 * @return an enumeration of like Persistents
642 */
643 Enumeration<P> selection(Persistent criteria, String orderByClause,
644 boolean includeDeleted, boolean excludeUnselectable)
645 throws SQLPoemException;
646
647
648 /**
649 * @param whereClause the SQL fragment to count the results of
650 * @return the SQL string for the current SQL dialect
651 */
652 String countSQL(String whereClause);
653
654 /**
655 * Return an SQL statement to count rows put together from the arguments.
656 *
657 * It is the programmer's responsibility to ensure that the where clause
658 * is suitable for the target DBMS.
659 *
660 * @param fromClause Comma separated list of table names
661 * @return the SQL query
662 */
663 String countSQL(String fromClause, String whereClause,
664 boolean includeDeleted, boolean excludeUnselectable);
665
666 /**
667 * It is the programmer's responsibility to ensure that the where clause
668 * is suitable for the target DBMS.
669 *
670 * @return the number records satisfying criteria.
671 */
672 int count(String whereClause,
673 boolean includeDeleted, boolean excludeUnselectable)
674 throws SQLPoemException;
675
676 /**
677 * It is the programmer's responsibility to ensure that the where clause
678 * is suitable for the target DBMS.
679 *
680 * @return the number records satisfying criteria.
681 */
682 int count(String whereClause, boolean includeDeleted)
683 throws SQLPoemException;
684
685 /**
686 * It is the programmer's responsibility to ensure that the where clause
687 * is suitable for the target DBMS.
688 *
689 * @return the number of records satisfying criteria.
690 */
691 int count(String whereClause)
692 throws SQLPoemException;
693
694 /**
695 * @return the number of records in this table.
696 */
697 int count()
698 throws SQLPoemException;
699
700 /**
701 * It is the programmer's responsibility to ensure that the where clause
702 * is suitable for the target DBMS.
703 *
704 * @param whereClause the SQL criteria
705 * @return whether any records satisfy criteria.
706 */
707 boolean exists(String whereClause) throws SQLPoemException;
708
709 /**
710 * @param persistent a {@link org.melati.poem.Persistent} with some fields filled in
711 * @return whether any records exist with the same fields filled
712 */
713 boolean exists(Persistent persistent);
714
715 /**
716 * Append an SQL logical expression to the given buffer to match rows
717 * according to criteria represented by the given object.
718 * <p>
719 * This default selects rows for which the non-null fields in the
720 * given object match, but subtypes may add other criteria.
721 * <p>
722 * The column names are now qualified with the table name so that
723 * subtypes can append elements of a join but there is no filtering
724 * by canselect columns.
725 *
726 * TODO Add mechanism for searching for Nulls (that would be query
727 * constructs as per SQL parse tree, but efferent not afferent)
728 *
729 * @see #notifyColumnInfo(org.melati.poem.ColumnInfo)
730 * @see #clearColumnInfoCaches()
731 */
732 void appendWhereClause(StringBuffer clause, Persistent persistent);
733
734 /**
735 * Return an SQL WHERE clause to select rows that match the non-null
736 * fields of the given object.
737 * <p>
738 * This does not filter out any rows with a capability the user
739 * does not have in a canselect column, nor did it ever filter
740 * out rows deleted according to a "deleted" column.
741 * But the caller usually gets a second chance to do both.
742 * @return an SQL fragment
743 */
744 String whereClause(Persistent criteria);
745
746 /**
747 * Return an SQL WHERE clause to select rows using the given object
748 * as a selection criteria and optionally deleted rows or those
749 * included rows the user is not capable of selecting.
750 * <p>
751 * This is currently implemented in terms of
752 * {@link org.melati.poem.Table#appendWhereClause(StringBuffer, org.melati.poem.Persistent)}.
753 * @return an SQL fragment
754 */
755 String whereClause(Persistent criteria,
756 boolean includeDeleted, boolean excludeUnselectable);
757
758 /**
759 * @return an SQL fragment
760 * @see #cnfWhereClause(java.util.Enumeration, boolean, boolean)
761 * @see #whereClause(org.melati.poem.Persistent)
762 */
763 String cnfWhereClause(Enumeration<P> persistents);
764
765 /**
766 * Return a Conjunctive Normal Form (CNF) where clause.
767 * See http://en.wikipedia.org/wiki/Conjunctive_normal_form.
768 *
769 * @return an SQL fragment
770 */
771 String cnfWhereClause(Enumeration<P> persistents,
772 boolean includeDeleted, boolean excludeUnselectable);
773
774 /**
775 * All the objects in the table which refer to a given object. If none of
776 * the table's columns are reference columns, the <TT>Enumeration</TT>
777 * returned will obviously be empty.
778 * <p>
779 * It is not guaranteed to be quick to execute!
780 *
781 * @return an <TT>Enumeration</TT> of <TT>Persistent</TT>s
782 */
783
784 Enumeration<P> referencesTo(Persistent object);
785
786 /**
787 * All the columns in the table which refer to the given table.
788 *
789 * @param table the table to count the references within
790 * @return an Enumeration of Columns referring to the specified Table
791 */
792 Enumeration<Column<?>> referencesTo(Table<?> table);
793
794 /**
795 * @return the current highest troid
796 */
797 int getMostRecentTroid();
798
799 /**
800 * @param persistent unused parameter, but might be needed in another troid schema
801 * @return the next Troid
802 */
803 Integer troidFor(Persistent persistent);
804
805 /**
806 * Write a new row containing the given object.
807 * <p>
808 * The given object will be assigned the next troid and its internal
809 * state will also be modified.
810 *
811 * @exception org.melati.poem.InitialisationPoemException The object failed validation
812 * (currently one of its field values failed).
813 */
814 void create(Persistent p)
815 throws AccessPoemException, ValidationPoemException,
816 InitialisationPoemException;
817
818 /**
819 * Create a new object (record) in the table.
820 *
821 * @param initialiser A piece of code for setting the new object's
822 * initial values. You'll probably want to define
823 * it as an anonymous class.
824 *
825 * @return A <TT>Persistent</TT> representing the new object, or, if the
826 * table was defined in the DSD under the name <TT><I>foo</I></TT>,
827 * an application-specialised subclass <TT><I>Foo</I></TT> of
828 * <TT>Persistent</TT>.
829 *
830 * @exception org.melati.poem.AccessPoemException
831 * if <TT>initialiser</TT> provokes one during its work (which
832 * is unlikely, since POEM's standard checks are disabled
833 * while it runs)
834 * @exception org.melati.poem.ValidationPoemException
835 * if <TT>initialiser</TT> provokes one during its work
836 * @exception org.melati.poem.InitialisationPoemException
837 * if the object is left by <TT>initialiser</TT> in a state in
838 * which not all of its fields have legal values, or in which
839 * the calling thread would not be allowed write access to the
840 * object under its <TT>AccessToken</TT>---<I>i.e.</I> you
841 * can't create objects you wouldn't be allowed to write to.
842 *
843 * @see org.melati.poem.Initialiser#init(Persistent)
844 * @see org.melati.poem.PoemThread#accessToken()
845 * @see #getCanCreate()
846 */
847 Persistent create(Initialiser initialiser)
848 throws AccessPoemException, ValidationPoemException,
849 InitialisationPoemException;
850
851 /**
852 * @return A freshly minted floating <TT>Persistent</TT> object for this table,
853 * ie one without a troid set
854 */
855 Persistent newPersistent();
856
857 /**
858 * It is the programmer's responsibility to ensure that the where clause
859 * is suitable for the target DBMS.
860 *
861 * @param whereClause the criteria
862 */
863 void delete_unsafe(String whereClause);
864
865 /**
866 * The number of `extra' (non-DSD-defined) columns in the table.
867 */
868 int extrasCount();
869
870 /**
871 * The capability required for reading records from the table, unless
872 * overridden in the record itself. This simply comes from the table's
873 * record in the <TT>tableinfo</TT> table.
874 *
875 * @return the capability needed to read this table
876 */
877 Capability getDefaultCanRead();
878
879 /**
880 * The capability required for updating records in the table, unless
881 * overridden in the record itself. This simply comes from the table's
882 * record in the <TT>tableinfo</TT> table.
883 *
884 * @return the default {@link org.melati.poem.Capability} required to write a
885 * {@link org.melati.poem.Persistent}, if any
886 */
887 Capability getDefaultCanWrite();
888
889 /**
890 * The capability required for deleting records in the table, unless
891 * overridden in the record itself. This simply comes from the table's
892 * record in the <TT>tableinfo</TT> table.
893 * @return the default {@link org.melati.poem.Capability} required to delete a
894 * {@link org.melati.poem.Persistent}, if any
895 */
896 Capability getDefaultCanDelete();
897
898 /**
899 * The capability required for creating records in the table. This simply
900 * comes from the table's record in the <TT>tableinfo</TT> table.
901 *
902 * @return the Capability required to write to this table
903 * @see #create(Initialiser)
904 */
905 Capability getCanCreate();
906
907 /**
908 * @return the canReadColumn or the canSelectColumn or null
909 */
910 Column<Capability> canReadColumn();
911
912 /**
913 * @return the canSelectColumn or null
914 */
915 Column<Capability> canSelectColumn();
916
917 /**
918 * @return the canWriteColumn or null
919 */
920 Column<Capability> canWriteColumn();
921
922 /**
923 * @return the canDeleteColumn or null
924 */
925 Column<Capability> canDeleteColumn();
926
927 /**
928 * Add a {@link org.melati.poem.Column} to the database and the {@link org.melati.poem.TableInfo} table.
929 *
930 * @param infoP the meta data about the {@link org.melati.poem.Column}
931 * @return the newly added column
932 */
933 Column<?> addColumnAndCommit(ColumnInfo infoP) throws PoemException;
934
935 /**
936 * @param columnInfo metadata about the column to delete, which is itself deleted
937 */
938 void deleteColumnAndCommit(ColumnInfo columnInfo) throws PoemException;
939
940 /**
941 * A concise string to stand in for the table. The table's name and a
942 * description of where it was defined (the DSD, the metadata tables or the
943 * JDBC metadata).
944 * {@inheritDoc}
945 * @see Object#toString()
946 */
947 String toString();
948
949 /**
950 * Print some diagnostic information about the contents and consistency of
951 * POEM's cache for this table to stderr.
952 */
953 void dumpCacheAnalysis();
954
955 /**
956 * Print information about the structure of the table to stdout.
957 */
958 void dump();
959
960 /**
961 * Print information to PrintStream.
962 *
963 * @param ps PrintStream to dump to
964 */
965 void dump(PrintStream ps);
966
967 /**
968 * A mechanism for caching a selection of records.
969 *
970 * It is the programmer's responsibility to ensure that the where clause
971 * is suitable for the target DBMS.
972 *
973 * @param whereClause raw SQL selection clause appropriate for this DBMS
974 * @param orderByClause which field to order by or null
975 * @return the results
976 */
977 CachedSelection<P> cachedSelection(String whereClause,
978 String orderByClause);
979
980 /**
981 * A mechanism for caching a record count.
982 *
983 * It is the programmer's responsibility to ensure that the where clause
984 * is suitable for the target DBMS.
985 *
986 * @param whereClause raw SQL selection clause appropriate for this DBMS
987 * @param includeDeleted whether to include soft deleted records
988 * @return a cached count
989 */
990 CachedCount cachedCount(String whereClause, boolean includeDeleted);
991
992 /**
993 * A mechanism for caching a record count.
994 *
995 * It is the programmer's responsibility to ensure that the where clause
996 * is suitable for the target DBMS.
997 *
998 * @param whereClause raw SQL selection clause appropriate for this DBMS
999 * @param includeDeleted whether to include soft deleted records
1000 * @param excludeUnselectable whether to exclude columns which cannot be selected
1001 * @return a cached count
1002 */
1003 CachedCount cachedCount(String whereClause, boolean includeDeleted,
1004 boolean excludeUnselectable);
1005
1006 /**
1007 * A mechanism for caching a record count.
1008 *
1009 * @param criteria a {@link org.melati.poem.Persistent} with selection fields filled
1010 * @param includeDeleted whether to include soft deleted records
1011 * @param excludeUnselectable whether to exclude columns which cannot be selected
1012 * @return a cached count
1013 */
1014 CachedCount cachedCount(Persistent criteria, boolean includeDeleted,
1015 boolean excludeUnselectable);
1016
1017 /**
1018 * @param criteria a Persistent to extract where clause from
1019 * @return a CachedCount of records matching Criteria
1020 */
1021 CachedCount cachedCount(Persistent criteria);
1022
1023 /**
1024 * A mechanism for caching a record count.
1025 *
1026 * It is the programmer's responsibility to ensure that the where clause
1027 * is suitable for the target DBMS.
1028 *
1029 * @param whereClause raw SQL selection clause appropriate for this DBMS
1030 * @return a cached count
1031 */
1032 CachedCount cachedCount(String whereClause);
1033
1034 /**
1035 * @return a cached count of all records in the table,
1036 * obeying includedDeleted and other exclusions
1037 */
1038 CachedCount cachedCount();
1039
1040 /**
1041 * A mechanism for caching an existance.
1042 *
1043 * It is the programmer's responsibility to ensure that the where clause
1044 * is suitable for the target DBMS.
1045 *
1046 * NOTE It is possible for the count to be written simultaneously,
1047 * but the cache will end up with the same result.
1048 *
1049 * @param whereClause raw SQL selection clause appropriate for this DBMS
1050 * @return a cached exists
1051 */
1052 CachedExists cachedExists(String whereClause);
1053
1054 /**
1055 * A mechanism for caching a record count.
1056 *
1057 * It is the programmer's responsibility to ensure that the where clause
1058 * is suitable for the target DBMS.
1059 *
1060 * @param whereClause raw SQL selection clause appropriate for this DBMS
1061 * @param orderByClause raw SQL order clause appropriate for this DBMS
1062 * @param nullable whether the ReferencePoemType is nullable
1063 * @return a {@link org.melati.poem.RestrictedReferencePoemType}
1064 */
1065 RestrictedReferencePoemType<?> cachedSelectionType(String whereClause,
1066 String orderByClause, boolean nullable);
1067
1068 /**
1069 * Make up a <TT>Field</TT> object whose possible values are a selected
1070 * subset of the records in the table. You can make a "dropdown" offering a
1071 * choice of your green customers by putting this in your handler
1072 *
1073 * <BLOCKQUOTE><PRE>
1074 * context.put("greens",
1075 * melati.getDatabase().getCustomerTable().cachedSelectionField(
1076 * "colour = 'green'", null, true, null, "greens"));
1077 * </PRE></BLOCKQUOTE>
1078 *
1079 * and this in your template
1080 *
1081 * <BLOCKQUOTE><PRE>
1082 * Select a customer: $ml.input($greens)
1083 * </PRE></BLOCKQUOTE>
1084 *
1085 * The list of member records is implicitly cached---permanently, and however
1086 * big it turns out to be. So don't go mad with this. It is recomputed on
1087 * demand if the contents of the table are changed. The <TT>whereClause</TT>
1088 * and <TT>orderByClause</TT> you pass in are checked to see if you have
1089 * asked for the same list before, so however many times you call this
1090 * method, you should only trigger actual <TT>SELECT</TT>s when the table
1091 * contents have changed. The list is also transaction-safe, in that it will
1092 * always reflect the state of affairs within your transaction even if you
1093 * haven't done a commit.
1094 *
1095 * It is the programmer's responsibility to ensure that the where clause
1096 * is suitable for the target DBMS.
1097 *
1098 * @param whereClause an SQL expression (the bit after the
1099 * <TT>SELECT</TT> ... <TT>WHERE</TT>) for picking
1100 * out the records you want
1101 *
1102 * @param orderByClause a comma-separated list of column names which
1103 * determine the order in which the records are
1104 * presented; if this is <TT>null</TT>, the
1105 * <TT>displayorderpriority</TT> attributes of the
1106 * table's columns determine the order
1107 *
1108 * @param nullable whether to allow a blank <TT>NULL</TT> option
1109 * as the first possibility
1110 *
1111 * @param selectedTroid the troid of the record to which the
1112 * <TT>SELECT</TT> field should initially be set
1113 *
1114 * @param nameP the HTML name attribute of the field,
1115 * <I>i.e.</I>
1116 * <TT><SELECT NAME=<I>name</I>></TT>
1117 * @return a Field object
1118 */
1119 Field<?> cachedSelectionField(
1120 String whereClause, String orderByClause, boolean nullable,
1121 Integer selectedTroid, String nameP);
1122
1123 /**
1124 * Don't call this in your application code.
1125 * Columns should be defined either in the DSD (in which
1126 * case the boilerplate code generated by the preprocessor will call this
1127 * method) or directly in the RDBMS (in which case the initialisation code
1128 * will).
1129 */
1130 void defineColumn(Column<?> column)
1131 throws DuplicateColumnNamePoemException,
1132 DuplicateTroidColumnPoemException,
1133 DuplicateDeletedColumnPoemException;
1134
1135 /**
1136 * @return incremented extra columns index
1137 */
1138 int getNextExtrasIndex();
1139
1140 /**
1141 * @param tableInfo the TableInfo to set
1142 */
1143 void setTableInfo(TableInfo tableInfo);
1144
1145 /**
1146 * @return the {@link org.melati.poem.TableInfo} for this table.
1147 */
1148 TableInfo getTableInfo();
1149
1150 /**
1151 * @return a DBMS table type eg TEXT
1152 */
1153 String getDbmsTableType();
1154
1155
1156 /**
1157 * Match columnInfo with this Table's columns.
1158 * Conversely, create a ColumnInfo for any columns which don't have one.
1159 */
1160 void unifyWithColumnInfo() throws PoemException;
1161
1162 /** Unify SQL REMARKS with table.description.
1163 *
1164 * @param tableDescriptions a JDBC {@link java.sql.ResultSet} with cursor at current row
1165 */
1166 void unifyWithMetadata(ResultSet tableDescriptions) throws SQLException;
1167
1168 /**
1169 * Unify the JDBC description of this tables columns with the
1170 * meta data held in the {@link org.melati.poem.TableInfo}
1171 *
1172 * @param colDescs a JDBC {@link java.sql.ResultSet} describing the columns with cursor at current row
1173 * @param primaryKey name of primary key column
1174 */
1175 void unifyWithDB(ResultSet colDescs, String primaryKey)
1176 throws PoemException;
1177
1178 String defaultDisplayName();
1179
1180 String defaultDescription();
1181
1182 int defaultDisplayOrder();
1183
1184 Integer defaultCacheLimit();
1185
1186 boolean defaultRememberAllTroids();
1187
1188 String defaultCategory();
1189
1190
1191 }