Skip to content

Commit 979edb0

Browse files
committed
add 0-based array indexing
1 parent f4f6b9f commit 979edb0

File tree

3 files changed

+39
-1
lines changed

3 files changed

+39
-1
lines changed

src/main/scala/tyql/expr/Expr.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,14 +320,15 @@ object Expr:
320320
assert(strs.nonEmpty, "concatWith requires at least one argument")
321321
StrConcatSeparator(sep, strs.head, strs.tail)
322322

323-
extension [A](x: Expr[List[A], NonScalarExpr])(using ResultTag[List[A]])
323+
extension [A](x: Expr[List[A], NonScalarExpr])(using ResultTag[A], ResultTag[List[A]])
324324
def prepend(elem: Expr[A, NonScalarExpr]): Expr[List[A], NonScalarExpr] = ListPrepend(elem, x)
325325
def append(elem: Expr[A, NonScalarExpr]): Expr[List[A], NonScalarExpr] = ListAppend(x, elem)
326326
// XXX Due to Scala overloading bugs, there can be no two extensions methods named `contains` with similar arguments.
327327
// XXX Because the list one is less used, this one is called `containsElement` instead.
328328
def containsElement(elem: Expr[A, NonScalarExpr]): Expr[Boolean, NonScalarExpr] = ListContains(x, elem)
329329
def length: Expr[Int, NonScalarExpr] = ListLength(x)
330330
def ++(other: Expr[List[A], NonScalarExpr]): Expr[List[A], NonScalarExpr] = ListConcat(x, other)
331+
def apply(i: Expr[Int, NonScalarExpr]): Expr[A, NonScalarExpr] = ListGet(x, Expr.Plus(i, Expr.IntLit(1)))
331332

332333
// Aggregations
333334
def sum[T : ResultTag : Numeric](x: Expr[T, ?]): AggregationExpr[T] = AggregationExpr.Sum(x)
@@ -524,6 +525,8 @@ object Expr:
524525
case class ListContains[A]($list: Expr[List[A], NonScalarExpr], $x: Expr[A, NonScalarExpr])(using ResultTag[Boolean])
525526
extends Expr[Boolean, NonScalarExpr]
526527
case class ListLength[A]($list: Expr[List[A], NonScalarExpr])(using ResultTag[Int]) extends Expr[Int, NonScalarExpr]
528+
case class ListGet[A]($list: Expr[List[A], NonScalarExpr], $i: Expr[Int, NonScalarExpr])(using ResultTag[A])
529+
extends Expr[A, NonScalarExpr]
527530
case class ListConcat[A]
528531
($xs: Expr[List[A], NonScalarExpr], $ys: Expr[List[A], NonScalarExpr])
529532
(using ResultTag[List[A]])

src/main/scala/tyql/ir/QueryIRTree.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,15 @@ object QueryIRTree:
890890
case a: AggregationExpr[?] => generateAggregation(a, symbols)
891891
case a: Aggregation[?, ?] => generateQuery(a, symbols).appendFlag(SelectFlags.ExprLevel)
892892
case list: Expr.ListExpr[?] => ListTypeExpr(list.$elements.map(generateExpr(_, symbols)), list)
893+
case g: Expr.ListGet[?] => BinExprOp(
894+
"",
895+
generateExpr(g.$list, symbols),
896+
"[",
897+
generateExpr(g.$i, symbols),
898+
"]",
899+
Precedence.Comparison,
900+
g
901+
)
893902
case c: Expr.ListConcat[?] =>
894903
BinExprOp(
895904
"",

src/test/scala/test/integration/ArrayTests.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,32 @@ class ArrayTest extends FunSuite {
5353
}
5454
}
5555

56+
test("array indexing") {
57+
withDB.allWithArraySupport { conn =>
58+
val db = tyql.DB(conn)
59+
val q = Exprs[(a: String)](Tuple1(lit(List("a", "b", "c", "e"))(0)))
60+
val got = db.run(q)
61+
assertEquals(got.length, 1)
62+
assertEquals(got.head.toList.head, "a")
63+
}
64+
65+
withDB.allWithArraySupport { conn =>
66+
val db = tyql.DB(conn)
67+
val q = Exprs[(a: String)](Tuple1(lit(List("a", "b", "c", "e"))(2)))
68+
val got = db.run(q)
69+
assertEquals(got.length, 1)
70+
assertEquals(got.head.toList.head, "c")
71+
}
72+
73+
withDB.allWithArraySupport { conn =>
74+
val db = tyql.DB(conn)
75+
val q = Exprs[(a: String)](Tuple1(lit(List("a", "b", "c", "e"))(3)))
76+
val got = db.run(q)
77+
assertEquals(got.length, 1)
78+
assertEquals(got.head.toList.head, "e")
79+
}
80+
}
81+
5682
test("array concat") {
5783
withDB.allWithArraySupport { conn =>
5884
val db = tyql.DB(conn)

0 commit comments

Comments
 (0)