Add more examples of joins

This commit is contained in:
2025-02-10 09:20:29 -06:00
parent 74e755b111
commit c53f9b8fc9

View File

@ -155,9 +155,9 @@ new QFilterOrderBy()
---- ----
==== QueryJoin ==== QueryJoin
* `joinTable` - *String, required* - Name of the table that is being joined in to the existing query. * `joinTable` - *String, required (though inferrable)* - Name of the table that is being joined in to the existing query.
** Will be inferred from *joinMetaData*, if *joinTable* is not set when *joinMetaData* gets set. ** Will be inferred from *joinMetaData*, if *joinTable* is not set when *joinMetaData* gets set.
* `baseTableOrAlias` - *String, required* - Name of a table (or an alias) already defined in the query, to which the *joinTable* will be joined. * `baseTableOrAlias` - *String, required (though inferrable)* - Name of a table (or an alias) already defined in the query, to which the *joinTable* will be joined.
** Will be inferred from *joinMetaData*, if *baseTableOrAlias* is not set when *joinMetaData* gets set (which will only use the leftTableName from the joinMetaData - never an alias). ** Will be inferred from *joinMetaData*, if *baseTableOrAlias* is not set when *joinMetaData* gets set (which will only use the leftTableName from the joinMetaData - never an alias).
* `joinMetaData` - *QJoinMetaData object* - Optional specification of a {link-join} in the current QInstance. * `joinMetaData` - *QJoinMetaData object* - Optional specification of a {link-join} in the current QInstance.
If not set, will be looked up at runtime based on *baseTableOrAlias* and *joinTable*. If not set, will be looked up at runtime based on *baseTableOrAlias* and *joinTable*.
@ -165,21 +165,78 @@ If not set, will be looked up at runtime based on *baseTableOrAlias* and *joinTa
* `alias` - *String* - Optional (unless multiple instances of the same table are being joined together, when it becomes required). * `alias` - *String* - Optional (unless multiple instances of the same table are being joined together, when it becomes required).
Behavior based on SQL `FROM` clause aliases. Behavior based on SQL `FROM` clause aliases.
If given, must be used as the part before the dot in field name specifications throughout the rest of the query input. If given, must be used as the part before the dot in field name specifications throughout the rest of the query input.
* `select` - *boolean, default: false* - Specify whether fields from the *rightTable* should be selected by the query. * `select` - *boolean, default: false* - Specify whether fields from the *joinTable* should be selected by the query.
If *true*, then the `QRecord` objects returned by this query will have values with corresponding to the (table-or-alias `.` field-name) form. If *true*, then the `QRecord` objects returned by this query will have values with corresponding to the (table-or-alias `.` field-name) form.
* `type` - *Enum of INNER, LEFT, RIGHT, FULL, default: INNER* - specifies the SQL-style type of join being performed. * `type` - *Enum of INNER, LEFT, RIGHT, FULL, default: INNER* - specifies the SQL-style type of join being performed.
[source,java] [source,java]
.QueryJoin definition examples: .Basic QueryJoin usage example:
---- ----
// selecting from an "orderLine" table - then join to its corresponding "order" table // selecting from an "orderLine" table, joined to its corresponding (parent) "order" table
queryInput.withTableName("orderLine"); queryInput.withTableName("orderLine");
queryInput.withQueryJoin(new QueryJoin("order").withSelect(true)); queryInput.withQueryJoin(new QueryJoin("order").withSelect(true));
... ...
queryOutput.getRecords().get(0).getValueBigDecimal("order.grandTotal"); queryOutput.getRecords().get(0).getValueBigDecimal("order.grandTotal");
----
[source,java]
."V" shaped query - selecting from one parent table, and two children joined to it:
----
// TODO this needs verified for accuracy, though is a reasonable starting point as-is
// selecting from an "order" table, and two children of it, orderLine and customer
queryInput.withTableName("order");
queryInput.withQueryJoin(new QueryJoin("orderLine").withSelect(true));
queryInput.withQueryJoin(new QueryJoin("customer").withSelect(true));
...
QRecord joinedRecord = queryOutput.getRecords().get(0);
joinedRecord.getValueString("orderNo");
joinedRecord.getValueString("orderLine.sku");
joinedRecord.getValueString("customer.firstName");
----
[source,java]
."Chain" shaped query - selecting from one parent table, a child table, and a grandchild:
----
// TODO this needs verified for accuracy, though is a reasonable starting point as-is
// selecting from an "order" table, with a "customer" child table, and an "address" sub-table
queryInput.withTableName("order");
queryInput.withQueryJoin(new QueryJoin("customer").withSelect(true));
queryInput.withQueryJoin(new QueryJoin("address").withSelect(true));
...
QRecord joinedRecord = queryOutput.getRecords().get(0);
joinedRecord.getValueString("orderNo");
joinedRecord.getValueString("customer.firstName");
joinedRecord.getValueString("address.street1");
----
[source,java]
.QueryJoin usage example where two tables have two different joins between them:
----
// TODO this needs verified for accuracy, though is a reasonable starting point as-is
// here there's a "fulfillmentPlan" table, which points at the order table (many-to-one,
// as an order's plan can change over time, and we keep old plans around).
// This join is named: fulfillmentPlanJoinOrder
//
// The other join is "order" pointing at its current "fulfillmentPlan"
// This join is named: orderJoinCurrentFulfillmentPlan
// to select an order along with its current fulfillment plan:
queryInput.withTableName("order");
queryInput.withQueryJoin(new QueryJoin(instance.getJoin("orderJoinCurrentFulfillmentPlan"))
.withSelect(true));
// to select an order, and all fulfillment plans for an order (1 or more records):
queryInput.withTableName("order");
queryInput.withQueryJoin(new QueryJoin(instance.getJoin("fulfillmentPlanJoinOrder"))
.withSelect(true));
----
[source,java]
.QueryJoin usage example for table with two joins to the same child table, selecting from both:
----
// given an "order" table with 2 foreign keys to a customer table (billToCustomerId and shipToCustomerId) // given an "order" table with 2 foreign keys to a customer table (billToCustomerId and shipToCustomerId)
// Note, we must supply the JoinMetaData to the QueryJoin, to drive what fields to join on in each case. // Note, we must supply the JoinMetaData to the QueryJoin, to drive what fields to join on in each case.
// we must also define an alias for each of the QueryJoins
queryInput.withTableName("order"); queryInput.withTableName("order");
queryInput.withQueryJoins(List.of( queryInput.withQueryJoins(List.of(
new QueryJoin(instance.getJoin("orderJoinShipToCustomer") new QueryJoin(instance.getJoin("orderJoinShipToCustomer")
@ -190,11 +247,18 @@ queryInput.withQueryJoins(List.of(
.withSelect(true)))); .withSelect(true))));
... ...
record.getValueString("billToCustomer.firstName") record.getValueString("billToCustomer.firstName")
+ " placed an order for " + " paid for an order, to be sent to "
+ record.getValueString("shipToCustomer.firstName") + record.getValueString("shipToCustomer.firstName")
---- ----
[source,java]
.Implicit QueryJoin, where unambiguous and required by QQueryFilter
----
// TODO finish and verify
queryInput.withTableName("order");
----
=== QueryOutput === QueryOutput
* `records` - *List of QRecord* - List of 0 or more records that match the query filter. * `records` - *List of QRecord* - List of 0 or more records that match the query filter.
** _Note: If a *recordPipe* was supplied to the QueryInput, then calling `queryOutput.getRecords()` will result in an `IllegalStateException` being thrown - as the records were placed into the pipe as they were fetched, and cannot all be accessed as a single list._ ** _Note: If a *recordPipe* was supplied to the QueryInput, then calling `queryOutput.getRecords()` will result in an `IllegalStateException` being thrown - as the records were placed into the pipe as they were fetched, and cannot all be accessed as a single list._