Skip to content

Commit

Permalink
implement Bytes operations as a subet of String operations
Browse files Browse the repository at this point in the history
  • Loading branch information
lihaoyi committed Dec 10, 2023
1 parent 08326f8 commit f173d38
Show file tree
Hide file tree
Showing 14 changed files with 471 additions and 89 deletions.
209 changes: 209 additions & 0 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -8316,6 +8316,215 @@ Db("Hello").replace("ll", "rr")



## DbBlobOps
Operations that can be performed on `Db[Bytes]`
### DbBlobOps.plus



```scala
Db(Bytes("hello")) + Db(Bytes("world"))
```


*
```sql
SELECT (? || ?) AS res
```



*
```scala
Bytes("helloworld")
```



### DbBlobOps.like



```scala
Db(Bytes("hello")).like(Bytes("he%"))
```


*
```sql
SELECT (? LIKE ?) AS res
```



*
```scala
true
```



### DbBlobOps.length



```scala
Db(Bytes("hello")).length
```


*
```sql
SELECT LENGTH(?) AS res
```



*
```scala
5
```



### DbBlobOps.octetLength



```scala
Db(Bytes("叉烧包")).octetLength
```


*
```sql
SELECT OCTET_LENGTH(?) AS res
```



*
```scala
9
```



### DbBlobOps.position



```scala
Db(Bytes("hello")).indexOf(Bytes("ll"))
```


*
```sql
SELECT POSITION(? IN ?) AS res
```



*
```scala
3
```



### DbBlobOps.substring



```scala
Db(Bytes("Hello")).substring(2, 2)
```


*
```sql
SELECT SUBSTRING(?, ?, ?) AS res
```



*
```scala
Bytes("el")
```



### DbBlobOps.startsWith



```scala
Db(Bytes("Hello")).startsWith(Bytes("Hel"))
```


*
```sql
SELECT (? LIKE ? || '%') AS res
```



*
```scala
true
```



### DbBlobOps.endsWith



```scala
Db(Bytes("Hello")).endsWith(Bytes("llo"))
```


*
```sql
SELECT (? LIKE '%' || ?) AS res
```



*
```scala
true
```



### DbBlobOps.contains



```scala
Db(Bytes("Hello")).contains(Bytes("ll"))
```


*
```sql
SELECT (? LIKE '%' || ? || '%') AS res
```



*
```scala
true
```



## DbMathOps
Math operations; supported by H2/Postgres/MySql, not supported by Sqlite
### DbMathOps.power
Expand Down
48 changes: 48 additions & 0 deletions scalasql/operations/src/DbStringLikeOps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package scalasql.operations
import scalasql.core.Db
import scalasql.core.SqlStr.SqlStringSyntax

abstract class DbStringLikeOps[T](v: Db[T]) {

/** Concatenates two strings */
def +(x: Db[T]): Db[T] = Db { implicit ctx => sql"($v || $x)" }

/** TRUE if the operand matches a pattern */
def like(x: Db[T]): Db[Boolean] = Db { implicit ctx => sql"($v LIKE $x)" }

/** Returns an integer value representing the starting position of a string within the search string. */
def indexOf(x: Db[T]): Db[Int]

/** Converts a string to all lowercase characters. */
def toLowerCase: Db[T] = Db { implicit ctx => sql"LOWER($v)" }

/** Converts a string to all uppercase characters. */
def toUpperCase: Db[T] = Db { implicit ctx => sql"UPPER($v)" }

/** Returns the number of characters in this string */
def length: Db[Int] = Db { implicit ctx => sql"LENGTH($v)" }

/** Returns the number of bytes in this string */
def octetLength: Db[Int] = Db { implicit ctx => sql"OCTET_LENGTH($v)" }

/** Returns a portion of a string. */
def substring(start: Db[Int], length: Db[Int]): Db[T] = Db { implicit ctx =>
sql"SUBSTRING($v, $start, $length)"
}

/** Returns whether or not this strings starts with the other. */
def startsWith(other: Db[T]): Db[Boolean] = Db { implicit ctx =>
sql"($v LIKE $other || '%')"
}

/** Returns whether or not this strings ends with the other. */
def endsWith(other: Db[T]): Db[Boolean] = Db { implicit ctx =>
sql"($v LIKE '%' || $other)"
}

/** Returns whether or not this strings contains the other. */
def contains(other: Db[T]): Db[Boolean] = Db { implicit ctx =>
sql"($v LIKE '%' || $other || '%')"
}

}
52 changes: 6 additions & 46 deletions scalasql/operations/src/DbStringOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,23 @@ package scalasql.operations
import scalasql.core.Db
import scalasql.core.SqlStr.SqlStringSyntax

