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.time.ZonedDateTime;
021import java.util.Collection;
022import java.util.Comparator;
023import java.util.Date;
024import java.util.List;
025import java.util.Optional;
026import java.util.OptionalDouble;
027import java.util.OptionalInt;
028import java.util.OptionalLong;
029
030import org.talend.sdk.component.api.record.Schema.Entry;
031
032public interface Record {
033
034    /**
035     * @return the schema of this record.
036     */
037    Schema getSchema();
038
039    /**
040     * Create a Builder with values of the record present in {@link Schema}.
041     * 
042     * @param schema new schema
043     * @return a {@link Record.Builder}
044     */
045    default Builder withNewSchema(Schema schema) {
046        throw new UnsupportedOperationException("#withNewSchema is not implemented");
047    }
048
049    /**
050     * Access a record field value.
051     *
052     * IMPORTANT: it is always better to use the typed accessors and the optional flavor when the entry is nullable.
053     *
054     * @param expectedType the expected type for the column.
055     * @param name the name of the column.
056     * @param <T> the type of expectedType.
057     * @return the column value.
058     */
059    <T> T get(Class<T> expectedType, String name);
060
061    /**
062     * See {@link Record#get(Class, String)}.
063     * 
064     * @param name entry name.
065     * @return the value of the entry in this record.
066     */
067    default String getString(final String name) {
068        return get(String.class, name);
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 int getInt(final String name) {
078        return get(Integer.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 long getLong(final String name) {
088        return get(Long.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 double getDouble(final String name) {
098        return get(Double.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 float getFloat(final String name) {
108        return get(Float.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 boolean getBoolean(final String name) {
118        return get(Boolean.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 byte[] getBytes(final String name) {
128        return get(byte[].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 Record getRecord(final String name) {
138        return get(Record.class, name);
139    }
140
141    /**
142     * See {@link Record#get(Class, String)}.
143     * 
144     * @param type type of the elements of the collection.
145     * @param name entry name.
146     * @param <T> type of the collection elements.
147     * @return the value of the entry in this record.
148     */
149    default <T> Collection<T> getArray(final Class<T> type, final String name) {
150        return get(Collection.class, name);
151    }
152
153    /**
154     * See {@link Record#get(Class, String)}.
155     * 
156     * @param name entry name.
157     * @return the value of the entry in this record.
158     */
159    default ZonedDateTime getDateTime(final String name) {
160        return get(ZonedDateTime.class, name);
161    }
162
163    /**
164     * See {@link Record#get(Class, String)}.
165     * 
166     * @param type type of the elements of the collection.
167     * @param name entry name.
168     * @param <T> type of the collection elements.
169     * @return the value of the entry in this record.
170     */
171    default <T> Optional<Collection<T>> getOptionalArray(final Class<T> type, final String name) {
172        final Collection<T> value = get(Collection.class, name);
173        return ofNullable(value);
174    }
175
176    /**
177     * See {@link Record#get(Class, String)}.
178     * 
179     * @param name entry name.
180     * @return the value of the entry in this record.
181     */
182    default Optional<ZonedDateTime> getOptionalDateTime(final String name) {
183        return ofNullable(get(ZonedDateTime.class, name));
184    }
185
186    /**
187     * See {@link Record#get(Class, String)}.
188     * 
189     * @param name entry name.
190     * @return the value of the entry in this record.
191     */
192    default Optional<String> getOptionalString(final String name) {
193        return ofNullable(get(String.class, name));
194    }
195
196    /**
197     * See {@link Record#get(Class, String)}.
198     * 
199     * @param name entry name.
200     * @return the value of the entry in this record.
201     */
202    default OptionalInt getOptionalInt(final String name) {
203        final Integer value = get(Integer.class, name);
204        return value == null ? OptionalInt.empty() : OptionalInt.of(value);
205    }
206
207    /**
208     * See {@link Record#get(Class, String)}.
209     * 
210     * @param name entry name.
211     * @return the value of the entry in this record.
212     */
213    default OptionalLong getOptionalLong(final String name) {
214        final Long value = get(Long.class, name);
215        return value == null ? OptionalLong.empty() : OptionalLong.of(value);
216    }
217
218    /**
219     * See {@link Record#get(Class, String)}.
220     * 
221     * @param name entry name.
222     * @return the value of the entry in this record.
223     */
224    default OptionalDouble getOptionalDouble(final String name) {
225        final Double value = get(Double.class, name);
226        return value == null ? OptionalDouble.empty() : OptionalDouble.of(value);
227    }
228
229    /**
230     * See {@link Record#get(Class, String)}.
231     * 
232     * @param name entry name.
233     * @return the value of the entry in this record.
234     */
235    default OptionalDouble getOptionalFloat(final String name) {
236        final Float value = get(Float.class, name);
237        return value == null ? OptionalDouble.empty() : OptionalDouble.of(value);
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 Optional<Boolean> getOptionalBoolean(final String name) {
247        return ofNullable(get(Boolean.class, name));
248    }
249
250    /**
251     * See {@link Record#get(Class, String)}.
252     * 
253     * @param name entry name.
254     * @return the value of the entry in this record.
255     */
256    default Optional<byte[]> getOptionalBytes(final String name) {
257        return ofNullable(get(byte[].class, name));
258    }
259
260    /**
261     * See {@link Record#get(Class, String)}.
262     * 
263     * @param name entry name.
264     * @return the value of the entry in this record.
265     */
266    default Optional<Record> getOptionalRecord(final String name) {
267        return ofNullable(get(Record.class, name));
268    }
269
270    /**
271     * Allows to create a record with a fluent API. This is the unique recommended way to create a record.
272     */
273
274    interface Builder {
275
276        Record build();
277
278        Object getValue(String name);
279
280        List<Entry> getCurrentEntries();
281
282        /**
283         * Mark that next entry created {@code withXXXX()} will be before {@code entryName} in schema order.
284         *
285         * @see
286         * <ul>
287         * <li>{@link Schema#naturalOrder()}</li>
288         * <li>{@link Schema#getEntriesOrdered()}</li>
289         * <li>{@link Schema#getEntriesOrdered(Comparator)}</li>
290         * </ul>
291         *
292         * @param entryName target entry name. This entry <b>must</b> exist!
293         *
294         * @return this Builder
295         */
296        default Builder before(String entryName) {
297            throw new UnsupportedOperationException("#before is not implemented");
298        }
299
300        /**
301         * Mark that next entry created {@code withXXXX()} will be after {@code entryName} in schema order.
302         *
303         * @see
304         * <ul>
305         * <li>{@link Schema#naturalOrder()}</li>
306         * <li>{@link Schema#getEntriesOrdered()}</li>
307         * <li>{@link Schema#getEntriesOrdered(Comparator)}</li>
308         * </ul>
309         *
310         * @param entryName target entry name. This entry <b>must</b> exist!
311         *
312         * @return this Builder
313         */
314        default Builder after(String entryName) {
315            throw new UnsupportedOperationException("#after");
316        }
317
318        Builder removeEntry(Schema.Entry schemaEntry);
319
320        Builder updateEntryByName(String name, Schema.Entry schemaEntry);
321
322        Builder with(Schema.Entry entry, Object value);
323
324        Builder withString(String name, String value);
325
326        Builder withString(Schema.Entry entry, String value);
327
328        Builder withBytes(String name, byte[] value);
329
330        Builder withBytes(Schema.Entry entry, byte[] value);
331
332        Builder withDateTime(String name, Date value);
333
334        Builder withDateTime(Schema.Entry entry, Date value);
335
336        Builder withDateTime(String name, ZonedDateTime value);
337
338        Builder withDateTime(Schema.Entry entry, ZonedDateTime value);
339
340        Builder withTimestamp(String name, long value);
341
342        Builder withTimestamp(Schema.Entry entry, long value);
343
344        Builder withInt(String name, int value);
345
346        Builder withInt(Schema.Entry entry, int value);
347
348        Builder withLong(String name, long value);
349
350        Builder withLong(Schema.Entry entry, long value);
351
352        Builder withFloat(String name, float value);
353
354        Builder withFloat(Schema.Entry entry, float value);
355
356        Builder withDouble(String name, double value);
357
358        Builder withDouble(Schema.Entry entry, double value);
359
360        Builder withBoolean(String name, boolean value);
361
362        Builder withBoolean(Schema.Entry entry, boolean value);
363
364        Builder withRecord(Schema.Entry entry, Record value);
365
366        /**
367         * @since 1.1.6
368         *
369         * @param name entry name.
370         * @param value record value.
371         * @return this builder.
372         */
373        Builder withRecord(String name, Record value);
374
375        <T> Builder withArray(Schema.Entry entry, Collection<T> values);
376    }
377}