-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
423 additions
and
37 deletions.
There are no files selected for viewing
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
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
9 changes: 9 additions & 0 deletions
9
ce3/src/main/scala/scalacheck/extrasyntax/ArbitraryFromGen.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,9 @@ | ||
package scalacheck.extrasyntax | ||
|
||
import org.scalacheck.{Arbitrary, Gen} | ||
|
||
trait ArbitraryFromGen { | ||
|
||
implicit def genArbitrary[A](implicit gen: Gen[A]): Arbitrary[A] = Arbitrary(gen) | ||
|
||
} |
28 changes: 28 additions & 0 deletions
28
ce3/src/main/scala/scalacheck/extrasyntax/GenExtraSyntax.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,28 @@ | ||
package scalacheck.extrasyntax | ||
|
||
import org.scalacheck.Gen | ||
|
||
trait GenExtraSyntax { | ||
|
||
private object impl { | ||
def const[A](ga: Gen[A]): Gen[A] = Gen.const(ga.sample.get) | ||
} | ||
|
||
implicit class GenOps2[A](ga: Gen[A]) { | ||
|
||
/** make Any generator constant TO ONE VALUE */ | ||
def const: Gen[A] = impl.const(ga) | ||
|
||
/** make CONSTANT LIST from Any generator */ | ||
def constListOfN(n: Int): Gen[List[A]] = impl.const(Gen.listOfN(n, ga)) | ||
|
||
/** take random element from {{{Gen[Seq[A]]}}} and produce {{{Gen[A]}}} */ | ||
def oneOf[B](implicit ev: A <:< Seq[B]): Gen[B] = ga.map(ev).flatMap(x => Gen.oneOf(x)) | ||
|
||
def notPresentIn(as: Seq[A]): Gen[A] = ga.retryUntil(a => !as.contains(a)) | ||
|
||
def notPresentIn(gas: Gen[Seq[A]]): Gen[A] = notPresentIn(gas.sample.get) | ||
|
||
} | ||
|
||
} |
70 changes: 70 additions & 0 deletions
70
ce3/src/main/scala/scalacheck/extrasyntax/GenExtraSyntaxTest.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,70 @@ | ||
package scalacheck.extrasyntax | ||
|
||
import org.scalacheck.Gen | ||
import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks | ||
|
||
class GenExtraSyntaxTest extends BootstrapFunSuite with ScalaCheckDrivenPropertyChecks with ArbitraryFromGen with GenExtraSyntax { | ||
|
||
override implicit val generatorDrivenConfig: PropertyCheckConfiguration = PropertyCheckConfiguration(minSuccessful = 25) | ||
|
||
val tenCharsId = Gen.listOfN(10, Gen.alphaChar).map(_.mkString) | ||
|
||
test(".const syntax provides always constant value") { | ||
implicit val g: Gen[String] = tenCharsId.const | ||
|
||
forAll { (x: String) => | ||
pprint.pprintln(x) | ||
x shouldBe g.sample.value | ||
} | ||
} | ||
|
||
test(".constListOfN(...) syntax provides always constant value of a List[A]") { | ||
implicit val g: Gen[List[String]] = tenCharsId.constListOfN(5) | ||
|
||
forAll { (x: List[String]) => | ||
pprint.pprintln(x) | ||
x shouldBe g.sample.value | ||
} | ||
} | ||
|
||
test(".oneOf syntax provides always constant value from the Gen[Geq[A]] given") { | ||
// always the same list | ||
val gs: Gen[List[String]] = tenCharsId.constListOfN(5) | ||
// element from the list | ||
implicit val g: Gen[String] = gs.oneOf | ||
|
||
forAll { (x: String) => | ||
pprint.pprintln(x) | ||
gs.sample.value should contain(x) | ||
} | ||
|
||
pprint.pprintln(gs.sample.value) | ||
} | ||
|
||
test(".notPresentIn - allows to reuse generator, but with a guarantee not have a duplicate one") { | ||
|
||
/** Int: 1..10 */ | ||
val g0: Gen[Int] = Gen.choose(1, 10) | ||
|
||
/** List[Int] max length = 9 */ | ||
val g1: Gen[List[Int]] = Gen.listOfN(10, g0).map(_.distinct.sorted) | ||
|
||
/** Int: 1..10 but never in the list */ | ||
val g2 = g0.notPresentIn _ | ||
|
||
implicit val gtuple: Gen[(List[Int], Int)] = for { | ||
xs <- g1 // list | ||
x <- g2(xs) // element not presented in the list | ||
} yield (xs, x) | ||
|
||
forAll { t: (List[Int], Int) => | ||
t match { | ||
case (xs, x) => | ||
pprint.pprintln((xs, x)) | ||
xs shouldNot contain(x) | ||
} | ||
} | ||
|
||
} | ||
|
||
} |
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,89 @@ | ||
package slickvt | ||
|
||
import akka.NotUsed | ||
import akka.stream.scaladsl.Source | ||
import model._ | ||
import slick.jdbc.PostgresProfile.api.{Tag => _, _} | ||
import slick.lifted.Rep | ||
import slickvt.model.TagFilter.{ExcludesOnly, IncludesAndExcludes, IncludesOnly} | ||
import slickvt.model.TargetStrategies._ | ||
|
||
trait Impl extends StreamOps with SlickStreamingQueryOps { | ||
|
||
private def negateBy(strategy: TargetStrategy): Rep[Boolean] => Rep[Boolean] = | ||
if (strategy == Exclude) !_ else identity | ||
|
||
private def whereCountry(query: ProfileTable, country: CountryFilter) = country match { | ||
case CountryFilter(Seq(), _) => query.country.isDefined | ||
case CountryFilter(countries, strategy) => query.country | ||
.map { country => negateBy(strategy)(country inSet countries) } | ||
.getOrElse(LiteralColumn(false)) | ||
} | ||
|
||
private def whereAffiliate(profiles: ProfileTable, affiliate: AffiliateFilter) = affiliate match { | ||
case AffiliateFilter(Seq(), _) => LiteralColumn(true) | ||
case AffiliateFilter(affiliates, strategy) => profiles.affiliateId | ||
.map { id => negateBy(strategy)(id inSet affiliates) } | ||
.getOrElse(LiteralColumn(strategy == Exclude)) | ||
} | ||
|
||
private def wherePlayerUuids(profiles: ProfileTable, playerUuids: PlayerUuidFilter) = | ||
profiles.playerUUID inSet playerUuids.includeUuids | ||
|
||
def qCond(p: Boolean)(r: Rep[Boolean]): Rep[Boolean] = if (p) r else !r | ||
|
||
private def mkTagWhereClause(rqTags: Seq[PTag])(tags: TagTable): Rep[Boolean] = | ||
rqTags.groupMap(_.rank)(_.tagId) | ||
.map { case (rank, tagIds) => (tags.rank === rank) && (tags.tagId inSet tagIds) } | ||
.reduce(_ || _) | ||
|
||
def mkProfilesFilter(request: RQuery) = | ||
ProfileTable.profiles // case class RQuery( | ||
.filter(_.brandId === request.brandId) // brandId: String, | ||
.filter(profiles => qCond(request.isTest)(profiles.playerUUID.like(TestPattern))) // isTest: Boolean = false | ||
.filterOpt(request.affiliateFilter)(whereAffiliate) // affiliateFilter: Option[AffiliateFilter] = None | ||
.filterOpt(request.countryFilter)(whereCountry) // countryFilter: Option[CountryFilter] = None | ||
.filterOpt(request.playerUuidFilter)(wherePlayerUuids) // playerUuidFilter: Option[PlayerUuidFilter] = None | ||
.filterOpt(request.playerId)(_.playerUUID === _) // playerId: Option[String] = None | ||
|
||
private def mkTagsFilter(request: RQuery): Query[TagTable, Tag, Seq] = | ||
TagTable.tags | ||
.filter(_.brandId === request.brandId) | ||
.filterOpt(request.playerUuidFilter)(_.playerUUID inSet _.includeUuids) | ||
.filterOpt(request.playerId)(_.playerUUID === _) | ||
|
||
|
||
private def doFindProfilesWithTags(request: RQuery) = { | ||
val profilesFiltered = mkProfilesFilter(request) | ||
val tagsFiltered = mkTagsFilter(request) | ||
|
||
val tagsFiltered2 = request.tagFilter match { | ||
case Some(IncludesOnly(includes)) => | ||
tagsFiltered | ||
.filter(mkTagWhereClause(includes)) | ||
case Some(ExcludesOnly(excludes)) => | ||
tagsFiltered | ||
.filterNot(mkTagWhereClause(excludes)) | ||
case Some(IncludesAndExcludes(includes, excludes)) => | ||
tagsFiltered | ||
.filter(mkTagWhereClause(includes)) | ||
.filterNot(mkTagWhereClause(excludes)) | ||
case _ => | ||
tagsFiltered | ||
} | ||
|
||
profilesFiltered | ||
.joinLeft(tagsFiltered2).on(_.playerUUID === _.playerUUID) | ||
.map{ case (p, ots) => p -> ots.map(t => t.tagId -> t.rank)} | ||
.sortBy { case (p, _) => p.playerUUID } | ||
.result | ||
} | ||
|
||
def findProfilesWithTagsSource(request: RQuery) = { | ||
val s = runStream(doFindProfilesWithTags(request)) | ||
|
||
regroupSequentialAfterJoin(s)(_._1)(_._2) | ||
.map { case (p, ts) => p -> ts.flatten } | ||
} | ||
|
||
} |
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
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,31 @@ | ||
package slickvt | ||
|
||
import akka.actor.ActorSystem | ||
import akka.stream.ActorMaterializer | ||
import cats.implicits._ | ||
import slick.jdbc.PostgresProfile.api.{Tag => _, _} | ||
import slickvt.model._ | ||
|
||
object Launcher2 extends App with Impl { | ||
|
||
implicit val system = ActorSystem() | ||
implicit val mat = ActorMaterializer() | ||
|
||
val rq = RQuery(brandId = "bccashgames", | ||
tagFilter = TagFilter( | ||
includeTags = Seq( | ||
PTag("TAG-completed",0), | ||
PTag("TAG-promo_test",0), | ||
PTag("TAG-testcampaign",0), | ||
), | ||
excludeTags = Seq(), | ||
).some, | ||
// playerId = "PLAYER-fea4a1cf-c83d-40dc-803a-60f46a813390".some | ||
) | ||
|
||
findProfilesWithTagsSource(rq) | ||
.filter{case(_,ts)=>ts.size > 1} | ||
// .take(1) | ||
.runForeach(x => pprint.pprintln(x)) | ||
|
||
} |
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
Oops, something went wrong.