Skip to content

Ref and ResolvedRef

In Vasat a model is ANY case class, there is no restriction on what fields it can and cant have. The problem with this approach is that some of the fields like id, and dateMade are quite handy and universally apply to whatever object you might have.

The solution in vasat is the Reference object

Ref

A Ref is a container for the metadata of a data model. It contains things like the model's

  • id
  • date made
  • date updated
  • access control paths
  • version hash
  • displayName

ResolvedRef

A resolved reference is the object in question as well as the metadata for that object

scala

case class User(firstName:String, lastName:String, email:Option[String] = None)
 
val u:User = Ref("1234", u)

// will display as
 
{
    id:"1234",
    dateMade:...,
    dateUpdated:...,
    displayName:"Joe Spagettio",
    item:{
        firstName:"Joe",
        lastName:"Spagettio"
    }
 
}

Creating a ResolvedRef

scala
val u:ResolvedRef[User] = User("joe","blogs").makeRef
// or if you want to specify the ID
val u:ResolvedRef[User] = User("joe","blogs").existingRef("12345")
 
 
u.save()

UnresolvedRef

An unresolved ref is a pointer for a data model. It contains the Model type and the id of that model

scala
val userRef = Ref[User]("1234")

Unresolved refs are useful in definition a link to an object from another object see Relationships

Loading and Saving with Refs

There are some convenience methods when working with Ref objects. For all the convince methods to work there needs to be an implicit modelRepository and executionContext present in the scope of execution

scala
val u = Ref[User]("12345")
 
u.load().andThenMap{resolvedRef =>
    println("User is " + resolvedRef.item)
}
 
// or doing it synchronously (this will block code! not recommended)
val resolvedRef = u.load_!()
println("User is " + resolvedRef.item)
scala
val u:ResolvedRef[User] = ???
 
u.save().andThenMap{_ => // return of a save is a Noop, so it can be ignored
    println("User saved")
}
 
// or doing it synchronously (this will block code! not recommended)
u.save_!()
println("User saved")

Relationships in objects

References to another object also make use of Ref objects

consider the following:

scala
case class User(
   firstName:String,
   lastName:String,
   email:Option[String],
   address:Ref[Address] // a reference to another model type
)

Using the ref object you can control when the relationship object is loaded

scala
val u:Ref[User] = ???
 
val res = u.load().andThenFuture{ur =>
   ur.item.address.load().andThenMap{addr =>
    (ur.item,addr.item)
   }
}
 
// res == VValidF[(User,Address)]

If is important to note also that the json representation of a ref is just its ID as a string

js
{
    firstName:"joe",
    lastName:"blogs",
    address:"1234-5678-90" // Ref[Address] 
}

DisplayName

In the admin interface when selecting a list of items from a pulldown, there needs to be a standard string representation field for every object type. displayName is a field that can be set using code for every object type

eg: Setting the display name

scala
@DBAuto
class UserRepo extends DBContext[User,SlickBaseTable]{
 
    override def displayNameValue(id: String, obj: User): Option[String] = Some(obj.firstName + " " + obj.lastName)
    
}

Macros

When using the @DBAuto macro if your case class has a field name:String, it will automatically be used for displayName