Как сгенерировать код Java для генерации строки из массива в DataWeave 2?

Я работаю над переносом приложения 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')

Вы можете просто убрать эту запятую var result = test() joinBy "," replace ")," with ")" @GettingStarted With123

Karthik 05.01.2023 10:11
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы пытаетесь перенести логику из метода 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 ")

Harshank Bansal 05.01.2023 15:02

Это интересный подход.

aled 05.01.2023 17:40

Большое спасибо @aled за подробную информацию и решение! Вчера провел почти весь день и расстроился. Пока я до сих пор не понимаю всей логики вашего решения (буду читать и перечитывать и тратить некоторое время на понимание Dataweave!), но да, оно работает! Большое спасибо, и вы правы, исходя из мира Java, я пытался заставить dataweave делать это способом Java, мне определенно нужно изучить и изменить свой стиль мышления «Java», еще раз большое спасибо!

GettingStarted With123 05.01.2023 23:11

@GettingStartedWith123 подумайте, какова логика создания вывода из ввода, не пытаясь писать код. В этом смысле это будет похоже на создание сложного SQL-запроса, если это поможет. Например: мне нужно взять каждые n элементов (для этого используется функция DivisionBy()), затем для первых n мне нужно сделать так, а для следующих мне нужно сделать то-то и то-то.

aled 05.01.2023 23:28

Вот что я придумал. Он похож на версию Аледа, с небольшими изменениями, чтобы сделать код меньше.

%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. Я тоже попробую это решение, спасибо!

GettingStarted With123 05.01.2023 23:14

Мне нравится, как это устраняет необходимость в if.

aled 05.01.2023 23:25

Другие вопросы по теме