Skip to content

Commit

Permalink
Support NamedTuples
Browse files Browse the repository at this point in the history
  • Loading branch information
Primetalk committed Jan 19, 2025
1 parent a42d82c commit 51feedf
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 37 deletions.
6 changes: 5 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ lazy val `type-class-schema` = project
.in(file("type-class-schema"))
.settings(
name := "type-class-schema",
publish / skip := true
publish / skip := true,
scalacOptions ++= Seq(
"experimental",
"language:experimental.namedTuples"
)
)
.dependsOn()
.settings(commonSettings*)
Original file line number Diff line number Diff line change
@@ -1,61 +1,69 @@
package ru.primetalk.typed.ontology.example2

import ru.primetalk.typed.ontology.typeclass.schema.{Column, RecordSchema, RecordTupleValue, RecordValueType, SchemaValueType}
import scala.language.experimental.namedTuples

import ru.primetalk.typed.ontology.typeclass.schema.{
Column,
RecordSchema,
RecordTupleValue,
RecordValueType,
SchemaValueType
}
import ru.primetalk.typed.ontology.typeclass.table.TableColumn
import ru.primetalk.typed.ontology.typeclass.table.TableColumn.given
import ru.primetalk.typed.ontology.typeclass.schema.RecordTupleValue.{*, given}

import java.time.LocalDateTime

object Product:
case object id extends TableColumn["id", Int]
case object id extends TableColumn["id", Int]
type id = id.type
case object name extends TableColumn["name", String]
case object name extends TableColumn["name", String]
type name = name.type
case object price extends TableColumn["price", BigInt]
type price = price.type
type PriceSchema = price *: EmptyTuple
type price = price.type
type PriceSchema = price *: EmptyTuple
type NamePriceSchema = name *: price *: EmptyTuple
type TableSchema = id *: name *: price *: EmptyTuple
type TableSchema = id *: name *: price *: EmptyTuple
val tableSchema: TableSchema = (id, name, price)
val idNameSchema = (id, name)
val namePriceSchema = (name, price)
type priceSchema = price *: EmptyTuple
type primitivePriceRow = BigInt *: EmptyTuple
val priceSchema = price *: EmptyTuple
type PrimaryKeySchema = id *: EmptyTuple
val primaryKeySchema: PrimaryKeySchema = Tuple1(id)
val namePriceSchema = (name, price)
type priceSchema = price *: EmptyTuple
type primitivePriceRow = BigInt *: EmptyTuple
val priceSchema = price *: EmptyTuple
type PrimaryKeySchema = id *: EmptyTuple
val primaryKeySchema: PrimaryKeySchema = Tuple1(id)

val fullSchema = RecordSchema.infer[TableSchema]
val svt = summon[SchemaValueType[TableSchema, ?]]
type Row = svt.Value
val svt = summon[SchemaValueType[TableSchema, ?]]
type Row = svt.Value
type PrimitiveRow = (Int, String, BigInt)
summon[Row =:= RecordTupleValue[TableSchema, (Int, String, BigInt)]]
summon[(Int, String, BigInt) <:< Row]

object Order:
case object id extends TableColumn["id", Int]
case object id extends TableColumn["id", Int]
type id = id.type
case object date extends TableColumn["date", LocalDateTime]
type date = date.type
type date = date.type
type TableSchema = id *: date *: EmptyTuple
val tableSchema: TableSchema = (id, date)
val ts = (id, date)
val ts = (id, date)

val svt = SchemaValueType.Aux[TableSchema]
type Row = svt.Value

object OrderItem:
object id extends TableColumn["id", Int]
object id extends TableColumn["id", Int]
type id = id.type
object orderId extends TableColumn["orderId", Int]
object orderId extends TableColumn["orderId", Int]
type orderId = orderId.type
object productId extends TableColumn["productId", Int]
type productId = productId.type
type productId = productId.type
type TableSchema = id *: orderId *: productId *: EmptyTuple
val tableSchema: TableSchema = (id, orderId, productId)
val tableSchema: TableSchema = (id, orderId, productId)
val tableSchema2: TableSchema = RecordSchema.infer[TableSchema]
val tableSchema3: TableSchema = id *: orderId *: productId *: EmptyTuple
val tableSchema3: TableSchema = id *: orderId *: productId *: EmptyTuple

