@@ -5,7 +5,7 @@ import io.github.datacatering.datacaterer.api.HttpMethodEnum.HttpMethodEnum
55import io .github .datacatering .datacaterer .api .HttpQueryParameterStyleEnum .HttpQueryParameterStyleEnum
66import io .github .datacatering .datacaterer .api .converter .Converters .{toScalaList , toScalaMap }
77import io .github .datacatering .datacaterer .api .model .Constants ._
8- import io .github .datacatering .datacaterer .api .model .{ArrayType , Count , DataType , DoubleType , Field , HeaderType , PerFieldCount , Step , StringType , Task , TaskSummary }
8+ import io .github .datacatering .datacaterer .api .model .{ArrayType , Count , DataType , DoubleType , Field , HeaderType , PerFieldCount , Step , StringType , Task , TaskSummary , TransformationConfig }
99
1010import scala .annotation .varargs
1111import scala .collection .JavaConverters ._
@@ -168,6 +168,88 @@ case class TaskBuilder(task: Task = Task()) {
168168 )
169169 this .modify(_.task.steps)(_ ++ List (placeholderStep))
170170 }
171+
172+ /**
173+ * Configure custom transformation for all steps in this task. Defaults to whole-file mode.
174+ * Transformations execute after files are written ("last mile" transformation).
175+ * Step-level transformations will override this task-level configuration.
176+ *
177+ * @param className Fully qualified class name of the transformer
178+ * @return TaskBuilder
179+ */
180+ def transformation (className : String ): TaskBuilder =
181+ this .modify(_.task.transformation).setTo(Some (TransformationConfig (className = className)))
182+
183+ /**
184+ * Configure per-record transformation for all steps. Transforms each record/line individually.
185+ *
186+ * @param className Fully qualified class name of the transformer
187+ * @param methodName Method name to invoke (default: "transformRecord")
188+ * @return TaskBuilder
189+ */
190+ def transformationPerRecord (className : String , methodName : String = " transformRecord" ): TaskBuilder =
191+ this .modify(_.task.transformation).setTo(Some (TransformationConfig (
192+ className = className,
193+ methodName = methodName,
194+ mode = " per-record"
195+ )))
196+
197+ /**
198+ * Configure whole-file transformation for all steps. Transforms entire files as units.
199+ *
200+ * @param className Fully qualified class name of the transformer
201+ * @param methodName Method name to invoke (default: "transformFile")
202+ * @return TaskBuilder
203+ */
204+ def transformationWholeFile (className : String , methodName : String = " transformFile" ): TaskBuilder =
205+ this .modify(_.task.transformation).setTo(Some (TransformationConfig (
206+ className = className,
207+ methodName = methodName,
208+ mode = " whole-file"
209+ )))
210+
211+ /**
212+ * Set output path for transformation. If specified, creates new files instead of replacing originals.
213+ *
214+ * @param outputPath Path where transformed output should be written
215+ * @param deleteOriginal Whether to delete original files after transformation (default: false)
216+ * @return TaskBuilder
217+ */
218+ def transformationOutput (outputPath : String , deleteOriginal : Boolean = false ): TaskBuilder =
219+ this .task.transformation match {
220+ case Some (config) =>
221+ this .modify(_.task.transformation).setTo(Some (config.copy(outputPath = Some (outputPath), deleteOriginal = deleteOriginal)))
222+ case None =>
223+ this
224+ }
225+
226+ /**
227+ * Add options to transformation configuration.
228+ *
229+ * @param options Options to pass to the transformer
230+ * @return TaskBuilder
231+ */
232+ def transformationOptions (options : Map [String , String ]): TaskBuilder =
233+ this .task.transformation match {
234+ case Some (config) =>
235+ this .modify(_.task.transformation).setTo(Some (config.copy(options = config.options ++ options)))
236+ case None =>
237+ this
238+ }
239+
240+ /**
241+ * Explicitly enable or disable transformation for all steps in this task.
242+ *
243+ * @param enabled Whether transformation is enabled
244+ * @return TaskBuilder
245+ */
246+ def enableTransformation (enabled : Boolean ): TaskBuilder =
247+ this .task.transformation match {
248+ case Some (config) =>
249+ this .modify(_.task.transformation).setTo(Some (config.copy(enabled = enabled)))
250+ case None =>
251+ this
252+ }
171253}
172254
173255case class StepBuilder (step : Step = Step (), optValidation : Option [DataSourceValidationBuilder ] = None ) {
@@ -490,6 +572,87 @@ case class StepBuilder(step: Step = Step(), optValidation: Option[DataSourceVali
490572 @ varargs def excludeFieldPatterns (patterns : String * ): StepBuilder =
491573 this .modify(_.step.options)(_ ++ Map (EXCLUDE_FIELD_PATTERNS -> patterns.mkString(" ," )))
492574
575+ /**
576+ * Configure custom transformation for this step. Defaults to whole-file mode.
577+ * Transformations execute after the file is written ("last mile" transformation).
578+ *
579+ * @param className Fully qualified class name of the transformer
580+ * @return StepBuilder
581+ */
582+ def transformation (className : String ): StepBuilder =
583+ this .modify(_.step.transformation).setTo(Some (TransformationConfig (className = className)))
584+
585+ /**
586+ * Configure per-record transformation. Transforms each record/line in the file individually.
587+ *
588+ * @param className Fully qualified class name of the transformer
589+ * @param methodName Method name to invoke (default: "transformRecord")
590+ * @return StepBuilder
591+ */
592+ def transformationPerRecord (className : String , methodName : String = " transformRecord" ): StepBuilder =
593+ this .modify(_.step.transformation).setTo(Some (TransformationConfig (
594+ className = className,
595+ methodName = methodName,
596+ mode = " per-record"
597+ )))
598+
599+ /**
600+ * Configure whole-file transformation. Transforms the entire file as a unit.
601+ *
602+ * @param className Fully qualified class name of the transformer
603+ * @param methodName Method name to invoke (default: "transformFile")
604+ * @return StepBuilder
605+ */
606+ def transformationWholeFile (className : String , methodName : String = " transformFile" ): StepBuilder =
607+ this .modify(_.step.transformation).setTo(Some (TransformationConfig (
608+ className = className,
609+ methodName = methodName,
610+ mode = " whole-file"
611+ )))
612+
613+ /**
614+ * Set output path for transformation. If specified, creates a new file instead of replacing the original.
615+ *
616+ * @param outputPath Path where transformed output should be written
617+ * @param deleteOriginal Whether to delete the original file after transformation (default: false)
618+ * @return StepBuilder
619+ */
620+ def transformationOutput (outputPath : String , deleteOriginal : Boolean = false ): StepBuilder =
621+ this .step.transformation match {
622+ case Some (config) =>
623+ this .modify(_.step.transformation).setTo(Some (config.copy(outputPath = Some (outputPath), deleteOriginal = deleteOriginal)))
624+ case None =>
625+ this
626+ }
627+
628+ /**
629+ * Add options to transformation configuration.
630+ *
631+ * @param options Options to pass to the transformer
632+ * @return StepBuilder
633+ */
634+ def transformationOptions (options : Map [String , String ]): StepBuilder =
635+ this .step.transformation match {
636+ case Some (config) =>
637+ this .modify(_.step.transformation).setTo(Some (config.copy(options = config.options ++ options)))
638+ case None =>
639+ this
640+ }
641+
642+ /**
643+ * Explicitly enable or disable transformation for this step.
644+ *
645+ * @param enabled Whether transformation is enabled
646+ * @return StepBuilder
647+ */
648+ def enableTransformation (enabled : Boolean ): StepBuilder =
649+ this .step.transformation match {
650+ case Some (config) =>
651+ this .modify(_.step.transformation).setTo(Some (config.copy(enabled = enabled)))
652+ case None =>
653+ this
654+ }
655+
493656 private def getValidation : DataSourceValidationBuilder = optValidation.getOrElse(DataSourceValidationBuilder ())
494657}
495658
0 commit comments