abstract class DbStringOps(v: Db[String]) {

/** Concatenates two strings */
def +(x: Db[String]): Db[String] = Db { implicit ctx => sql"($v || $x)" }

/** TRUE if the operand matches a pattern */
def like[T](x: Db[T]): Db[Boolean] = Db { implicit ctx => sql"($v LIKE $x)" }

/** Returns an integer value representing the starting position of a string within the search string. */
def indexOf(x: Db[String]): Db[Int]

/** Converts a string to all lowercase characters. */
def toLowerCase: Db[String] = Db { implicit ctx => sql"LOWER($v)" }

/** Converts a string to all uppercase characters. */
def toUpperCase: Db[String] = Db { implicit ctx => sql"UPPER($v)" }
trait DbStringOps[T] {
protected def v: Db[T]

/** Removes leading and trailing whitespace characters from a character string. */
def trim: Db[String] = Db { implicit ctx => sql"TRIM($v)" }

/** Returns the number of characters in this string */
def length: Db[Int] = Db { implicit ctx => sql"LENGTH($v)" }

/** Returns the number of bytes in this string */
def octetLength: Db[Int] = Db { implicit ctx => sql"OCTET_LENGTH($v)" }
def trim: Db[T] = Db { implicit ctx => sql"TRIM($v)" }

/** Removes leading whitespace characters from a character string. */
def ltrim: Db[String] = Db { implicit ctx => sql"LTRIM($v)" }
def ltrim: Db[T] = Db { implicit ctx => sql"LTRIM($v)" }

/** Removes trailing whitespace characters from a character string. */
def rtrim: Db[String] = Db { implicit ctx => sql"RTRIM($v)" }

/** Returns a portion of a string. */
def substring(start: Db[Int], length: Db[Int]): Db[String] = Db { implicit ctx =>
sql"SUBSTRING($v, $start, $length)"
}

/** Returns whether or not this strings starts with the other. */
def startsWith(other: Db[String]): Db[Boolean] = Db { implicit ctx =>
sql"($v LIKE $other || '%')"
}

/** Returns whether or not this strings ends with the other. */
def endsWith(other: Db[String]): Db[Boolean] = Db { implicit ctx =>
sql"($v LIKE '%' || $other)"
}

/** Returns whether or not this strings contains the other. */
def contains(other: Db[String]): Db[Boolean] = Db { implicit ctx =>
sql"($v LIKE '%' || $other || '%')"
}
def rtrim: Db[T] = Db { implicit ctx => sql"RTRIM($v)" }

/**
* The replace(X,Y,Z) function returns a string formed by substituting string Z
* for every occurrence of string Y in string X
*/
def replace(y: Db[String], z: Db[String]): Db[String] = Db { implicit ctx =>
def replace(y: Db[T], z: Db[T]): Db[T] = Db { implicit ctx =>
sql"REPLACE($v, $y, $z)"
}

Expand Down
2 changes: 1 addition & 1 deletion scalasql/operations/src/PadOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import scalasql.core.Db
import scalasql.core.SqlStr.SqlStringSyntax

trait PadOps {
protected def v: Db[String]
protected def v: Db[_]

def rpad(length: Db[Int], fill: Db[String]): Db[String] = Db { implicit ctx =>
sql"RPAD($v, $length, $fill)"
Expand Down
2 changes: 1 addition & 1 deletion scalasql/operations/src/TrimOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import scalasql.core.Db
import scalasql.core.SqlStr.SqlStringSyntax

trait TrimOps {
protected def v: Db[String]
protected def v: Db[_]

/**
* Trim [[x]]s from the left hand side of the string [[v]]
Expand Down
5 changes: 4 additions & 1 deletion scalasql/src/dialects/Dialect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,10 @@ trait Dialect extends DialectTypeMappers {
): operations.DbOptionOps[T] =
new operations.DbOptionOps(JoinNullable.toExpr(v))

implicit def DbStringOpsConv(v: Db[String]): operations.DbStringOps
implicit def DbStringOpsConv(
v: Db[String]
): operations.DbStringLikeOps[String] with operations.DbStringOps[String]
implicit def DbBlobOpsConv(v: Db[geny.Bytes]): operations.DbStringLikeOps[geny.Bytes]

implicit def AggNumericOpsConv[V: Numeric: TypeMapper](v: Aggregatable[Db[V]])(
implicit qr: Queryable.Row[Db[V], V]
Expand Down
13 changes: 9 additions & 4 deletions scalasql/src/dialects/H2Dialect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ trait H2Dialect extends Dialect {
override def put(r: PreparedStatement, idx: Int, v: T): Unit = r.setString(idx, v.toString)
}

override implicit def DbStringOpsConv(v: Db[String]): H2Dialect.DbStringOps =
override implicit def DbStringOpsConv(v: Db[String]): H2Dialect.DbStringOps[String] =
new H2Dialect.DbStringOps(v)

override implicit def DbBlobOpsConv(v: Db[geny.Bytes]): H2Dialect.DbStringLikeOps[geny.Bytes] =
new H2Dialect.DbStringLikeOps(v)

override implicit def DbNumericOpsConv[T: Numeric: TypeMapper](
v: Db[T]
): H2Dialect.DbNumericOps[T] = new H2Dialect.DbNumericOps(v)
Expand Down Expand Up @@ -89,11 +93,12 @@ object H2Dialect extends H2Dialect {
}
}

class DbStringOps(protected val v: Db[String])
extends operations.DbStringOps(v)
class DbStringOps[T](v: Db[T]) extends DbStringLikeOps(v) with operations.DbStringOps[T]
class DbStringLikeOps[T](protected val v: Db[T])
extends operations.DbStringLikeOps(v)
with TrimOps
with PadOps {
def indexOf(x: Db[String]): Db[Int] = Db { implicit ctx => sql"INSTR($v, $x)" }
def indexOf(x: Db[T]): Db[Int] = Db { implicit ctx => sql"INSTR($v, $x)" }
}

class DbNumericOps[T: Numeric: TypeMapper](protected val v: Db[T])
Expand Down
Loading

0 comments on commit f173d38

Please sign in to comment.