type SmallerSchema = id *: orderId *: EmptyTuple
val smallerSchema: SmallerSchema = RecordSchema.infer[SmallerSchema]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
package ru.primetalk.typed.ontology.example2

import ru.primetalk.typed.ontology.typeclass.schema.{Getter, Projector, RecordTupleValue, SchemaValueType}
import scala.language.experimental.namedTuples

import ru.primetalk.typed.ontology.typeclass.schema.{
Getter,
Projector,
RecordTupleValue,
SchemaValueType
}
import ru.primetalk.typed.ontology.typeclass.schema.RecordTupleValue.{*, given}
import ru.primetalk.typed.ontology.typeclass.table.TableColumn
import ru.primetalk.typed.ontology.typeclass.table.TableColumn.{*, given}

class OrderOntologySpec extends BaseSpec:

test("get value"){
test("get value") {

val row: Product.Row = (1, "product name", BigInt(1))
val a = row.toNamedTuple
assert(a.id == 1)
assert(a.name == "product name")
val ev1 = summon[(Int, String, BigInt) <:< Product.Row]
val getter = summon[Getter[Product.id, Int, RecordTupleValue[Product.TableSchema, Int *: String *: BigInt *: EmptyTuple]]]
val getter = summon[Getter[
Product.id,
Int,
RecordTupleValue[Product.TableSchema, Int *: String *: BigInt *: EmptyTuple]
]]
val svt1 = summon[SchemaValueType[Product.id, Int]]
val svt = SchemaValueType.Aux[Product.id]
val svt = SchemaValueType.Aux[Product.id]
assert(row.get(Product.id) == 1)
assert(row.project(Product.priceSchema) == BigInt(1) *: EmptyTuple)
assert(row.project(Product.idNameSchema) == (1, "product name"))
Expand Down
4 changes: 3 additions & 1 deletion project/metals.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// format: off
// DO NOT EDIT! This file is auto-generated.

// This file enables sbt-bloop to create bloop config files.

addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.15")
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.6")

// format: on
4 changes: 3 additions & 1 deletion project/project/metals.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// format: off
// DO NOT EDIT! This file is auto-generated.

// This file enables sbt-bloop to create bloop config files.

addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.15")
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.6")

// format: on
4 changes: 3 additions & 1 deletion project/project/project/metals.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// format: off
// DO NOT EDIT! This file is auto-generated.

// This file enables sbt-bloop to create bloop config files.

addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.15")
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "2.0.6")

// format: on
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@ package ru.primetalk.typed.ontology.typeclass.schema
/** @tparam C is a column that could be part of RecordSchema. */
trait Column[C]:
type Name <: String
def name(column: C): Name
// def name: Name

object Column:
inline def infer[Col: ValueOf]: Col =
valueOf[Col]

// inline def nameOf[C](using col: Column[C]): col.Name =
// col.name

// type NameOf[C] <: String = C match
// case {type Name <: String} => c#Name
// case _ => Nothing
type Columns[Schema <: Tuple] = Tuple.Map[Schema, Column]
// type ColumnNames[Schema <: Tuple] = Tuple.Map[Tuple.Map[Schema, Column], NameOf]

inline def columnNames[Schema <: Tuple](using columns: Columns[Schema]): columns.type =
columns
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ru.primetalk.typed.ontology.typeclass.schema

/**
* This type class creates a relation between a column and it's name.
*/
trait ColumnName[C, N <: String]

/**
* This type class creates a correspondence between a list of columns and a list of names.
*/
sealed abstract class ColumnsNames[C <: Tuple, N <: Tuple]

object ColumnsNames:

given emptyColumnsNames: ColumnsNames[EmptyTuple, EmptyTuple] = new ColumnsNames[EmptyTuple, EmptyTuple] {}

given nonEmptyColumnsNames[C, CS <: Tuple, N <: String, NS <: Tuple](using ColumnName[C, N], ColumnsNames[CS, NS]): ColumnsNames[C *: CS, N *: NS] =
new ColumnsNames[C *: CS, N *: NS] {}

end ColumnsNames
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ru.primetalk.typed.ontology.typeclass.schema

import scala.language.experimental.namedTuples

/** Projector from Source schema to Dest schema exists only if such conversion is possible. In this
* case it allows to perform the conversion of values.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package ru.primetalk.typed.ontology.typeclass.schema

import scala.annotation.{implicitNotFound, targetName}
import scala.language.experimental.namedTuples
import scala.NamedTuple.*
import scala.NamedTupleDecomposition.*

/** Type-level annotation of a Tuple with it's RecordSchema.
* Elements are connected via Column[T], SchemaValueType[C].
Expand All @@ -22,9 +25,13 @@ object RecordTupleValue:

given svtFromValidRecordTupleValue[S <: Tuple, V <: Tuple](using vrtv: ValidRecordTupleValue[S, V]): SchemaValueType[S, RecordTupleValue[S, V]] =
new SchemaValueType[S, RecordTupleValue[S, V]]

extension [R <: Tuple, V <: Tuple](v: RecordTupleValue[R, V])
inline def toTuple: V = v.asInstanceOf[V]

inline def toNamedTuple[Names <: Tuple](using columnsNames: ColumnsNames[R, Names]): NamedTuple[Names, V] =
v.asInstanceOf[NamedTuple[Names, V]]

inline def prepend[H, HV](vh: HV)(using SchemaValueType[H, HV]): RecordTupleValue[H *: R, HV *: V] =
vh *: v.toTuple

Expand All @@ -33,7 +40,7 @@ object RecordTupleValue:

inline def project[Dest <: Tuple, DestV <: Tuple](dest: Dest)(using proj: Projector[R, V, Dest, DestV]): RecordTupleValue[Dest, DestV] =
proj.apply(v)

object Prepend:
def unapply[H, HV, R <: Tuple, V <: Tuple](r: RecordTupleValue[H *: R, HV *: V]): (HV, RecordTupleValue[R, V]) =
(r.toTuple.head, r.toTuple.tail)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ru.primetalk.typed.ontology.typeclass.schema

import scala.language.experimental.namedTuples

type RecordValueType[R <: Tuple, V <: Tuple] = SchemaValueType[R, RecordTupleValue[R, V]]

//object RecordValueType:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@ package ru.primetalk.typed.ontology.typeclass.table

import ru.primetalk.typed.ontology.typeclass.schema.*

class TableColumn[Name <: String, V]
class TableColumn[Name <: String & Singleton, V]

object TableColumn:

class ColumnImpl[Name1 <: String : ValueOf, V, C <: TableColumn[Name1, V]: ValueOf] extends Column[C]:
class ColumnImpl[Name1 <: String & Singleton : ValueOf, V, C <: TableColumn[Name1, V]: ValueOf] extends Column[C]:
type Name = Name1

def name(column: C): Name =
valueOf[Name1]

inline given [Name1 <: String : ValueOf, V, C <: TableColumn[Name1, V]: ValueOf]: Column[C] =
end ColumnImpl

inline given [Name1 <: String & Singleton : ValueOf, V, C <: TableColumn[Name1, V]: ValueOf]: Column[C] =
new ColumnImpl[Name1, V, C]

inline given svtForColumn[Name1 <: String, V, C <: TableColumn[Name1, V]: ValueOf]: SchemaValueType[C, V] =
inline given svtForColumn[Name1 <: String & Singleton, V, C <: TableColumn[Name1, V]: ValueOf]: SchemaValueType[C, V] =
new SchemaValueType[C, V]

given columnName[Name <: String & Singleton, V, C <: TableColumn[Name, V]]: ColumnName[C, Name] =
new ColumnName[C, Name] {}

end TableColumn

0 comments on commit 51feedf

Please sign in to comment.