Another question answers how to define a one-to-many association, by defining a method in the "one" case class (Directorate) that returns a Seq of the "many" class (ServiceArea).
But it doesn't address the "bidirectional" part of the question.
Using that example, I'd like to see how to traverse the association from the other direction.
Instead of
case class ServiceArea(areaCode: String, dirCode: String, name: String)
I'd like to see
case class ServiceArea(areaCode: String, directorate: Directorate, name: String)
Is this possible with Slick?
Because when I try something like
object ServiceAreas ...
def * = areaCode ~ directorate ~ name <> (ServiceArea, ServiceArea.unapply _)
it fails to compile, not finding an implicit value for evidence parameter of type TypeMapper[ForeignKeyQuery[ServiceAreas,ServiceArea]].
You have to adjust your way of thinking a little. Slick handles composition and execution of queries, but as you mentioned in your comment, it's not an ORM (thank goodness).
Have a look at the code you referenced:
case class ServiceArea(areaCode: String, dirCode: String, name: String)
object ServiceAreas extends Table[ServiceArea]("SERVICE_AREAS") {
def areaCode = column[String]("AREAE_CODE", O.PrimaryKey)
def dirCode = column[String]("DIRECTORATE_CODE")
def name = column[String]("NAME")
def directorate = foreignKey("DIR_FK", dirCode, Directorates)(_.dirCode)
def * = areaCode ~ dirCode ~ name <> (ServiceArea, ServiceArea.unapply _)
}
The link to directorate is already defined by a navigatable foreign key.
So now you can write a query like this:
def directorates = for {
area <- Parameters[String]
sa <- ServiceAreas if sa.areaCode === area
dir <- sa.directorate
} yield dir
Which will yield a Directorate for each match.
Related
Does there is a way to let the return value know its type should belong to some isinstance?
for example,def myfunction(...) -> instance[MyClass]:
(It's an informal grammar, I just example I want the syntax is something like that)
that means it only accepts the return type which belongs MyClass.
An example
I was given an example under the following, to make you more clear what I use for it to do what.
consider the following:
from typing import List, TypeVar, Union, Type
class Table:
NAME: str
def show_info(self):
print(self.NAME)
class TableA(Table):
NAME = 'A'
def method_belong_a_only(self):
print('a only')
class TableB(Table):
NAME = 'B'
def method_belong_b_only(self):
print('b only')
class DBBase:
Tables: List[Table]
class MyDB(DBBase):
Tables = [TableA, TableB]
def get_table(self, table_name: str) -> Union[Table, None]:
table_list = [_ for _ in self.Tables if hasattr(_, 'NAME') and _.NAME == table_name]
if not table_list:
return None
if len(table_list) > 1:
raise ValueError('Table name conflict!')
return table_list[0]() # create an instance
and then if I write the following,
db = MyDB()
ta = db.get_table('A')
ta.show_info() # ok
# ta. # IDE will show method, which belongs to Table only.
ta.method_belong_a_only() # It still can run, but IDE show Cannot find reference 'method_belong_a_only' in Table|None
tb: TableB = db.get_table('B') # It still can run, but IDE show ``Expected type 'TableA', got 'Optional[Table]' instead``
# tb. # Now, It can show ``method_belong_b_only``
I don't want it(PyCharm IDE) to show warnings to me, and I want it works well on intelligence.
You can use typing.TypeVar PEP484.type-aliases
from typing import List, TypeVar, Union, Type
T_Table = TypeVar('T_Table', bound=Table)
class MyDB2(DBBase):
Tables = [TableA, TableB]
def get_table(self, t: Type[T_Table] = Table) -> Union[T_Table, None]:
t_set = {cur_t for cur_t in self.Tables if cur_t.__name__ == t.__name__}
if not t_set:
return None
table = t_set.pop()
return table() # create an instance
def get_table_2(self, table_type_name: str) -> Union[T_Table, None]:
t_set = {cur_t for cur_t in self.Tables if cur_t.__name__ == table_type_name}
if not t_set:
return None
table = t_set.pop()
return table() # create an instance
db = MyDB2()
a = db.get_table(TableA)
# a = db.get_table(str) # <-- Expected type 'Type[T_Table]', got 'Type[str]' instead
a.method_belong_a_only() # intellisense will work perfectly.
b: TableB = db.get_table_2('TableB') # This is another way, if IDE felt confused, you can tell him what the type it is.
# b. # intellisense will work perfectly.
I am trying to add the required behavior to a CharFiled or TextField so I can store a list of lists and retrieve it as a list of lists again. I am not asking for a solution rather I would like to see an example where a subclassing of an already supported field type is done as I didn't find any in the documentation or the Internet.
Do I have to do it as explained in the documents for creating a custom type?
for example:
class mylistoflists(TextField):
if yes, then what do I have to assign to field_type?
Example code (see tests/fields.py for full example):
class ListField(TextField):
def db_value(self, value):
return ','.join(value) if value else ''
def python_value(self, value):
return value.split(',') if value else []
class Todo(TestModel):
content = TextField()
tags = ListField()
class TestCustomField(ModelTestCase):
requires = [Todo]
def test_custom_field(self):
t1 = Todo.create(content='t1', tags=['t1-a', 't1-b'])
t2 = Todo.create(content='t2', tags=[])
t1_db = Todo.get(Todo.id == t1.id)
self.assertEqual(t1_db.tags, ['t1-a', 't1-b'])
t2_db = Todo.get(Todo.id == t2.id)
self.assertEqual(t2_db.tags, [])
t1_db = Todo.get(Todo.tags == Value(['t1-a', 't1-b'], unpack=False))
self.assertEqual(t1_db.id, t1.id)
The code below is a PlaySlick sample that demonstrates a DAO class. I used this as a sample, however my issue is that I use the same table (for example, the CatTable class) in more than one DAO, and since the table is an inner class, I cannot import it in other DAOs as it's not in a companion object. Is there a way to fix this?
package dao
import scala.concurrent.Future
import javax.inject.Inject
import models.Cat
import play.api.db.slick.DatabaseConfigProvider
import play.api.db.slick.HasDatabaseConfigProvider
import play.api.libs.concurrent.Execution.Implicits.defaultContext
import slick.driver.JdbcProfile
class CatDAO #Inject()(protected val dbConfigProvider: DatabaseConfigProvider)
extends HasDatabaseConfigProvider[JdbcProfile] {
import driver.api._
private val Cats = TableQuery[CatsTable]
def all(): Future[Seq[Cat]] = db.run(Cats.result)
def insert(cat: Cat): Future[Unit] = db.run(Cats += cat).map { _ => () }
private class CatsTable(tag: Tag) extends Table[Cat](tag, "CAT") {
def name = column[String]("NAME", O.PrimaryKey)
def color = column[String]("COLOR")
def * = (name, color) <> (Cat.tupled, Cat.unapply _)
}
}
Sure. Classic approach we often use is this:
// student course segment
case class StudentCourseSegment(studentId: Id[Student],
courseId: Id[Course],
semesterId: Id[Semester],
id: Id[StudentCourseSegment] = Id.none)
class StudentCourseSegmentTable(tag: Tag) extends
Table[StudentCourseSegment](tag, "STUDENT_COURSE_SEGMENT") {
def studentId = column[Id[Student]]("STUDENT_ID")
def courseId = column[Id[Course]]("COURSE_ID")
def semesterId = column[Id[Semester]]("SEMESTER_ID")
def id = column[Id[StudentCourseSegment]]("ID", O.PrimaryKey, O.AutoInc)
def * = (studentId, courseId, semesterId, id) <> (StudentCourseSegment.tupled,
StudentCourseSegment.unapply)
// foreign keys
def student = foreignKey("fk_segment_student", studentId, StudentTable)(_.id)
def course = foreignKey("fk_segment_course", courseId, CourseTable)(_.id)
def semester = foreignKey("fk_segment_semester", semesterId, SemesterTable)(_.id)
}
lazy val StudentCourseSegmentTable = TableQuery[StudentCourseSegmentTable]
(example from my presentation: http://slides.com/pdolega/slick-101#/69)
So you have (on the same level):
case class - aka unpacked type (your domain in application)
table definition - aka mixed type
table query object
Your main DAO for this table will use this definitions, but so will other DAOs (e.g. for doing joins).
Point here I guess is this: nothing forces you to keep TableQuery (or other mentioned artifacts) as private inner members / classes. You can keep them as inner classes, as top level classes in same file or entirely somewhere else.
Also one thing - not related to the question but I see it in your example. I'd suggest to stay on DBIO level as in your DAO classes; if you transform everything instantly to Futures you loose composability (you won't be able to perform multiple operations in same transaction).
I am trying to replicate the Verbal Expression library for python in Genie as an exercise to learn how to use classes. I've got simple classes like the ones listed at the tutorial down, however when it comes to instatiate methods in a object oriented fashion I am running into problems. Here is what I am trying:
For training purposes I want a method called add that behaves identically as string.concat().
[indent=4]
class VerEx : Object
def add(strg:string) : string
return this.concat(strg)
But I get the error:
verbalexpressions.gs:33.16-33.26: error: The name `concat' does not exist in the context of `VerEx'
When I use a different approach, like:
class VerEx : Object
def add(strg:string) : string
a:string=""
a.concat(strg)
return a
init
test:string = "test"
sec:string = " + a bit more"
print test.VerEx.add(sec)
I get the error in the last line of the above text, with the warning:
verbalexpressions.gs:84.11-84.21: error: The name `VerEx' does not exist in the context of `string?'
I want to be able to make test.add(sec) behave identically to test.concat(sec), what can I do to achieve this?
a small example for this,
Note:
unhandle RegexError in
new Regex
r.replace
[indent=4]
class VerX
s: GenericArray of string
construct ()
s = new GenericArray of string
def add (v: string): VerX
s.add (v)
return self
def find (v: string): VerX
return self.add ("(%s)".printf (v))
def replace(old: string, repl: string): string
// new Regex: unhandle RegexError HERE!!
var r = new Regex (#"$(self)")
// r.replace: unhandle RegexError HERE!!
return r.replace(old, old.length, 0, repl)
def to_string (): string
return string.joinv ("", s.data)
init
var replace_me = "Replace bird with a duck"
var v = new VerX
print v.find("bird").replace(replace_me, "duck")
var result = (new VerX).find("red").replace("We have a red house", "blue")
print result
I am wondering if I can pass variable to be evaluated as String inside gstring evaluation.
simplest example will be some thing like
def var ='person.lName'
def value = "${var}"
println(value)
I am looking to get output the value of lastName in the person instance. As a last resort I can use reflection, but wondering there should be some thing simpler in groovy, that I am not aware of.
Can you try:
def var = Eval.me( 'new Date()' )
In place of the first line in your example.
The Eval class is documented here
edit
I am guessing (from your updated question) that you have a person variable, and then people are passing in a String like person.lName , and you want to return the lName property of that class?
Can you try something like this using GroovyShell?
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
GroovyShell shell = new GroovyShell( binding )
def result = shell.evaluate( commandString )
Or this, using direct string parsing and property access
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
// Split the command string into a list based on '.', and inject starting with null
def result = commandString.split( /\./ ).inject( null ) { curr, prop ->
// if curr is null, then return the property from the binding
// Otherwise try to get the given property from the curr object
curr?."$prop" ?: binding[ prop ]
}