All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sksamuel.avro4s.AvroOutputStream.scala Maven / Gradle / Ivy

package com.sksamuel.avro4s

import org.apache.avro.Schema

import java.io.{File, OutputStream}
import java.nio.file.{Files, Path, Paths}
import org.apache.avro.file.CodecFactory
import org.apache.avro.io.EncoderFactory

/**
  * An [[AvroOutputStream]] will write instances of T to an underlying
  * representation.
  *
  * There are three implementations of this stream
  *  - a Data stream,
  *  - a Binary stream
  *  - a Json stream
  *
  * See the methods on the companion object to create instances of each
  * of these types of stream.
  */
trait AvroOutputStream[T] extends AutoCloseable {
  def close(): Unit
  def flush(): Unit
  def fSync(): Unit
  def write(t: T): Unit
  def write(ts: Seq[T]): Unit = ts.foreach(write)
}

object AvroOutputStream:

  /**
    * An [[AvroOutputStream]] that does not write the schema.
    *
    * Use this when you want the smallest messages possible at the cost of not having the
    * schema available in the messages for downstream clients.
    */
  def binary[T](schema: Schema, encoder: Encoder[T]): AvroOutputStreamBuilder[T] =
    given Encoder[T] = encoder
    new AvroOutputStreamBuilder[T](schema, encoder, AvroFormat.Binary)

  def binary[T](using schemaFor: SchemaFor[T], encoder: Encoder[T]): AvroOutputStreamBuilder[T] =
    new AvroOutputStreamBuilder[T](schemaFor.schema, encoder, AvroFormat.Binary)

  /**
    * An [[AvroOutputStream]] that writes as JSON.
    */
  def json[T](schema: Schema, encoder: Encoder[T]): AvroOutputStreamBuilder[T] =
    new AvroOutputStreamBuilder[T](schema, encoder, AvroFormat.Json)

  def json[T](using schemaFor: SchemaFor[T], encoder: Encoder[T]): AvroOutputStreamBuilder[T] =
    new AvroOutputStreamBuilder[T](schemaFor.schema, encoder, AvroFormat.Json)

  /**
    * An [[AvroOutputStream]] that writes the schema alongside data.
    *
    * This is the standard implementation for Avro.
    */
  def data[T](schema: Schema, encoder: Encoder[T]): AvroOutputStreamBuilder[T] =
    new AvroOutputStreamBuilder[T](schema, encoder, AvroFormat.Data)

  def data[T](using schemaFor: SchemaFor[T], encoder: Encoder[T]): AvroOutputStreamBuilder[T] =
    new AvroOutputStreamBuilder[T](schemaFor.schema, encoder, AvroFormat.Data)

class AvroOutputStreamBuilder[T](schema: Schema, encoder: Encoder[T], format: AvroFormat) {
  def to(path: Path): AvroOutputStreamBuilderWithSource[T] = to(Files.newOutputStream(path))
  def to(path: String): AvroOutputStreamBuilderWithSource[T] = to(Paths.get(path))
  def to(file: File): AvroOutputStreamBuilderWithSource[T] = to(file.toPath)
  def to(out: OutputStream): AvroOutputStreamBuilderWithSource[T] =
    new AvroOutputStreamBuilderWithSource(schema, encoder, format, out)
}

case class AvroOutputStreamBuilderWithSource[T](schema: Schema,
                                                encoder: Encoder[T],
                                                format: AvroFormat,
                                                out: OutputStream,
                                                codec: CodecFactory = CodecFactory.nullCodec) {

  def withCodec(codec: CodecFactory) = copy(codec = codec)

  /**
    * Builds an [[AvroOutputStream]]
    */
  def build(): AvroOutputStream[T] = {
    given Encoder[T] = encoder
    format match {
      case AvroFormat.Data => new AvroDataOutputStream[T](schema, out, codec)
      case AvroFormat.Binary => new AvroBinaryOutputStream[T](schema, out, EncoderFactory.get().binaryEncoder(out, null))
      case AvroFormat.Json =>
        val serializer = EncoderFactory.get().jsonEncoder(schema, out)
        new AvroBinaryOutputStream[T](schema, out, serializer)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy