# -*- tcl -*-
#
# This is an introductory example how to use the nx mongo mapping for
# referencing some object. We use here an example of an Posting having
# a single (possible compound) user as originator. All example work
# the same way as well with with multivalued attributes.
#
# Gustaf Neumann              fecit, May 2011
#
package require nx::mongo
package require nx::test

# Establish connection to the database
? {::nx::mongo::db connect -db "tutorial"} mongoc_client_t:0

# Make sure, we start always from scratch
nx::mongo::db drop collection users
nx::mongo::db drop collection posts


######################################################################
# The first approach to implement references simply as a property.
# This is just feasible in cases, where the user has just a name and
# not more attributes.
#
? {nx::mongo::Class create Post {
  :property title
  :property user
}} ::Post

# Insert entry with the schema of ::Post into the database:
? {nx::mongo::db is_oid [Post insert -title "Hello trivial World" -user smith] } 1

# Retrieve the entry from the database:
? {nsf::is object [set p [Post find first -cond {title = "Hello trivial World"}]]} 1
? {$p cget -user} smith
? {$p destroy; nsf::is object $p} 0

######################################################################
# The second approach to implement references to other objects via an
# property pointing to the object id of another object. This is the
# classical database approach. When the object is fetched, the
# application developer has to care about fetching/dereferencing the
# referenced object.
#
? {nx::mongo::Class create User {
  :property name
}} ::User
? {nx::mongo::Class create Post {
  :property title
  :property user_id
}} ::Post

# The method "insert" returns the object id of the newly created
# object. We can use this value as a reference in the Post.
? {nx::mongo::db is_oid [set oid [User insert -name Smith]]} 1
? {nx::mongo::db is_oid [Post insert -title "Hello simple World" -user_id $oid]} 1

# Retrieve the entry from the database:
? {nsf::is object [set p [Post find first -cond {title = "Hello simple World"}]]} 1
? {nsf::is object [set u [User find first -cond [list _id = [$p cget -user_id]]]]} 1
? {$u cget -name} "Smith"

######################################################################
# The third approach is to embed the object in the referencing
# document. This might be feasible when the values of the embedded
# objects seldom change, When the containing object (the Post
# instance) is loaded, the appropriate object structure is created
# automatically.
#
? {nx::mongo::Class create User {
  :property name
}} ::User
? {nx::mongo::Class create Post {
  :property title
  :property user:embedded,type=::User
}} ::Post

? {nx::mongo::db is_oid [Post insert -title "Hello embedded World" -user [User new -name Smith]]} 1

# Retrieve the entry from the database:
? {nsf::is object [set p [Post find first -cond {title = "Hello embedded World"}]]} 1
? {[$p cget -user] cget -name} "Smith"

######################################################################
# The fourth approach is to use mongo db-refs for referencing.  This
# is similar to approach two, but provides support for dereferencing
# and maintaining the reference lists.
#
? {nx::mongo::Class create User {
  :property name
}} ::User
? {nx::mongo::Class create Post {
  :property title
  :property user:reference,type=::User
}} ::Post

? {nx::mongo::db is_oid [Post insert -title "Hello referenced World" -user [User new -name SmithR]]} 1

# Retrieve the entry from the database:
? {nsf::is object [set p [Post find first -cond {title = "Hello referenced World"}]]} 1
? {[$p cget -user] cget -name} SmithR
  

puts stderr "\nContent of the collection posts:"
Post show

puts stderr "\nContent of the collection users:"
User show
######################################################################
# Output
######################################################################

# Content of the collection posts:
# Content of the collection posts:
# {
#     _id: 51fa2f29cb562e0000000000, 
#     title: {Hello trivial World}, 
#     user: smith
# }, {
#     _id: 51fa2f29cb562e0000000002, 
#     title: {Hello simple World}, 
#     user_id: 51fa2f29cb562e0000000001
# }, {
#     _id: 51fa2f29cb562e0000000003, 
#     title: {Hello embedded World}, 
#     user: { 
#       name: Smith }
# }, {
#     _id: 51fa2f29cb562e0000000005, 
#     title: {Hello referenced World}, 
#     user: { 
#       $ref: users, 
#       $id: 51fa2f29cb562e0000000004, 
#       $db: tutorial }
# }
# 
# Content of the collection users:
# {
#     _id: 51fa2f29cb562e0000000001, 
#     name: Smith
# }, {
#     _id: 51fa2f29cb562e0000000004, 
#     name: SmithR
# }
# 

######################################################################
#
# Local variables:
#    mode: tcl
#    tcl-indent-level: 2
#    indent-tabs-mode: nil
# End:
