diff --git a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala index 88f7b62e7..327b66f7d 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/ElasticRequest.scala @@ -12,13 +12,14 @@ sealed trait ElasticRequest[+A] { self => final def map[B](f: A => B): ElasticRequest[B] = ElasticRequest.Map(self, f) + // todo: Error for Routing.make Left final def routing(value: String): ElasticRequest[A] = self match { case Map(request, mapper) => Map(request.routing(value), mapper) - case r: Create => r.copy(routing = Some(Routing(value))).asInstanceOf[ElasticRequest[A]] - case r: CreateOrUpdate => r.copy(routing = Some(Routing(value))).asInstanceOf[ElasticRequest[A]] - case r: Exists => r.copy(routing = Some(Routing(value))).asInstanceOf[ElasticRequest[A]] - case r: GetById => r.copy(routing = Some(Routing(value))).asInstanceOf[ElasticRequest[A]] + case r: Create => r.copy(routing = Routing.make(value).toOption).asInstanceOf[ElasticRequest[A]] + case r: CreateOrUpdate => r.copy(routing = Routing.make(value).toOption).asInstanceOf[ElasticRequest[A]] + case r: Exists => r.copy(routing = Routing.make(value).toOption).asInstanceOf[ElasticRequest[A]] + case r: GetById => r.copy(routing = Routing.make(value).toOption).asInstanceOf[ElasticRequest[A]] case _ => self } } diff --git a/modules/library/src/main/scala/zio/elasticsearch/package.scala b/modules/library/src/main/scala/zio/elasticsearch/package.scala index 7557bbcec..3b2d56e9a 100644 --- a/modules/library/src/main/scala/zio/elasticsearch/package.scala +++ b/modules/library/src/main/scala/zio/elasticsearch/package.scala @@ -1,20 +1,48 @@ package zio import zio.prelude.Assertion._ -import zio.prelude.{Newtype, Subtype} +import zio.prelude.{AssertionError, Newtype} +import zio.prelude.QuotedAssertion package object elasticsearch { - object Routing extends Subtype[String] { - override def assertion = assert { + object Routing extends Newtype[String] { + override def assertion: QuotedAssertion[String] = assert { !isEmptyString } } type Routing = Routing.Type - object DocumentId extends Newtype[String] + object DocumentId extends Newtype[String] {} type DocumentId = DocumentId.Type - object IndexName extends Newtype[String] + object IndexName extends Newtype[String] { + override def assertion: QuotedAssertion[String] = assertCustom { (x: String) => + if (x.toLowerCase != x) Left(AssertionError.Failure("IndexName must be lower case only.")) + else if (x.startsWith("-") || x.startsWith("+") || x.startsWith("_")) + Left(AssertionError.Failure("IndexName cannot start with -, _, +.")) + else if (x.exists(char => raw"""\/*?"<>|,#""".contains(char)) || x.contains(' ')) + Left( + AssertionError.Failure( + "IndexName cannot include \\, /, *, ?, \", <, >, |, ` ` (space character), ,(comma), #" + ) + ) + else if (x.contains(':')) + Left(AssertionError.Failure("""IndexName cannot include ":"(since 7.0).""")) + else if (x == "." || x == "..") + Left(AssertionError.Failure("""IndexName cannot be . or ..""")) + else if (x.getBytes().length > 255) + Left( + AssertionError.Failure( + """IndexName cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit faster)""" + ) + ) + else if (x.startsWith(".")) { + // todo: Warning should be that IndexNames starting with . are deprecated? + Right(()) + } else + Right(()) + } + } type IndexName = IndexName.Type }