001/** 002 * Copyright (C) 2006-2025 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.api.record; 017 018import static java.util.Optional.ofNullable; 019 020import java.math.BigDecimal; 021import java.time.Instant; 022import java.time.ZonedDateTime; 023import java.util.Collection; 024import java.util.Comparator; 025import java.util.Date; 026import java.util.List; 027import java.util.Optional; 028import java.util.OptionalDouble; 029import java.util.OptionalInt; 030import java.util.OptionalLong; 031import java.util.function.Function; 032 033import org.talend.sdk.component.api.record.Schema.Entry; 034 035public interface Record { 036 037 String RECORD_ERROR_SUPPORT = "talend.component.record.error.support"; 038 039 String RECORD_NULLABLE_CHECK = "talend.component.record.nullable.check"; 040 041 /** 042 * @return the schema of this record. 043 */ 044 Schema getSchema(); 045 046 /** 047 * Create a Builder with values of the record present in {@link Schema}. 048 * 049 * @param schema new schema 050 * @return a {@link Record.Builder} 051 */ 052 default Builder withNewSchema(Schema schema) { 053 throw new UnsupportedOperationException("#withNewSchema is not implemented"); 054 } 055 056 /** 057 * Access a record field value. 058 * 059 * IMPORTANT: it is always better to use the typed accessors and the optional flavor when the entry is nullable. 060 * 061 * @param expectedType the expected type for the column. 062 * @param name the name of the column. 063 * @param <T> the type of expectedType. 064 * @return the column value. 065 */ 066 <T> T get(Class<T> expectedType, String name); 067 068 default <T> T get(Class<T> expectedType, Schema.Entry entry) { 069 if (entry == null) { 070 return null; 071 } 072 return this.get(expectedType, entry.getName()); 073 } 074 075 /** 076 * See {@link Record#get(Class, String)}. 077 * 078 * @param name entry name. 079 * @return the value of the entry in this record. 080 */ 081 default String getString(final String name) { 082 return get(String.class, name); 083 } 084 085 /** 086 * See {@link Record#get(Class, String)}. 087 * 088 * @param name entry name. 089 * @return the value of the entry in this record. 090 */ 091 default int getInt(final String name) { 092 return get(Integer.class, name); 093 } 094 095 /** 096 * See {@link Record#get(Class, String)}. 097 * 098 * @param name entry name. 099 * @return the value of the entry in this record. 100 */ 101 default long getLong(final String name) { 102 return get(Long.class, name); 103 } 104 105 /** 106 * See {@link Record#get(Class, String)}. 107 * 108 * @param name entry name. 109 * @return the value of the entry in this record. 110 */ 111 default double getDouble(final String name) { 112 return get(Double.class, name); 113 } 114 115 /** 116 * See {@link Record#get(Class, String)}. 117 * 118 * @param name entry name. 119 * @return the value of the entry in this record. 120 */ 121 default float getFloat(final String name) { 122 return get(Float.class, name); 123 } 124 125 /** 126 * See {@link Record#get(Class, String)}. 127 * 128 * @param name entry name. 129 * @return the value of the entry in this record. 130 */ 131 default boolean getBoolean(final String name) { 132 return get(Boolean.class, name); 133 } 134 135 /** 136 * See {@link Record#get(Class, String)}. 137 * 138 * @param name entry name. 139 * @return the value of the entry in this record. 140 */ 141 default byte[] getBytes(final String name) { 142 return get(byte[].class, name); 143 } 144 145 /** 146 * See {@link Record#get(Class, String)}. 147 * 148 * @param name entry name. 149 * @return the value of the entry in this record. 150 */ 151 default Record getRecord(final String name) { 152 return get(Record.class, name); 153 } 154 155 /** 156 * See {@link Record#get(Class, String)}. 157 * 158 * @param type type of the elements of the collection. 159 * @param name entry name. 160 * @param <T> type of the collection elements. 161 * @return the value of the entry in this record. 162 */ 163 default <T> Collection<T> getArray(final Class<T> type, final String name) { 164 return get(Collection.class, name); 165 } 166 167 /** 168 * See {@link Record#get(Class, String)}. 169 * 170 * @param name entry name. 171 * @return the value of the entry in this record. 172 */ 173 default ZonedDateTime getDateTime(final String name) { 174 return get(ZonedDateTime.class, name); 175 } 176 177 /** 178 * See {@link Record#get(Class, String)}. 179 * 180 * @param name entry name. 181 * @return the value of the entry in this record. 182 */ 183 default Instant getInstant(final String name) { 184 return get(Instant.class, name); 185 } 186 187 default BigDecimal getDecimal(final String name) { 188 return get(BigDecimal.class, name); 189 } 190 191 /** 192 * See {@link Record#get(Class, String)}. 193 * 194 * @param type type of the elements of the collection. 195 * @param name entry name. 196 * @param <T> type of the collection elements. 197 * @return the value of the entry in this record. 198 */ 199 default <T> Optional<Collection<T>> getOptionalArray(final Class<T> type, final String name) { 200 final Collection<T> value = get(Collection.class, name); 201 return ofNullable(value); 202 } 203 204 /** 205 * See {@link Record#get(Class, String)}. 206 * 207 * @param name entry name. 208 * @return the value of the entry in this record. 209 */ 210 default Optional<ZonedDateTime> getOptionalDateTime(final String name) { 211 return ofNullable(get(ZonedDateTime.class, name)); 212 } 213 214 /** 215 * See {@link Record#get(Class, String)}. 216 * 217 * @param name entry name. 218 * @return the value of the entry in this record. 219 */ 220 default Optional<Instant> getOptionalInstant(final String name) { 221 return ofNullable(get(Instant.class, name)); 222 } 223 224 /** 225 * See {@link Record#get(Class, String)}. 226 * 227 * @param name entry name. 228 * @return the value of the entry in this record. 229 */ 230 default Optional<BigDecimal> getOptionalDecimal(final String name) { 231 return ofNullable(get(BigDecimal.class, name)); 232 } 233 234 /** 235 * See {@link Record#get(Class, String)}. 236 * 237 * @param name entry name. 238 * @return the value of the entry in this record. 239 */ 240 default Optional<String> getOptionalString(final String name) { 241 return ofNullable(get(String.class, name)); 242 } 243 244 /** 245 * See {@link Record#get(Class, String)}. 246 * 247 * @param name entry name. 248 * @return the value of the entry in this record. 249 */ 250 default OptionalInt getOptionalInt(final String name) { 251 final Integer value = get(Integer.class, name); 252 return value == null ? OptionalInt.empty() : OptionalInt.of(value); 253 } 254 255 /** 256 * See {@link Record#get(Class, String)}. 257 * 258 * @param name entry name. 259 * @return the value of the entry in this record. 260 */ 261 default OptionalLong getOptionalLong(final String name) { 262 final Long value = get(Long.class, name); 263 return value == null ? OptionalLong.empty() : OptionalLong.of(value); 264 } 265 266 /** 267 * See {@link Record#get(Class, String)}. 268 * 269 * @param name entry name. 270 * @return the value of the entry in this record. 271 */ 272 default OptionalDouble getOptionalDouble(final String name) { 273 final Double value = get(Double.class, name); 274 return value == null ? OptionalDouble.empty() : OptionalDouble.of(value); 275 } 276 277 /** 278 * See {@link Record#get(Class, String)}. 279 * 280 * @param name entry name. 281 * @return the value of the entry in this record. 282 */ 283 default OptionalDouble getOptionalFloat(final String name) { 284 final Float value = get(Float.class, name); 285 return value == null ? OptionalDouble.empty() : OptionalDouble.of(value); 286 } 287 288 /** 289 * See {@link Record#get(Class, String)}. 290 * 291 * @param name entry name. 292 * @return the value of the entry in this record. 293 */ 294 default Optional<Boolean> getOptionalBoolean(final String name) { 295 return ofNullable(get(Boolean.class, name)); 296 } 297 298 /** 299 * See {@link Record#get(Class, String)}. 300 * 301 * @param name entry name. 302 * @return the value of the entry in this record. 303 */ 304 default Optional<byte[]> getOptionalBytes(final String name) { 305 return ofNullable(get(byte[].class, name)); 306 } 307 308 /** 309 * See {@link Record#get(Class, String)}. 310 * 311 * @param name entry name. 312 * @return the value of the entry in this record. 313 */ 314 default Optional<Record> getOptionalRecord(final String name) { 315 return ofNullable(get(Record.class, name)); 316 } 317 318 default boolean isValid() { 319 return !getSchema().getAllEntries() 320 .anyMatch(entry -> !entry.isValid()); 321 } 322 323 /** 324 * Allows to create a record with a fluent API. This is the unique recommended way to create a record. 325 */ 326 327 interface Builder { 328 329 Record build(); 330 331 Object getValue(String name); 332 333 List<Entry> getCurrentEntries(); 334 335 default Entry getEntry(final String name) { 336 return this.getCurrentEntries() 337 .stream() 338 .filter((Entry e) -> name.equals(e.getName())) 339 .findFirst() 340 .orElse(null); 341 } 342 343 /** 344 * Mark that next entry created {@code withXXXX()} will be before {@code entryName} in schema order. 345 * 346 * @see 347 * <ul> 348 * <li>{@link Schema#naturalOrder()}</li> 349 * <li>{@link Schema#getEntriesOrdered()}</li> 350 * <li>{@link Schema#getEntriesOrdered(Comparator)}</li> 351 * </ul> 352 * 353 * @param entryName target entry name. This entry <b>must</b> exist! 354 * 355 * @return this Builder 356 */ 357 default Builder before(String entryName) { 358 throw new UnsupportedOperationException("#before is not implemented"); 359 } 360 361 /** 362 * Mark that next entry created {@code withXXXX()} will be after {@code entryName} in schema order. 363 * 364 * @see 365 * <ul> 366 * <li>{@link Schema#naturalOrder()}</li> 367 * <li>{@link Schema#getEntriesOrdered()}</li> 368 * <li>{@link Schema#getEntriesOrdered(Comparator)}</li> 369 * </ul> 370 * 371 * @param entryName target entry name. This entry <b>must</b> exist! 372 * 373 * @return this Builder 374 */ 375 default Builder after(String entryName) { 376 throw new UnsupportedOperationException("#after"); 377 } 378 379 Builder removeEntry(Schema.Entry schemaEntry); 380 381 Builder updateEntryByName(String name, Schema.Entry schemaEntry); 382 383 default Builder updateEntryByName(String name, 384 Schema.Entry schemaEntry, 385 Function<Object, Object> valueCastFunction) { 386 throw new UnsupportedOperationException("#updateEntryByName"); 387 } 388 389 Builder with(Schema.Entry entry, Object value); 390 391 Builder withString(String name, String value); 392 393 Builder withString(Schema.Entry entry, String value); 394 395 Builder withBytes(String name, byte[] value); 396 397 Builder withBytes(Schema.Entry entry, byte[] value); 398 399 Builder withDateTime(String name, Date value); 400 401 Builder withDateTime(Schema.Entry entry, Date value); 402 403 Builder withDateTime(String name, ZonedDateTime value); 404 405 Builder withDateTime(Schema.Entry entry, ZonedDateTime value); 406 407 default Builder withDecimal(String name, BigDecimal value) { 408 throw new UnsupportedOperationException("#withDecimal"); 409 } 410 411 default Builder withDecimal(Schema.Entry entry, BigDecimal value) { 412 throw new UnsupportedOperationException("#withDecimal"); 413 } 414 415 Builder withTimestamp(String name, long value); 416 417 Builder withTimestamp(Schema.Entry entry, long value); 418 419 default Builder withInstant(String name, Instant value) { 420 throw new UnsupportedOperationException("#withInstant"); 421 } 422 423 default Builder withInstant(Schema.Entry entry, Instant value) { 424 throw new UnsupportedOperationException("#withInstant"); 425 } 426 427 Builder withInt(String name, int value); 428 429 Builder withInt(Schema.Entry entry, int value); 430 431 Builder withLong(String name, long value); 432 433 Builder withLong(Schema.Entry entry, long value); 434 435 Builder withFloat(String name, float value); 436 437 Builder withFloat(Schema.Entry entry, float value); 438 439 Builder withDouble(String name, double value); 440 441 Builder withDouble(Schema.Entry entry, double value); 442 443 Builder withBoolean(String name, boolean value); 444 445 Builder withBoolean(Schema.Entry entry, boolean value); 446 447 Builder withRecord(Schema.Entry entry, Record value); 448 449 /** 450 * @since 1.1.6 451 * 452 * @param name entry name. 453 * @param value record value. 454 * @return this builder. 455 */ 456 Builder withRecord(String name, Record value); 457 458 <T> Builder withArray(Schema.Entry entry, Collection<T> values); 459 } 460}