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