When doing beta reductions, the Opinions of AST elements need to be set to their neutral positions.
Due to the introduction of null checks in map
, flatMap
, and exists
, in
FlattenOptionOperation
in order to resolve #1053, as well as to support non-ansi
compliant string concatenation as outlined in #1295, large conditional composites
became common.
Due to the introduction of null checks in map
, flatMap
, and exists
, in
FlattenOptionOperation
in order to resolve #1053, as well as to support non-ansi
compliant string concatenation as outlined in #1295, large conditional composites
became common. For example:
Now, let's add a
case class Holder(value:Option[String])
// The following statement
query[Holder].map(h => h.value.map(_ + "foo"))
// Will yield the following result
SELECT CASE WHEN h.value IS NOT NULL THEN h.value || 'foo' ELSE null END FROM Holder h
getOrElse
statement to the clause that requires an additional
wrapped null check. We cannot rely on there being a map
call beforehand
since we could be reading value
as a nullable field directly from the database).
This of course is highly redundant and can be reduced to simply:
// The following statement
query[Holder].map(h => h.value.map(_ + "foo").getOrElse("bar"))
// Yields the following result:
SELECT CASE WHEN
CASE WHEN h.value IS NOT NULL THEN h.value || 'foo' ELSE null END
IS NOT NULL THEN
CASE WHEN h.value IS NOT NULL THEN h.value || 'foo' ELSE null END
ELSE 'bar' END FROM Holder h
This reduction is done by the "Center Rule." There are some other simplification
rules as well. Note how we are force to null-check both
SELECT CASE WHEN h.value IS NOT NULL AND (h.value || 'foo') IS NOT NULL THEN h.value || 'foo' ELSE 'bar' END FROM Holder h
h.value
as well as (h.value || 'foo')
because
a user may use Option[T].flatMap
and explicitly transform a particular value to null
.
Take the .returning
part in a query that contains it and return the array of columns
representing of the returning seccovtion with any other operations etc...
Take the .returning
part in a query that contains it and return the array of columns
representing of the returning seccovtion with any other operations etc... that they might contain.
A problem occurred in the original way infixes were done in that it was assumed that infix clauses represented pure functions.
A problem occurred in the original way infixes were done in that it was assumed that infix
clauses represented pure functions. While this is true of many UDFs (e.g. CONCAT
, GETDATE
)
it is certainly not true of many others e.g. RAND()
, and most importantly RANK()
. For this reason,
the operations that are done in ApplyMap
on standard AST Map
clauses cannot be done therefore additional
safety checks were introduced there in order to assure this does not happen. In addition to this however,
it is necessary to add this normalization step which inserts Nested
AST elements in every map
that contains impure infix. See more information and examples in #1534.
When actions are used with a .returning
clause, remove the columns used in the returning clause from the action.
When actions are used with a .returning
clause, remove the columns used in the returning clause from the action.
E.g. for insert(Person(id, name)).returning(_.id)
remove the id
column from the original insert.
When doing beta reductions, the Opinions of AST elements need to be set to their neutral positions.
For example, the
Property
AST element has a field calledrenameable
which dicatates whether to use aNamingStrategy
during tokenization inSqlIdiom
(and other idioms) or not. Since this property only does things after Normalization, it should be completely transparent to beta reduction (all AST Opinion's have the same behavior). This is why we need to automatically set therenameable
field to a pre-defined value every timeProperty
is looked up. This is done via theAst.neutralize
method.