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