Я работаю над переносом приложения Mule 3 на Mule 4. Мы используем код Java для генерации запроса к базе данных Oracle. Вот существующая функция Java:
public static String generateStringInClause(String tableAlias, String fieldName, List<String> keys) {
String inClause = "";
for (int i = 0; i < keys.size(); i++){
if (i==0) {
inClause += "('" + keys.get(i) + "'";
} else if ((i+1)%10==0) {
inClause += ",'" + keys.get(i) + "')";
} else if (i%10==0) {
inClause += " or "+tableAlias+"."+fieldName+" in ('" + keys.get(i) + "'";
} else if (i == keys.size()-1){
inClause += ",'" + keys.get(i) + "')";
} else {
inClause += ",'" + keys.get(i) + "'";
}
}
if (keys.size() % 10 == 1 || keys.size() == 1) {
inClause = inClause + ")";
}
return inClause;
}
Вот фактические результаты кода Java, когда я передаю список ключей разных размеров:
* 21 = ('a0','a1','a2'...'a8','a9') or xyz.abc in ('a10','a11',...'a19') or xyz.abc in ('a20')
* 12 = ('a0','a1','a2','a3','a4','a5','a6','a7','a8','a9') or xyz.abc in ('a10','a11')
* 11 = ('a0','a1','a2','a3','a4','a5','a6','a7','a8','a9') or xyz.abc in ('a10')
*
* 10 = ('a0','a1','a2','a3','a4','a5','a6','a7','a8','a9')
* 09 = ('a0','a1','a2','a3','a4','a5','a6','a7','a8')
* 01 = ('a0')
Теперь в Mule 4 мы не хотим использовать какие-либо методы/классы Java, поэтому необходимо преобразовать эту функцию в DataWeave.
Вот что я пробовал:
%dw 2.0
output application/java
var inClause = ""
var size = sizeOf(payload.keys)
fun test() = payload.keys map ((item, index) ->
if (index ==0) ( inClause ++ "('" ++ item ++ "'")
else if (mod((index+1),10)==0) ( "'" ++ item ++ "')")
else if (mod((index),10)==0) ( " or "++ payload.tableAlias ++ "." ++ payload.fieldName ++ " in ('" ++ item ++ "'")
else if (index == (size-1) ) ( "'" ++ item ++ "')")
else ("'" ++ item ++ "'")
)
var result = test() joinBy ","
var result1 = if ((mod(size,10) == 1) or (size == 1)) (result ++ ")") else (result)
---
result1
Этот скрипт отлично работает и дает тот же результат, когда у меня есть список до 10 элементов. Он не дает такого же результата, как метод Java, когда у меня есть> 10 элементов в списке ключей.
Вход в скрипт DataWeave:
{
"tableAlias": "xyz",
"fieldName": "abc",
"keys" : ["a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","a10"]
}
В выводе есть дополнительная запятая ,
перед or
, что приведет к сбою SQL-запроса.
Фактический результат:
('a0','a1','a2','a3','a4','a5','a6','a7','a8','a9'), or xyz.abc in ('a10')
Вы пытаетесь перенести логику из метода Java, но вам необходимо учитывать, что Java — это императивный язык, а DataWeave — функциональный язык. Миграция 1 к 1 может не работать или быть слишком сложной в обслуживании. Например, переменная inClause
абсолютно ничего не делает в скрипте DataWeave. Вы не можете накапливать значение в цикле, как в Java. Вы должны думать о том, чего вы пытаетесь достичь, как о результате, а затем думать о том, как это выразить.
В качестве примера я выбираю сначала разделить ключи на блоки по n. Мне нужно только условие для идентификации первого блока. Мне не нужно преобразовывать каждое значение после того, как я знаю, является ли это первым блоком или одним из остальных. Таким образом, мне не нужно беспокоиться о совпадении запятых или скобок. Затем я трансформирую каждый блок более естественно, на мой взгляд. Я добавил вспомогательную функцию для форматирования значений в каждом блоке. Я использую reduce() в конце, чтобы объединить строку, полученную в результате каждого блока. Замысел кода должен быть более ясным, чем в коде Java.
Я инкапсулировал входные данные функций в параметры, чтобы их можно было использовать повторно и чтобы они были чистыми. Размер блока также является параметром. Магические числа в коде не являются хорошей практикой.
%dw 2.0
output application/java
import * from dw::core::Arrays
fun quoteArray(a) = "(" ++ (a map ("'" ++ $ ++ "'") joinBy ",") ++ ")"
fun generateStringInClause(tableAlias, fieldName, keys, size) =
keys divideBy size
map ((item, index) ->
if (index == 0) quoteArray(item)
else (" or "++ tableAlias ++ "." ++ fieldName ++ " in " ++ quoteArray(item) )
)
reduce ((item, accumulator = "") -> accumulator ++ item)
---
generateStringInClause(payload.tableAlias, payload.fieldName, payload.keys, 10)
Вход:
{
"tableAlias": "xyz",
"fieldName": "abc",
"keys" : ["a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","a10","a11", "a12","a13","a14","a15","a16","a17","a18","a19","a20"]
}
Выход:
('a0','a1','a2','a3','a4','a5','a6','a7','a8','a9') or xyz.abc in ('a10','a11','a12','a13','a14','a15','a16','a17','a18','a19') or xyz.abc in ('a20')
Предложение. Вы можете использовать quoteArray
в отдельной функции карты, а затем joinBy
в операторе in. Это позволит избежать if/else
в индексе и дополнительных reduce
лайков keys divideBy size map quoteArray($) joinBy (" OR $(tableAlias).$(fieldName) IN ")
Это интересный подход.
Большое спасибо @aled за подробную информацию и решение! Вчера провел почти весь день и расстроился. Пока я до сих пор не понимаю всей логики вашего решения (буду читать и перечитывать и тратить некоторое время на понимание Dataweave!), но да, оно работает! Большое спасибо, и вы правы, исходя из мира Java, я пытался заставить dataweave делать это способом Java, мне определенно нужно изучить и изменить свой стиль мышления «Java», еще раз большое спасибо!
@GettingStartedWith123 подумайте, какова логика создания вывода из ввода, не пытаясь писать код. В этом смысле это будет похоже на создание сложного SQL-запроса, если это поможет. Например: мне нужно взять каждые n элементов (для этого используется функция DivisionBy()), затем для первых n мне нужно сделать так, а для следующих мне нужно сделать то-то и то-то.
Вот что я придумал. Он похож на версию Аледа, с небольшими изменениями, чтобы сделать код меньше.
%dw 2.0
import divideBy from dw::core::Arrays
output application/java
fun quoteArray(a) = "(" ++ (a map ("'$'") joinBy ",") ++ ")"
fun generateInClause(tableAlias, fieldName, keys, size) =
keys divideBy size
map quoteArray($)
joinBy (" OR $(tableAlias).$(fieldName) IN ")
---
"(" ++ generateInClause(payload.tableAlias, payload.fieldName, payload.keys, 10) ++ ")"
Спасибо, @Harshank тоже попробую. Также извиняюсь за такой комментарий новичка, как я, но я часто чувствую, что меньше кода нехорошо, так как это затрудняет читаемость и ремонтопригодность, но опять же это может быть потому, что я определенно не являюсь экспертом по Dataweave. Я тоже попробую это решение, спасибо!
Мне нравится, как это устраняет необходимость в if.
Вы можете просто убрать эту запятую
var result = test() joinBy "," replace ")," with ")"
@GettingStarted With123