简体   繁体   中英

Is there a better way to invoke a table-producing function other than calling `val` all the times?

I'm calling a function from the database, named some_table_generating_function for the sake of simplicity, in order to cast the query into a select statement returning Field<Array<UUID>> , it forces me to use the val function of the DSL, and it creates a lot of boilerplate for doing a simple function invocation.

The following example works, but it seems to be overusing the val function, do you have any suggestions to cleanse this piece of code?

context
  .select()
  .from(
    select(
      // fields to be selected
    )
      .from(
        Public.SOME_TABLE_GENERATING_FUNCTION(
          `val`(someString.capitalise()),
          `val`(someInt),
          `val`(BigDecimal(someDecimalString)),
          `val`(someInt),
          `val`(BigDecimal(anotherDecimalString)),
          `val`(BigDecimal(yetAnotherDecimalString)),
          `val`(anotherInt),
          `val`(someLong),
          `val`(anotherLong),
          // the important bit: uuid[] parameter expected for this parameter
          field(
            "ARRAY({0})::uuid[]",
            select(A_TABLE.UUID.cast(String::class.java))
              .from(A_TABLE)
              .innerJoin(ANOTHER_TABLE)
              .on(A_TABLE.UUID.eq(ANOTHER_TABLE.UUID))
              .where(
                // additional conditions
              )
          ) as Field<Array<UUID>>
        )
      )
      .join(THE_TABLE)
      .asTable("inner_query")
  )
  .where(
    // additional conditions
  )

Background on the availability of convenience overloads

jOOQ's API can't overload all possible combinations of Tn vs Field<Tn> for larger numbers of n where n is the number of function parameters. For example:

  • 1 parameter = 2 overloads ( f(T1) and f(F<T1>)
  • 2 parameters = 4 overloads ( f(T1, T2) , f(T1, F<T2>) , f(F<T1>, T2) , f(F<T1>, F<T2>)
  • 3 parameters = 8 overloads
  • n parameters = 2^n overloads

While the DSL API often provides complete overloads for 2 parameters, it stops at 3 parameters, offering only 2 overloads in total:

  • An overload accepting only bind values
  • An overload accepting only expressions

It is the same with convenience overloads of generated user defined functions.

Possibility of a more verbose call syntax

Ordinary routines support both the convenience syntax and a more verbose call syntax:

// Convenience call
Routines.ordinaryRoutine(1, 2)

// Verbose way to call the routine, equivalent to the above
val r = OrdinaryRoutine()
r.param1 = 1
r.param2 = 2

This currently isn't available for table valued functions, which only know the "convenience syntax". Might be worth looking into generating alternatives to calling table valued functions:

Workarounds

  • You could create an auxiliary function that calls your function but accepts the first set of parameters in the form of a UDT ( CREATE TYPE ), so you have to wrap the single UDT argument in DSL.val() only a single time. This doesn't scale too well in terms of function API design, but it works around this problem
  • You could use plain SQL templating for the function call ( from("f(?, ?, ... {0})", someString.capitalise(), someInt, ..., field(...)) ), since you're already using a plain SQL template. This won't be type safe, though.
  • You could extend the JavaGenerator to generate an extra overload for your specific case

Personally, I don't find any of these workarounds very practical. Since you probably don't have this case very often, I'd stick with the original call using explicit val calls

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM