Joinable.java
/*
** Module : Joinable.java
** Abstract : Interface for query types which can be added as components to CompoundQuery
**
** Copyright (c) 2004-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------Description-----------------------------
** 001 ECF 20051113 @23385 Created initial version. Query types which
** can be added as components to CompoundQuery
** must implement this interface.
** 002 ECF 20051214 @23749 Added support for scrolling queries. Added
** several methods and extend the new Scrollable
** base interface.
** 003 ECF 20060106 @23797 Removed record retrieval methods. Methods
** first, last, next, previous, unique, and
** current are now defined higher up in this
** interface hierarchy.
** 004 ECF 20060216 @24719 Added client-side where clause support. Added
** setResults method to allow CompoundQuery to
** set a final results list into a component.
** Added resolveArgs parameter to reset method
** to allow conditional substitution parameter
** resolution.
** 005 ECF 20070504 @33408 Changed load() signature to return boolean.
** 006 ECF 20070518 @33681 Added getRecordBuffers(). Must return an
** array of RecordBuffer instances used by this
** query.
** 007 ECF 20080112 @37000 Removed restriction of dealing only with IDs.
** This interface now handles both DMO instances
** and primary key IDs.
** 008 ECF 20081105 @40310 Added registerRecordChangeListeners(). Used
** by CompoundQuery to ensure change listeners
** are registered with the change broker at the
** appropriate scope.
** 009 ECF 20090312 @42983 Removed getTableCount(). This method has moved to
** the P2JQuery interface.
** 010 ECF 20090703 @43052 API change. Modified load() signature.
** 011 ECF 20131028 Import change.
** 012 ECF 20150802 Added methods required for compound query optimization.
** 013 SVL 20160608 Added silentIfNullId parameter to load() function.
** 014 ECF 20160620 Fixed javadoc and copyright.
** 015 ECF 20160727 Added getReferencedBuffers.
** 016 ECF 20180206 Cleaned up inheritance hierarchy.
** 017 OM 20180220 Added outer-join attribute.
** 018 OM 20181023 Added external buffers when making the adaptive server join
** components.
** 019 CA 20221130 Refactored the WHERE clause translation (when the bound and definition buffers
** are not the same), to be aware of the external buffers (i.e. added for CAN-FIND
** sub-select clauses). The translate will be performed before the query is being
** executed.
** 020 CA 20240422 Allow the query to be reset to its initialization state, so the same instance can
** be used to execute child buffer FILL operations.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.persist;
import java.util.*;
import com.goldencode.p2j.persist.lock.*;
/**
* Query types which can be added as components to <code>CompoundQuery</code>
* must implement this interface. It defines methods which will be called by
* the enclosing, compound query object, which retrieve records and update
* the state of the implementing query and its buffer(s).
*/
interface Joinable
extends Scrollable
{
/**
* Clear the current results from the query, so the same query instance can be executed again, without
* having to {@link #open() re-open} it.
*/
@Override
default void clearResults()
{
reset(true, true);
}
/**
* Sets the left-outer-join property for this query.
*
* @param outer
* {@code true} iif this is a left outer join component of the query.
*/
public void setOuter(boolean outer);
/**
* Set a mode on the underlying buffer(s) such that setting a null record
* into a buffer may or may not result in an error condition. This applies
* only to <code>FIRST</code>, <code>LAST</code>, and <code>UNIQUE</code>
* iteration types.
*
* @param errorIfNull
* If <code>true</code>, setting a <code>null</code> value as the
* current record in an underlying buffer will raise an error
* condition (if not in silent error mode); if <code>false</code>,
* this action will raise an end condition instead.
*/
public void setErrorIfNull(boolean errorIfNull);
/**
* Force the query to retrieve full records, rather than primary keys only.
*/
public void setFullRecords();
/**
* Set each buffer backing the query to unknown mode.
*
* @see RecordBuffer#setUnknownMode()
*/
public void setUnknownRecord();
/**
* Reset the query by clearing its state to a known default. This is
* used to ensure that subsequent requests for FIRST and LAST record
* retrievals operate on a known query/buffer state.
*
* @param resolveArgs
* <code>true</code> if query substitution arguments should be
* resolved as part of the reset; <code>false</code> if existing
* argument values should be used for the next query execution.
* @param forceOrigArgs
* Flag indicating that the original arguments used at the construction of the query must be
* re-calculated.
*/
public void reset(boolean resolveArgs, boolean forceOrigArgs);
/**
* Get an array of all record buffers referenced by this query, including those directly
* involved in the query, as well as those (if any) indirectly referenced by inlined,
* converted, CAN-FIND expressions.
*
* @return All record buffers referenced by this query.
*/
public RecordBuffer[] getReferencedBuffers();
/**
* Load one or more records into their associated buffers, given an array
* of primary key ID values, or the actual DMOs themselves. The IDs/DMOs
* are arranged to coincide with the tables underlying the query, from
* left-most to right-most (in the sense of how they are joined by the
* query).
* <p>
* The contract of this method is that if an implementor cannot load the
* expected value (e.g., the record has been deleted or is otherwise no
* longer available), it must throw {@link MissingRecordException}, after
* setting the associated buffer into {@link RecordBuffer#setUnknownMode()
* unknown mode}. Note that a record being locked by another session does
* not constitute a "missing" record. Note also that this exception must
* not be thrown until all the elements of <code>data</code> have been
* processed to the extent possible.
*
* @param data
* Array of primary key IDs or DMOs, one per table involved in the
* query.
* @param lockType
* Lock type which should override that of the query. Set to
* <code>null</code> to allow query to use its current lock type.
* @param silentIfNullId
* If <code>true</code>, do not raise {@link MissingRecordException}
* if some of the provided IDs are <code>null</code>. <code>null</code>
* IDs are valid for queries with OUTER join.
*
* @throws MissingRecordException
* if any record cannot be loaded, because it is no longer
* available (e.g., deleted, etc.).
* @throws PersistenceException
* if there is an error loading data.
*
* @see #getRow()
*/
public void load(Object[] data, LockType lockType, boolean silentIfNullId)
throws MissingRecordException,
PersistenceException;
/**
* Set the given results object into this query.
*
* @param results
* New result set for this query.
*/
public void setResults(Results results);
/**
* Assemble an array of primary key IDs or DMOs for the current record(s)
* in the buffers underlying this query, from left-most to right-most (in
* the sense of how the query joins the associated tables). This method
* essentially takes a lightweight snapshot of the currently loaded
* record(s), so that this may be restored later.
*
* @return Array of primary key IDs, one per table involved in the query.
*
* @see #load(Object[], LockType, boolean)
*/
public Object[] getRow();
/**
* Fetch the array of primary key IDs associated with the first result in
* this query's result list.
*
* @return Array of record IDs reflecting the first query result, or
* <code>null</code> if there is no such result.
*/
public Object[] peekFirst();
/**
* Fetch the array of primary key IDs associated with the last result in
* this query's result list.
*
* @return Array of record IDs reflecting the last query result, or
* <code>null</code> if there is no such result.
*/
public Object[] peekLast();
/**
* Check if this type of query should register record change listeners. Use this
* to avoid computing any scope for registration and end up with a no registration
* behavior.
*
* @return {@code true} if we should invest time into computing the scope in order
* to call {@link #registerRecordChangeListeners} or {@code false} if we
* can skip doing any work to honor {@link #registerRecordChangeListeners}.
*/
public default boolean shouldRegisterRecordChangeListeners()
{
return true;
}
/**
* Register all <code>RecordChangeListener</code>s associated with this
* query (if any), with the context-local <code>ChangeBroker</code> at the
* indicated scope.
*
* @param scope
* Scope at which listeners should be registered with the change
* broker.
*/
public void registerRecordChangeListeners(Integer scope);
/**
* Create an adaptive query component based on the information in this query (which is
* presumed to be a single-table query), and given a list of adaptive query components which
* represent outer, nested query loops, which will perform a server-side join to the
* innermost, nested query component.
*
* @param joinList
* List of adaptive components representing nested query loops which will contain
* the adaptive query component returned by this method. The last component in the
* list represents the nested query loop immediately containing the returned query
* component, with which the join will be made.
* @param query
* Adaptive query which will manage the server-side join of <code>joinList</code> and
* the returned query component.
* @param iteration
* Iteration type: FIRST, LAST, or NEXT.
* @param outer
* <code>true</code> if the join should be a left outer join. This type of join is
* not supported at the time of this writing, so this parameter should always be
* <code>false</code>. It is here to support a planned, future enhancement.
* @param fallback
* A compound query component to use in the event the multi-table adaptive query
* switches from preselect to dynamic retrieval mode.
*
* @return An adaptive query component suitable for a server-side join, based on the
* information in this query.
*/
public AdaptiveComponent makeAdaptiveServerJoinComponent(List<AdaptiveComponent> joinList,
AdaptiveQuery query,
int iteration,
boolean outer,
CompoundComponent fallback);
/**
* Create a preselect query component based on the information in this query (which is
* presumed to be a single-table query), and given a list of preselect query components which
* represent outer, nested query loops, which will perform a server-side join to the
* innermost, nested query component.
*
* @param joinList
* List of preselect components representing nested query loops which will contain
* the preselect query component returned by this method. The last component in the
* list represents the nested query loop immediately containing the returned query
* component, with which the join will be made.
* @param iteration
* Iteration type: FIRST, LAST, or NEXT.
* @param outer
* <code>true</code> if the join should be a left outer join. This type of join is
* not supported at the time of this writing, so this parameter should always be
* <code>false</code>. It is here to support a planned, future enhancement.
*
* @return A preselect query component suitable for a server-side join, based on the
* information in this query.
*/
public QueryComponent makePreselectServerJoinComponent(List<QueryComponent> joinList,
int iteration,
boolean outer);
/**
* Indicate whether this query has a client-side where clause expression associated with it.
*
* @return <code>true</code> if there is a where expression; else <code>false</code>.
*/
public boolean hasWhereExpression();
/**
* Get the query substitution arguments associated with this query, if any.
*
* @return Substitution arguments, in order, or <code>null</code> if there are none.
*/
public Object[] getArgs();
/**
* Get the original, HQL where clause associated with this query.
*
* @return Original where clause, or <code>null</code> if there is none.
*/
public String getOriginalWhere();
/**
* Force this query to operate in dynamic retrieval mode, if it supports this mode.
*/
public void forceDynamicOperation();
/**
* Get the sort phrase associated with this query.
*
* @return Sort phrase.
*/
public String getSortPhrase();
/**
* Get the external buffers, if any, associated with this query.
*
* @return Array of external buffers or {@code null}.
*/
public RecordBuffer[] getExternalBuffers();
/**
* Translate the WHERE clause.
*/
public void translateWhere();
}