diff --git a/build.sbt b/build.sbt index 12c7817e..269765e7 100644 --- a/build.sbt +++ b/build.sbt @@ -138,7 +138,10 @@ lazy val core = crossProject(JVMPlatform) ) } }, - mimaBinaryIssueFilters ++= Nil + mimaBinaryIssueFilters ++= List( + ProblemFilters.exclude[DirectMissingMethodProblem]("no.nrk.bigquery.BQDataset.of"), + ProblemFilters.exclude[DirectMissingMethodProblem]("no.nrk.bigquery.BQDataset.unsafeOf") + ) ) .disablePlugins(TypelevelCiSigningPlugin, Sonatype, SbtGpg) diff --git a/core/src/main/scala/no/nrk/bigquery/BQDataset.scala b/core/src/main/scala/no/nrk/bigquery/BQDataset.scala index 75d916f0..4135187c 100644 --- a/core/src/main/scala/no/nrk/bigquery/BQDataset.scala +++ b/core/src/main/scala/no/nrk/bigquery/BQDataset.scala @@ -20,15 +20,18 @@ final case class BQDataset private[bigquery] ( def underlying: DatasetId = DatasetId.of(project.value, id) def withLocation(locationId: LocationId): BQDataset = copy(location = Some(locationId)) + def withoutLocation: BQDataset = copy(location = None) + def withId(id: String): BQDataset = copy(id = id) + def withProject(project: ProjectId): BQDataset = copy(project = project) } object BQDataset { private val regex: Pattern = "^[a-zA-Z0-9_]{1,1024}".r.pattern - def unsafeOf(project: ProjectId, dataset: String) = - of(project, dataset).fold(err => throw new IllegalArgumentException(err), identity) + def unsafeOf(project: ProjectId, dataset: String, location: Option[LocationId] = None) = + of(project, dataset, location).fold(err => throw new IllegalArgumentException(err), identity) - def of(project: ProjectId, dataset: String): Either[String, BQDataset] = - if (regex.matcher(dataset).matches()) Right(BQDataset(project, dataset, None)) + def of(project: ProjectId, dataset: String, location: Option[LocationId] = None): Either[String, BQDataset] = + if (regex.matcher(dataset).matches()) Right(BQDataset(project, dataset, location)) else Left(s"invalid project ID '$dataset' - must match ${regex.pattern()}") } diff --git a/core/src/main/scala/no/nrk/bigquery/BQTableId.scala b/core/src/main/scala/no/nrk/bigquery/BQTableId.scala index b1c9b948..0b80fcd0 100644 --- a/core/src/main/scala/no/nrk/bigquery/BQTableId.scala +++ b/core/src/main/scala/no/nrk/bigquery/BQTableId.scala @@ -29,7 +29,7 @@ final case class BQTableId private[bigquery] (dataset: BQDataset, tableName: Str object BQTableId { - private val regex: Pattern = "(?U)^\\w[\\w_ -]{1,1023}".r.pattern + private val regex: Pattern = "(?U)^\\w[\\w_ *$-]{1,1023}".r.pattern def of(dataset: BQDataset, tableName: String): Either[String, BQTableId] = if (regex.matcher(tableName).matches()) Right(BQTableId(dataset, tableName)) @@ -38,6 +38,9 @@ object BQTableId { def unsafeOf(dataset: BQDataset, tableName: String): BQTableId = of(dataset, tableName).fold(err => throw new IllegalArgumentException(err), identity) + def unsafeFrom(project: ProjectId, dataset: String, tableName: String): BQTableId = + unsafeFromString(s"${project.value}.${dataset}.${tableName}") + def unsafeFromGoogle(dataset: BQDataset, tableId: TableId): BQTableId = { require( tableId.getProject == dataset.project.value && dataset.id == tableId.getDataset, diff --git a/core/src/test/scala/no/nrk/bigquery/BQTableIdTest.scala b/core/src/test/scala/no/nrk/bigquery/BQTableIdTest.scala index af4f61ae..2df1a9fd 100644 --- a/core/src/test/scala/no/nrk/bigquery/BQTableIdTest.scala +++ b/core/src/test/scala/no/nrk/bigquery/BQTableIdTest.scala @@ -20,4 +20,13 @@ class BQTableIdTest extends munit.ScalaCheckSuite { assertEquals(obtained, Right(BQTableId(BQDataset(ProjectId(project), dataset, None), table))) } } + + test("examples must work") { + val ids = List("cloudaudit_googleapis_com_data_access_*", "service_daily_example_v01$20200801") + + for (id <- ids) { + val obtained = BQTableId.of(dataset, id) + assertEquals(obtained, Right(BQTableId(dataset, id))) + } + } } diff --git a/core/src/test/scala/no/nrk/bigquery/Generators.scala b/core/src/test/scala/no/nrk/bigquery/Generators.scala index 83206179..b93e4be3 100644 --- a/core/src/test/scala/no/nrk/bigquery/Generators.scala +++ b/core/src/test/scala/no/nrk/bigquery/Generators.scala @@ -13,12 +13,12 @@ object Generators { val validProjectIdGen = for { firstchar <- Gen.stringOfN(1, Gen.alphaLowerChar) - maybedash <- Gen.oneOf("", "-") + maybeSymbol <- Gen.oneOf("", "-") alphaNumLower = Gen.oneOf(Gen.alphaLowerChar, Gen.numChar) - afterdash <- Gen.stringOfN(6 - maybedash.length, alphaNumLower) + afterdash <- Gen.stringOfN(6 - maybeSymbol.length, alphaNumLower) lastChars <- Generators - .shorterThan(29 - (1 + afterdash.length + maybedash.length), Gen.stringOf(alphaNumLower)) - } yield firstchar + maybedash + afterdash + lastChars + .shorterThan(29 - (1 + afterdash.length + maybeSymbol.length), Gen.stringOf(alphaNumLower)) + } yield firstchar + maybeSymbol + afterdash + lastChars val validDatasetIdGen = for { alpha <- Generators.shorterThanAlphaNum(1021).filterNot(_.isEmpty) @@ -31,7 +31,7 @@ object Generators { .stringOfN(1, unicodeIdentifierPart) .map(_.replaceAll("(?U)\\W", "")) .map(s => if (s.isEmpty) "a" else s) - choose <- Gen.oneOf("", " ", "-", "_") + choose <- Gen.oneOf("", " ", "-", "_", "$", "*") next <- Generators.shorterThan( 1022, Gen.stringOf(unicodeIdentifierPart).map(_.replaceAll("(?U)\\W", "")).filter(_.nonEmpty))