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