From 89f7ceb940709153aea297d2ee2330e028516215 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Sat, 13 Aug 2022 18:49:53 +0000 Subject: [PATCH 1/2] Use sealed abstract case classes to reduce bincompat surface --- .../events/ApiGatewayProxyEventV2.scala | 29 ++++- .../events/ApiGatewayProxyResultV2.scala | 17 ++- .../lambda/events/DynamoDbStreamEvent.scala | 28 ++++- .../lambda/events/KinesisStreamEvent.scala | 45 +++++++- .../feral/lambda/events/S3BatchEvent.scala | 32 +++++- .../feral/lambda/events/S3BatchResult.scala | 23 +++- .../scala/feral/lambda/events/SnsEvent.scala | 105 ++++++++++++++++-- .../scala/feral/lambda/events/SqsEvent.scala | 83 ++++++++++++-- 8 files changed, 325 insertions(+), 37 deletions(-) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala index 61245dc5..1fe6612c 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala @@ -20,18 +20,22 @@ package events import io.circe.Decoder import natchez.Kernel -final case class Http(method: String) +sealed abstract case class Http private (method: String) object Http { + private[lambda] def apply(method: String): Http = new Http(method) {} + implicit val decoder: Decoder[Http] = Decoder.forProduct1("method")(Http.apply) } -final case class RequestContext(http: Http) +sealed abstract case class RequestContext private (http: Http) object RequestContext { + private[lambda] def apply(http: Http): RequestContext = new RequestContext(http) {} + implicit val decoder: Decoder[RequestContext] = Decoder.forProduct1("http")(RequestContext.apply) } -final case class ApiGatewayProxyEventV2( +sealed abstract case class ApiGatewayProxyEventV2 private ( rawPath: String, rawQueryString: String, cookies: Option[List[String]], @@ -42,6 +46,25 @@ final case class ApiGatewayProxyEventV2( ) object ApiGatewayProxyEventV2 { + private[lambda] def apply( + rawPath: String, + rawQueryString: String, + cookies: Option[List[String]], + headers: Map[String, String], + requestContext: RequestContext, + body: Option[String], + isBase64Encoded: Boolean + ): ApiGatewayProxyEventV2 = + new ApiGatewayProxyEventV2( + rawPath, + rawQueryString, + cookies, + headers, + requestContext, + body, + isBase64Encoded + ) {} + implicit def decoder: Decoder[ApiGatewayProxyEventV2] = Decoder.forProduct7( "rawPath", "rawQueryString", diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala index ef70c9ee..60290c5a 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala @@ -18,7 +18,7 @@ package feral.lambda.events import io.circe.Encoder -final case class ApiGatewayProxyStructuredResultV2( +sealed abstract case class ApiGatewayProxyStructuredResultV2 private ( statusCode: Int, headers: Map[String, String], body: String, @@ -27,6 +27,21 @@ final case class ApiGatewayProxyStructuredResultV2( ) object ApiGatewayProxyStructuredResultV2 { + def apply( + statusCode: Int, + headers: Map[String, String], + body: String, + isBase64Encoded: Boolean, + cookies: List[String] + ): ApiGatewayProxyStructuredResultV2 = + new ApiGatewayProxyStructuredResultV2( + statusCode, + headers, + body, + isBase64Encoded, + cookies + ) {} + implicit def encoder: Encoder[ApiGatewayProxyStructuredResultV2] = Encoder.forProduct5( "statusCode", "headers", diff --git a/lambda/shared/src/main/scala/feral/lambda/events/DynamoDbStreamEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/DynamoDbStreamEvent.scala index d9d07f3e..f6859d9e 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/DynamoDbStreamEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/DynamoDbStreamEvent.scala @@ -81,7 +81,7 @@ object StreamRecord { )(StreamRecord.apply) } -final case class DynamoDbRecord( +sealed abstract case class DynamoDbRecord private ( awsRegion: Option[String], dynamodb: Option[StreamRecord], eventID: Option[String], @@ -93,6 +93,27 @@ final case class DynamoDbRecord( ) object DynamoDbRecord { + private[lambda] def apply( + awsRegion: Option[String], + dynamodb: Option[StreamRecord], + eventID: Option[String], + eventName: Option[String], + eventSource: Option[String], + eventSourceArn: Option[String], + eventVersion: Option[String], + userIdentity: Option[Json] + ): DynamoDbRecord = + new DynamoDbRecord( + awsRegion, + dynamodb, + eventID, + eventName, + eventSource, + eventSourceArn, + eventVersion, + userIdentity + ) {} + implicit val decoder: Decoder[DynamoDbRecord] = Decoder.forProduct8( "awsRegion", "dynamodb", @@ -105,11 +126,14 @@ object DynamoDbRecord { )(DynamoDbRecord.apply) } -final case class DynamoDbStreamEvent( +sealed abstract case class DynamoDbStreamEvent private ( records: List[DynamoDbRecord] ) object DynamoDbStreamEvent { + private[lambda] def apply(records: List[DynamoDbRecord]): DynamoDbStreamEvent = + new DynamoDbStreamEvent(records) {} + implicit val decoder: Decoder[DynamoDbStreamEvent] = Decoder.forProduct1("Records")(DynamoDbStreamEvent.apply) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala index a18f65ee..6ec8f240 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala @@ -23,7 +23,7 @@ import scodec.bits.ByteVector import java.time.Instant -final case class KinesisStreamRecordPayload( +sealed abstract case class KinesisStreamRecordPayload private ( approximateArrivalTimestamp: Instant, data: ByteVector, kinesisSchemaVersion: String, @@ -32,6 +32,21 @@ final case class KinesisStreamRecordPayload( ) object KinesisStreamRecordPayload { + private[lambda] def apply( + approximateArrivalTimestamp: Instant, + data: ByteVector, + kinesisSchemaVersion: String, + partitionKey: String, + sequenceNumber: String + ): KinesisStreamRecordPayload = + new KinesisStreamRecordPayload( + approximateArrivalTimestamp, + data, + kinesisSchemaVersion, + partitionKey, + sequenceNumber + ) {} + implicit val decoder: Decoder[KinesisStreamRecordPayload] = Decoder.forProduct5( "approximateArrivalTimestamp", "data", @@ -41,7 +56,7 @@ object KinesisStreamRecordPayload { )(KinesisStreamRecordPayload.apply) } -final case class KinesisStreamRecord( +sealed abstract case class KinesisStreamRecord private ( awsRegion: String, eventID: String, eventName: String, @@ -53,6 +68,27 @@ final case class KinesisStreamRecord( ) object KinesisStreamRecord { + private[lambda] def apply( + awsRegion: String, + eventID: String, + eventName: String, + eventSource: String, + eventSourceArn: String, + eventVersion: String, + invokeIdentityArn: String, + kinesis: KinesisStreamRecordPayload + ): KinesisStreamRecord = + new KinesisStreamRecord( + awsRegion, + eventID, + eventName, + eventSource, + eventSourceArn, + eventVersion, + invokeIdentityArn, + kinesis + ) {} + implicit val decoder: Decoder[KinesisStreamRecord] = Decoder.forProduct8( "awsRegion", "eventID", @@ -65,11 +101,14 @@ object KinesisStreamRecord { )(KinesisStreamRecord.apply) } -final case class KinesisStreamEvent( +sealed abstract case class KinesisStreamEvent private ( records: List[KinesisStreamRecord] ) object KinesisStreamEvent { + private[lambda] def apply(records: List[KinesisStreamRecord]): KinesisStreamEvent = + new KinesisStreamEvent(records) {} + implicit val decoder: Decoder[KinesisStreamEvent] = Decoder.forProduct1("Records")(KinesisStreamEvent.apply) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala index b7c113e1..8b84912c 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala @@ -21,7 +21,7 @@ import io.circe.Decoder // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aws-lambda/trigger/s3-batch.d.ts -final case class S3BatchEvent( +sealed abstract case class S3BatchEvent private ( invocationSchemaVersion: String, invocationId: String, job: S3BatchEventJob, @@ -29,6 +29,19 @@ final case class S3BatchEvent( ) object S3BatchEvent { + private[lambda] def apply( + invocationSchemaVersion: String, + invocationId: String, + job: S3BatchEventJob, + tasks: List[S3BatchEventTask] + ): S3BatchEvent = + new S3BatchEvent( + invocationSchemaVersion, + invocationId, + job, + tasks + ) {} + implicit val decoder: Decoder[S3BatchEvent] = Decoder.forProduct4("invocationSchemaVersion", "invocationId", "job", "tasks")( S3BatchEvent.apply) @@ -36,20 +49,31 @@ object S3BatchEvent { implicit def kernelSource: KernelSource[S3BatchEvent] = KernelSource.emptyKernelSource } -final case class S3BatchEventJob(id: String) +sealed abstract case class S3BatchEventJob private (id: String) object S3BatchEventJob { + private[lambda] def apply(id: String): S3BatchEventJob = + new S3BatchEventJob(id) {} + implicit val decoder: Decoder[S3BatchEventJob] = Decoder.forProduct1("id")(S3BatchEventJob.apply) } -final case class S3BatchEventTask( +sealed abstract case class S3BatchEventTask private ( taskId: String, s3Key: String, s3VersionId: Option[String], - s3BucketArn: String) + s3BucketArn: String +) object S3BatchEventTask { + private[lambda] def apply( + taskId: String, + s3Key: String, + s3VersionId: Option[String], + s3BucketArn: String + ): S3BatchEventTask = new S3BatchEventTask(taskId, s3Key, s3VersionId, s3BucketArn) {} + implicit val decoder: Decoder[S3BatchEventTask] = Decoder.forProduct4("taskId", "s3Key", "s3VersionId", "s3BucketArn")(S3BatchEventTask.apply) } diff --git a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala index c92b29a3..4fd82f38 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala @@ -20,7 +20,7 @@ import io.circe.Encoder // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aws-lambda/trigger/s3-batch.d.ts -final case class S3BatchResult( +sealed abstract case class S3BatchResult private ( invocationSchemaVersion: String, treatMissingKeysAs: S3BatchResultResultCode, invocationId: String, @@ -28,6 +28,14 @@ final case class S3BatchResult( ) object S3BatchResult { + private[lambda] def apply( + invocationSchemaVersion: String, + treatMissingKeysAs: S3BatchResultResultCode, + invocationId: String, + results: List[S3BatchResultResult] + ): S3BatchResult = + new S3BatchResult(invocationSchemaVersion, treatMissingKeysAs, invocationId, results) {} + implicit val encoder: Encoder[S3BatchResult] = Encoder.forProduct4( "invocationSchemaVersion", @@ -37,7 +45,7 @@ object S3BatchResult { (r.invocationSchemaVersion, r.treatMissingKeysAs, r.invocationId, r.results)) } -sealed abstract class S3BatchResultResultCode +sealed abstract class S3BatchResultResultCode extends Product with Serializable object S3BatchResultResultCode { case object Succeeded extends S3BatchResultResultCode @@ -51,12 +59,19 @@ object S3BatchResultResultCode { } } -final case class S3BatchResultResult( +sealed abstract case class S3BatchResultResult private ( taskId: String, resultCode: S3BatchResultResultCode, - resultString: String) + resultString: String +) object S3BatchResultResult { + private[lambda] def apply( + taskId: String, + resultCode: S3BatchResultResultCode, + resultString: String + ): S3BatchResultResult = new S3BatchResultResult(taskId, resultCode, resultString) {} + implicit val encoder: Encoder[S3BatchResultResult] = Encoder.forProduct3("taskId", "resultCode", "resultString")(r => (r.taskId, r.resultCode, r.resultString)) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala index e21a8af7..fb3981ad 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala @@ -26,16 +26,19 @@ import scodec.bits.ByteVector import java.time.Instant import java.util.UUID -final case class SnsEvent( +sealed abstract case class SnsEvent private ( records: List[SnsEventRecord] ) object SnsEvent { + private[lambda] def apply(records: List[SnsEventRecord]): SnsEvent = + new SnsEvent(records) {} + implicit val decoder: Decoder[SnsEvent] = Decoder.forProduct1("Records")(SnsEvent.apply) } -final case class SnsEventRecord( +sealed abstract case class SnsEventRecord private ( eventVersion: String, eventSubscriptionArn: String, eventSource: String, @@ -43,6 +46,14 @@ final case class SnsEventRecord( ) object SnsEventRecord { + private[lambda] def apply( + eventVersion: String, + eventSubscriptionArn: String, + eventSource: String, + sns: SnsMessage + ): SnsEventRecord = + new SnsEventRecord(eventVersion, eventSubscriptionArn, eventSource, sns) {} + implicit val decoder: Decoder[SnsEventRecord] = Decoder.forProduct4( "EventVersion", "EventSubscriptionArn", @@ -51,7 +62,7 @@ object SnsEventRecord { )(SnsEventRecord.apply) } -final case class SnsMessage( +sealed abstract case class SnsMessage private ( signature: String, messageId: UUID, `type`: String, @@ -66,6 +77,33 @@ final case class SnsMessage( ) object SnsMessage { + private[lambda] def apply( + signature: String, + messageId: UUID, + `type`: String, + topicArn: String, + messageAttributes: Map[String, SnsMessageAttribute], + signatureVersion: String, + timestamp: Instant, + signingCertUrl: String, + message: String, + unsubscribeUrl: String, + subject: Option[String] + ): SnsMessage = + new SnsMessage( + signature, + messageId, + `type`, + topicArn, + messageAttributes, + signatureVersion, + timestamp, + signingCertUrl, + message, + unsubscribeUrl, + subject + ) {} + private[this] implicit val instantDecoder: Decoder[Instant] = Decoder.decodeInstant implicit val decoder: Decoder[SnsMessage] = Decoder.forProduct11( @@ -83,18 +121,44 @@ object SnsMessage { )(SnsMessage.apply) } -sealed abstract class SnsMessageAttribute +sealed abstract class SnsMessageAttribute extends Product with Serializable object SnsMessageAttribute { - final case class String(value: Predef.String) extends SnsMessageAttribute - final case class Binary(value: ByteVector) extends SnsMessageAttribute - final case class Number(value: BigDecimal) extends SnsMessageAttribute - final case class StringArray(value: List[SnsMessageAttributeArrayMember]) + sealed abstract case class String private (value: Predef.String) extends SnsMessageAttribute + object String { + private[lambda] def apply(value: Predef.String): String = + new String(value) {} + } + + sealed abstract case class Binary private (value: ByteVector) extends SnsMessageAttribute + object Binary { + private[lambda] def apply(value: ByteVector): Binary = + new Binary(value) {} + } + + sealed abstract case class Number private (value: BigDecimal) extends SnsMessageAttribute + object Number { + private[lambda] def apply(value: BigDecimal): Number = + new Number(value) {} + } + + sealed abstract case class StringArray private (value: List[SnsMessageAttributeArrayMember]) extends SnsMessageAttribute - final case class Unknown( + object StringArray { + private[lambda] def apply(value: List[SnsMessageAttributeArrayMember]): StringArray = + new StringArray(value) {} + } + + sealed abstract case class Unknown private ( `type`: Predef.String, value: Option[Predef.String] ) extends SnsMessageAttribute + object Unknown { + private[lambda] def apply( + `type`: Predef.String, + value: Option[Predef.String] + ): Unknown = new Unknown(`type`, value) {} + } implicit val decoder: Decoder[SnsMessageAttribute] = { val getString: Decoder[Predef.String] = Decoder.instance(_.get[Predef.String]("Value")) @@ -130,9 +194,26 @@ object SnsMessageAttribute { sealed abstract class SnsMessageAttributeArrayMember object SnsMessageAttributeArrayMember { - final case class String(value: Predef.String) extends SnsMessageAttributeArrayMember - final case class Number(value: BigDecimal) extends SnsMessageAttributeArrayMember - final case class Boolean(value: scala.Boolean) extends SnsMessageAttributeArrayMember + sealed abstract case class String private (value: Predef.String) + extends SnsMessageAttributeArrayMember + object String { + private[lambda] def apply(value: Predef.String): String = + new String(value) {} + } + + sealed abstract case class Number private (value: BigDecimal) + extends SnsMessageAttributeArrayMember + object Number { + private[lambda] def apply(value: BigDecimal): Number = + new Number(value) {} + } + + sealed abstract case class Boolean private (value: scala.Boolean) + extends SnsMessageAttributeArrayMember + object Boolean { + private[lambda] def apply(value: scala.Boolean): Boolean = + new Boolean(value) {} + } implicit val decoder: Decoder[SnsMessageAttributeArrayMember] = { val bool: Decoder[SnsMessageAttributeArrayMember.Boolean] = diff --git a/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala index e1043846..71ab8e10 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala @@ -28,16 +28,19 @@ import scala.util.Try // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/aws-lambda/trigger/Sqs.d.ts // https://docs.aws.amazon.com/lambda/latest/dg/invoking-lambda-function.html#supported-event-source-Sqs -final case class SqsEvent( +sealed abstract case class SqsEvent private ( records: List[SqsRecord] ) object SqsEvent { + private[lambda] def apply(records: List[SqsRecord]): SqsEvent = + new SqsEvent(records) {} + implicit val decoder: Decoder[SqsEvent] = Decoder.instance(_.get[List[SqsRecord]]("Records")).map(SqsEvent(_)) } -final case class SqsRecord( +sealed abstract case class SqsRecord( messageId: String, receiptHandle: String, body: String, @@ -50,6 +53,29 @@ final case class SqsRecord( ) object SqsRecord { + private[lambda] def apply( + messageId: String, + receiptHandle: String, + body: String, + attributes: SqsRecordAttributes, + messageAttributes: Map[String, SqsMessageAttribute], + md5OfBody: String, + eventSource: String, + eventSourceArn: String, + awsRegion: String + ): SqsRecord = + new SqsRecord( + messageId, + receiptHandle, + body, + attributes, + messageAttributes, + md5OfBody, + eventSource, + eventSourceArn, + awsRegion + ) {} + implicit val decoder: Decoder[SqsRecord] = Decoder.instance(i => for { messageId <- i.get[String]("messageId") @@ -74,7 +100,7 @@ object SqsRecord { )) } -final case class SqsRecordAttributes( +sealed abstract case class SqsRecordAttributes private ( awsTraceHeader: Option[String], approximateReceiveCount: String, sentTimestamp: Instant, @@ -86,6 +112,26 @@ final case class SqsRecordAttributes( ) object SqsRecordAttributes { + private[lambda] def apply( + awsTraceHeader: Option[String], + approximateReceiveCount: String, + sentTimestamp: Instant, + senderId: String, + approximateFirstReceiveTimestamp: Instant, + sequenceNumber: Option[String], + messageGroupId: Option[String], + messageDeduplicationId: Option[String] + ): SqsRecordAttributes = + new SqsRecordAttributes( + awsTraceHeader, + approximateReceiveCount, + sentTimestamp, + senderId, + approximateFirstReceiveTimestamp, + sequenceNumber, + messageGroupId, + messageDeduplicationId + ) {} implicit val decoder: Decoder[SqsRecordAttributes] = Decoder.instance(i => for { @@ -112,17 +158,38 @@ object SqsRecordAttributes { Kernel(a.awsTraceHeader.map("X-Amzn-Trace-Id" -> _).toMap) } -sealed abstract class SqsMessageAttribute +sealed abstract class SqsMessageAttribute extends Product with Serializable object SqsMessageAttribute { - final case class String(value: Predef.String) extends SqsMessageAttribute + sealed abstract case class String private (value: Predef.String) extends SqsMessageAttribute + object String { + private[lambda] def apply(value: Predef.String): String = + new String(value) {} + } + + sealed abstract case class Binary private (value: ByteVector) extends SqsMessageAttribute + object Binary { + private[lambda] def apply(value: ByteVector): Binary = + new Binary(value) {} + } - final case class Binary(value: ByteVector) extends SqsMessageAttribute - final case class Number(value: BigDecimal) extends SqsMessageAttribute - final case class Unknown( + sealed abstract case class Number private (value: BigDecimal) extends SqsMessageAttribute + object Number { + private[lambda] def apply(value: BigDecimal): Number = + new Number(value) {} + } + + sealed abstract case class Unknown( stringValue: Option[Predef.String], binaryValue: Option[Predef.String], dataType: Predef.String ) extends SqsMessageAttribute + object Unknown { + private[lambda] def apply( + stringValue: Option[Predef.String], + binaryValue: Option[Predef.String], + dataType: Predef.String + ): Unknown = new Unknown(stringValue, binaryValue, dataType) {} + } implicit val decoder: Decoder[SqsMessageAttribute] = { val strValue = From 4a2b2d40d19088c6059bf458e6e0ad542fd1f620 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Sun, 14 Aug 2022 03:46:02 +0000 Subject: [PATCH 2/2] Hide the unapply methods --- .../lambda/events/ApiGatewayProxyEventV2.scala | 4 ++++ .../lambda/events/ApiGatewayProxyResultV2.scala | 2 ++ .../feral/lambda/events/KinesisStreamEvent.scala | 5 +++++ .../scala/feral/lambda/events/S3BatchEvent.scala | 2 ++ .../scala/feral/lambda/events/S3BatchResult.scala | 2 ++ .../main/scala/feral/lambda/events/SnsEvent.scala | 14 ++++++++++++++ .../main/scala/feral/lambda/events/SqsEvent.scala | 10 ++++++++++ 7 files changed, 39 insertions(+) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala index 1fe6612c..7c5fd456 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyEventV2.scala @@ -23,6 +23,7 @@ import natchez.Kernel sealed abstract case class Http private (method: String) object Http { private[lambda] def apply(method: String): Http = new Http(method) {} + private[lambda] def unapply(http: Http): Nothing = ??? implicit val decoder: Decoder[Http] = Decoder.forProduct1("method")(Http.apply) } @@ -30,6 +31,7 @@ object Http { sealed abstract case class RequestContext private (http: Http) object RequestContext { private[lambda] def apply(http: Http): RequestContext = new RequestContext(http) {} + private[lambda] def unapply(requestContext: RequestContext): Nothing = ??? implicit val decoder: Decoder[RequestContext] = Decoder.forProduct1("http")(RequestContext.apply) @@ -65,6 +67,8 @@ object ApiGatewayProxyEventV2 { isBase64Encoded ) {} + private[lambda] def unapply(event: ApiGatewayProxyEventV2): Nothing = ??? + implicit def decoder: Decoder[ApiGatewayProxyEventV2] = Decoder.forProduct7( "rawPath", "rawQueryString", diff --git a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala index 60290c5a..4b5aa553 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/ApiGatewayProxyResultV2.scala @@ -42,6 +42,8 @@ object ApiGatewayProxyStructuredResultV2 { cookies ) {} + private[lambda] def unapply(result: ApiGatewayProxyStructuredResultV2): Nothing = ??? + implicit def encoder: Encoder[ApiGatewayProxyStructuredResultV2] = Encoder.forProduct5( "statusCode", "headers", diff --git a/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala index 6ec8f240..e8c56a57 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/KinesisStreamEvent.scala @@ -47,6 +47,8 @@ object KinesisStreamRecordPayload { sequenceNumber ) {} + private[lambda] def unapply(payload: KinesisStreamRecordPayload): Nothing = ??? + implicit val decoder: Decoder[KinesisStreamRecordPayload] = Decoder.forProduct5( "approximateArrivalTimestamp", "data", @@ -89,6 +91,8 @@ object KinesisStreamRecord { kinesis ) {} + private[lambda] def unapply(record: KinesisStreamRecord): Nothing = ??? + implicit val decoder: Decoder[KinesisStreamRecord] = Decoder.forProduct8( "awsRegion", "eventID", @@ -108,6 +112,7 @@ sealed abstract case class KinesisStreamEvent private ( object KinesisStreamEvent { private[lambda] def apply(records: List[KinesisStreamRecord]): KinesisStreamEvent = new KinesisStreamEvent(records) {} + private[lambda] def unapply(event: KinesisStreamEvent): Nothing = ??? implicit val decoder: Decoder[KinesisStreamEvent] = Decoder.forProduct1("Records")(KinesisStreamEvent.apply) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala index 8b84912c..cae6d467 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchEvent.scala @@ -42,6 +42,8 @@ object S3BatchEvent { tasks ) {} + private[lambda] def unapply(event: S3BatchEvent): Nothing = ??? + implicit val decoder: Decoder[S3BatchEvent] = Decoder.forProduct4("invocationSchemaVersion", "invocationId", "job", "tasks")( S3BatchEvent.apply) diff --git a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala index 4fd82f38..c915f378 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/S3BatchResult.scala @@ -36,6 +36,8 @@ object S3BatchResult { ): S3BatchResult = new S3BatchResult(invocationSchemaVersion, treatMissingKeysAs, invocationId, results) {} + private[lambda] def unapply(result: S3BatchResult): Nothing = ??? + implicit val encoder: Encoder[S3BatchResult] = Encoder.forProduct4( "invocationSchemaVersion", diff --git a/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala index fb3981ad..133ec139 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/SnsEvent.scala @@ -34,6 +34,8 @@ object SnsEvent { private[lambda] def apply(records: List[SnsEventRecord]): SnsEvent = new SnsEvent(records) {} + private[lambda] def unapply(event: SnsEvent): Nothing = ??? + implicit val decoder: Decoder[SnsEvent] = Decoder.forProduct1("Records")(SnsEvent.apply) } @@ -54,6 +56,8 @@ object SnsEventRecord { ): SnsEventRecord = new SnsEventRecord(eventVersion, eventSubscriptionArn, eventSource, sns) {} + private[lambda] def unapply(record: SnsEventRecord): Nothing = ??? + implicit val decoder: Decoder[SnsEventRecord] = Decoder.forProduct4( "EventVersion", "EventSubscriptionArn", @@ -104,6 +108,8 @@ object SnsMessage { subject ) {} + private[lambda] def unapply(message: SnsMessage): Nothing = ??? + private[this] implicit val instantDecoder: Decoder[Instant] = Decoder.decodeInstant implicit val decoder: Decoder[SnsMessage] = Decoder.forProduct11( @@ -128,18 +134,21 @@ object SnsMessageAttribute { object String { private[lambda] def apply(value: Predef.String): String = new String(value) {} + private[lambda] def unapply(string: String): Nothing = ??? } sealed abstract case class Binary private (value: ByteVector) extends SnsMessageAttribute object Binary { private[lambda] def apply(value: ByteVector): Binary = new Binary(value) {} + private[lambda] def unapply(binary: Binary): Nothing = ??? } sealed abstract case class Number private (value: BigDecimal) extends SnsMessageAttribute object Number { private[lambda] def apply(value: BigDecimal): Number = new Number(value) {} + private[lambda] def unapply(number: Number): Nothing = ??? } sealed abstract case class StringArray private (value: List[SnsMessageAttributeArrayMember]) @@ -147,6 +156,7 @@ object SnsMessageAttribute { object StringArray { private[lambda] def apply(value: List[SnsMessageAttributeArrayMember]): StringArray = new StringArray(value) {} + private[lambda] def unapply(stringArray: StringArray): Nothing = ??? } sealed abstract case class Unknown private ( @@ -158,6 +168,7 @@ object SnsMessageAttribute { `type`: Predef.String, value: Option[Predef.String] ): Unknown = new Unknown(`type`, value) {} + private[lambda] def unapply(unknown: Unknown): Nothing = ??? } implicit val decoder: Decoder[SnsMessageAttribute] = { @@ -199,6 +210,7 @@ object SnsMessageAttributeArrayMember { object String { private[lambda] def apply(value: Predef.String): String = new String(value) {} + private[lambda] def unapply(string: String): Nothing = ??? } sealed abstract case class Number private (value: BigDecimal) @@ -206,6 +218,7 @@ object SnsMessageAttributeArrayMember { object Number { private[lambda] def apply(value: BigDecimal): Number = new Number(value) {} + private[lambda] def unapply(number: Number): Nothing = ??? } sealed abstract case class Boolean private (value: scala.Boolean) @@ -213,6 +226,7 @@ object SnsMessageAttributeArrayMember { object Boolean { private[lambda] def apply(value: scala.Boolean): Boolean = new Boolean(value) {} + private[lambda] def unapply(boolean: Boolean): Nothing = ??? } implicit val decoder: Decoder[SnsMessageAttributeArrayMember] = { diff --git a/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala b/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala index 71ab8e10..3df7d997 100644 --- a/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala +++ b/lambda/shared/src/main/scala/feral/lambda/events/SqsEvent.scala @@ -35,6 +35,7 @@ sealed abstract case class SqsEvent private ( object SqsEvent { private[lambda] def apply(records: List[SqsRecord]): SqsEvent = new SqsEvent(records) {} + private[lambda] def unapply(event: SqsEvent): Nothing = ??? implicit val decoder: Decoder[SqsEvent] = Decoder.instance(_.get[List[SqsRecord]]("Records")).map(SqsEvent(_)) @@ -76,6 +77,8 @@ object SqsRecord { awsRegion ) {} + private[lambda] def unapply(record: SqsRecord): Nothing = ??? + implicit val decoder: Decoder[SqsRecord] = Decoder.instance(i => for { messageId <- i.get[String]("messageId") @@ -133,6 +136,8 @@ object SqsRecordAttributes { messageDeduplicationId ) {} + private[lambda] def unapply(attributes: SqsRecordAttributes): Nothing = ??? + implicit val decoder: Decoder[SqsRecordAttributes] = Decoder.instance(i => for { awsTraceHeader <- i.get[Option[String]]("AWSTraceHeader") @@ -164,18 +169,21 @@ object SqsMessageAttribute { object String { private[lambda] def apply(value: Predef.String): String = new String(value) {} + private[lambda] def unapply(string: String): Nothing = ??? } sealed abstract case class Binary private (value: ByteVector) extends SqsMessageAttribute object Binary { private[lambda] def apply(value: ByteVector): Binary = new Binary(value) {} + private[lambda] def unapply(binary: Binary): Nothing = ??? } sealed abstract case class Number private (value: BigDecimal) extends SqsMessageAttribute object Number { private[lambda] def apply(value: BigDecimal): Number = new Number(value) {} + private[lambda] def unapply(number: Number): Nothing = ??? } sealed abstract case class Unknown( @@ -189,6 +197,8 @@ object SqsMessageAttribute { binaryValue: Option[Predef.String], dataType: Predef.String ): Unknown = new Unknown(stringValue, binaryValue, dataType) {} + + private[lambda] def unapply(unknown: Unknown): Nothing = ??? } implicit val decoder: Decoder[SqsMessageAttribute] = {