-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add more cats CollectionAdapter (#284)
- Loading branch information
Showing
7 changed files
with
263 additions
and
0 deletions.
There are no files selected for viewing
43 changes: 43 additions & 0 deletions
43
cats/src/main/scala/scalapb/validate/cats/NonEmptyChainAdapter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package scalapb.validate.cats | ||
|
||
import cats.Foldable | ||
import cats.data.Chain | ||
import cats.data.NonEmptyChain | ||
import scalapb.validate.ValidationException | ||
import scalapb.CollectionAdapter | ||
|
||
class NonEmptyChainAdapter[T] extends CollectionAdapter[T, NonEmptyChain[T]] { | ||
override def foreach(coll: NonEmptyChain[T])(f: T => Unit): Unit = | ||
coll.iterator.foreach(f) | ||
|
||
override def empty: NonEmptyChain[T] = | ||
throw new ValidationException( | ||
"No empty instance available for cats.Data.NonEmptyChain" | ||
) | ||
|
||
override def newBuilder: Builder = | ||
List | ||
.newBuilder[T] | ||
.mapResult(list => | ||
NonEmptyChain | ||
.fromSeq(list) | ||
.toRight( | ||
new ValidationException("Could not build an empty NonEmptyChain") | ||
) | ||
) | ||
|
||
override def concat( | ||
first: NonEmptyChain[T], | ||
second: Iterable[T] | ||
): NonEmptyChain[T] = | ||
first :++ Chain(second.toList: _*) | ||
|
||
override def toIterator(value: NonEmptyChain[T]): Iterator[T] = value.iterator | ||
|
||
override def size(value: NonEmptyChain[T]): Int = | ||
Foldable[NonEmptyChain].size(value).toInt | ||
} | ||
|
||
object NonEmptyChainAdapter { | ||
def apply[T](): NonEmptyChainAdapter[T] = new NonEmptyChainAdapter[T] | ||
} |
42 changes: 42 additions & 0 deletions
42
cats/src/main/scala/scalapb/validate/cats/NonEmptySeqAdapter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package scalapb.validate.cats | ||
|
||
import cats.Foldable | ||
import cats.data.NonEmptySeq | ||
import scalapb.validate.ValidationException | ||
import scalapb.CollectionAdapter | ||
|
||
class NonEmptySeqAdapter[T] extends CollectionAdapter[T, NonEmptySeq[T]] { | ||
override def foreach(coll: NonEmptySeq[T])(f: T => Unit): Unit = | ||
coll.iterator.foreach(f) | ||
|
||
override def empty: NonEmptySeq[T] = | ||
throw new ValidationException( | ||
"No empty instance available for cats.Data.NonEmptySeq" | ||
) | ||
|
||
override def newBuilder: Builder = | ||
List | ||
.newBuilder[T] | ||
.mapResult(list => | ||
NonEmptySeq | ||
.fromSeq(list) | ||
.toRight( | ||
new ValidationException("Could not build an empty NonEmptySeq") | ||
) | ||
) | ||
|
||
override def concat( | ||
first: NonEmptySeq[T], | ||
second: Iterable[T] | ||
): NonEmptySeq[T] = | ||
first.appendSeq(second.toList) | ||
|
||
override def toIterator(value: NonEmptySeq[T]): Iterator[T] = value.iterator | ||
|
||
override def size(value: NonEmptySeq[T]): Int = | ||
Foldable[NonEmptySeq].size(value).toInt | ||
} | ||
|
||
object NonEmptySeqAdapter { | ||
def apply[T](): NonEmptySeqAdapter[T] = new NonEmptySeqAdapter[T] | ||
} |
43 changes: 43 additions & 0 deletions
43
cats/src/main/scala/scalapb/validate/cats/NonEmptyVectorAdapter.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package scalapb.validate.cats | ||
|
||
import cats.Foldable | ||
import cats.data.NonEmptyVector | ||
import scalapb.validate.ValidationException | ||
import scalapb.CollectionAdapter | ||
|
||
class NonEmptyVectorAdapter[T] extends CollectionAdapter[T, NonEmptyVector[T]] { | ||
override def foreach(coll: NonEmptyVector[T])(f: T => Unit): Unit = | ||
coll.iterator.foreach(f) | ||
|
||
override def empty: NonEmptyVector[T] = | ||
throw new ValidationException( | ||
"No empty instance available for cats.Data.NonEmptyVector" | ||
) | ||
|
||
override def newBuilder: Builder = | ||
Vector | ||
.newBuilder[T] | ||
.mapResult(list => | ||
NonEmptyVector | ||
.fromVector(list) | ||
.toRight( | ||
new ValidationException("Could not build an empty NonEmptyVector") | ||
) | ||
) | ||
|
||
override def concat( | ||
first: NonEmptyVector[T], | ||
second: Iterable[T] | ||
): NonEmptyVector[T] = | ||
first.appendVector(second.toVector) | ||
|
||
override def toIterator(value: NonEmptyVector[T]): Iterator[T] = | ||
value.iterator | ||
|
||
override def size(value: NonEmptyVector[T]): Int = | ||
Foldable[NonEmptyVector].size(value).toInt | ||
} | ||
|
||
object NonEmptyVectorAdapter { | ||
def apply[T](): NonEmptyVectorAdapter[T] = new NonEmptyVectorAdapter[T] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
syntax = "proto3"; | ||
|
||
package e2e.cats; | ||
|
||
import "scalapb/scalapb.proto"; | ||
import "validate/validate.proto"; | ||
|
||
option (scalapb.options) = { | ||
scope: FILE | ||
field_transformations: [ | ||
{ | ||
when: { | ||
options { | ||
[validate.rules] { | ||
repeated: {min_items: 1} | ||
} | ||
} | ||
} | ||
set: { | ||
[scalapb.field] { | ||
collection: { | ||
type: "_root_.cats.data.NonEmptyChain" | ||
adapter: "_root_.scalapb.validate.cats.NonEmptyChainAdapter" | ||
non_empty: true | ||
} | ||
} | ||
} | ||
} | ||
] | ||
}; | ||
|
||
message NonEmptyChainTest { | ||
repeated bool values = 1 [(validate.rules).repeated = { min_items: 1 }]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
syntax = "proto3"; | ||
|
||
package e2e.cats; | ||
|
||
import "scalapb/scalapb.proto"; | ||
import "validate/validate.proto"; | ||
|
||
option (scalapb.options) = { | ||
scope: FILE | ||
field_transformations: [ | ||
{ | ||
when: { | ||
options { | ||
[validate.rules] { | ||
repeated: {min_items: 1} | ||
} | ||
} | ||
} | ||
set: { | ||
[scalapb.field] { | ||
collection: { | ||
type: "_root_.cats.data.NonEmptySeq" | ||
adapter: "_root_.scalapb.validate.cats.NonEmptySeqAdapter" | ||
non_empty: true | ||
} | ||
} | ||
} | ||
} | ||
] | ||
}; | ||
|
||
message NonEmptySeqTest { | ||
repeated int32 values = 1 [(validate.rules).repeated = { min_items: 1 }]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
syntax = "proto3"; | ||
|
||
package e2e.cats; | ||
|
||
import "scalapb/scalapb.proto"; | ||
import "validate/validate.proto"; | ||
|
||
option (scalapb.options) = { | ||
scope: FILE | ||
field_transformations: [ | ||
{ | ||
when: { | ||
options { | ||
[validate.rules] { | ||
repeated: {min_items: 1} | ||
} | ||
} | ||
} | ||
set: { | ||
[scalapb.field] { | ||
collection: { | ||
type: "_root_.cats.data.NonEmptyVector" | ||
adapter: "_root_.scalapb.validate.cats.NonEmptyVectorAdapter" | ||
non_empty: true | ||
} | ||
} | ||
} | ||
} | ||
] | ||
}; | ||
|
||
message NonEmptyVectorTest { | ||
repeated string values = 1 [(validate.rules).repeated = { min_items: 1 }]; | ||
} |
33 changes: 33 additions & 0 deletions
33
e2e/src/test/scala/scalapb/validate/cats/NonEmptySpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package scalapb.validate.cats | ||
|
||
import _root_.cats.data.NonEmptyChain | ||
import _root_.cats.data.NonEmptySeq | ||
import _root_.cats.data.NonEmptyVector | ||
import e2e.cats.non_empty_seq.NonEmptySeqTest | ||
import e2e.cats.non_empty_vector.NonEmptyVectorTest | ||
import e2e.cats.non_empty_chain.NonEmptyChainTest | ||
import scalapb.validate.ValidationHelpers | ||
import scalapb.validate.Validator | ||
|
||
class NonEmptySpec extends munit.FunSuite with ValidationHelpers { | ||
test("NonEmptySeq serialize and parse successfully") { | ||
val x = NonEmptySeqTest.of(NonEmptySeq.of(1, 2, 3)) | ||
assertEquals(NonEmptySeqTest.parseFrom(x.toByteArray), x) | ||
assertEquals(NonEmptySeqTest.fromAscii(x.toProtoString), x) | ||
assert(Validator[NonEmptySeqTest].validate(x).isSuccess) | ||
} | ||
|
||
test("NonEmptyVector serialize and parse successfully") { | ||
val x = NonEmptyVectorTest.of(NonEmptyVector.of("a", "b", "c")) | ||
assertEquals(NonEmptyVectorTest.parseFrom(x.toByteArray), x) | ||
assertEquals(NonEmptyVectorTest.fromAscii(x.toProtoString), x) | ||
assert(Validator[NonEmptyVectorTest].validate(x).isSuccess) | ||
} | ||
|
||
test("NonEmptyChain serialize and parse successfully") { | ||
val x = NonEmptyChainTest.of(NonEmptyChain.of(true, false)) | ||
assertEquals(NonEmptyChainTest.parseFrom(x.toByteArray), x) | ||
assertEquals(NonEmptyChainTest.fromAscii(x.toProtoString), x) | ||
assert(Validator[NonEmptyChainTest].validate(x).isSuccess) | ||
} | ||
} |