# -*- tcl -*-
#
# An example for the usage of the nx mongo object mapping based on the
# the real world
#
#      "Business Insider" Data Model 
#
# (see e.g.
# https://www.slideshare.net/mongodb/nosql-the-shift-to-a-nonrelational-world).
#
# { title: 'Too Big to Fail', 
#   author: 'John S.',
#   ts: Date('05-Nov-09 10:33'),
#   [ comments: [ {author: 'Ian White',
#                  comment: 'Great Article!' },
#                 {author: 'Joe Smith',
#                  comment: 'But how fast is it?',
#                  replies: [ {author: Jane Smith',
#                              comment: 'scalable?' }]
#                 }
#   ],
#   tags: ['finance', 'economy']
# }
#
#
#
# Gustaf Neumann              fecit, May 2011
#
package require nx::mongo
package require nx::serializer
package require nx::test

#nsf::configure debug 2

# Establish connection to the database
::nx::mongo::db connect -db "tutorial"

# Make sure, we start always from scratch, so remove everything from
# the collection.
nx::mongo::db drop collection postings

######################################################################
# Create the application classes based on the "Business Insider" data
# model. Note that instances of the class "Comment" can be embedded in
# a posting (property "comments") as well as in an comment itself
# (property "replies"). All comments are in this example multivalued
# and incremental (i.e. one can use slot methods "... add ..." and
# "... delete ..." to add values to the attributes).
#
nx::mongo::Class create Comment {
  :property author:required
  :property comment:required 
  :property -incremental replies:embedded,type=::Comment,0..n
}

nx::mongo::Class create Posting {
  :index tags
  :property title:required
  :property author:required
  :property ts:required
  :property -incremental comments:embedded,type=::Comment,0..n
  :property -incremental tags:0..n
}

#puts stderr "OP [join [Posting info configure parameters] \n\t]"

######################################################################
# Build a composite Posting instance based on the example above.
#
set p [Posting new -title "Too Big to Fail" -author "John S." \
	   -ts "05-Nov-09 10:33" -tags {finance economy} \
	   -comments [list \
			  [Comment new -author "Ian White" -comment "Great Article!"] \
			  [Comment new -author "Joe Smith" -comment "But how fast is it?" \
			       -replies [list [Comment new -author "Jane Smith" -comment "scalable?"]]] \
			 ]]
#
# When we save the item, the embedded objects (the comments and
# replies) are saved together with the posting in a compound document.
#
$p save

# After saving the item, the main object contains an _id, such that a
# subsequent save operations do not create an additional entries in
# the database. For our little experiment here, we like to save
# multiple copies to see the results of our changes. Therefore, we
# remove the _id manually:
$p eval {unset :_id}

# We have two comments for the posting $p
? [list llength [$p cget -comments]] 2

# Now we want to remove e.g. the second comment (with the embedded
# replies). First get this comment object $c ...
set c [lindex [$p cget -comments] 1]

# ... and delete it
$c delete

# The delete operation destroy the embedded object and removes the
# reference to it in the comments property.
? [list llength [$p cget -comments]] 1

# The delete operation does not automatically persist the change,
# since there might be multiple changes in a complex
# document. Therefore, we have to perform an save operation of the
# containing document.
$p save

# Now, we have two postings in the database, the first with the two
# comments, the second one with just a single comment.
? {Posting count} 2

# Again, we want to continue with our test and remove the fresh _id as
# well.
$p eval {unset :_id}

# We add an additional comment at the end of the list of the comments
# with the incremental operations (the slot is incremental) ...
$p comments add [Comment new -author "Gustaf N" -comment "This sounds pretty cool"] end

# ... and we add another tag ...
$p tags add nx

# ... and save everything
$p save

# We have now three entries in the database collection.
? {Posting count} 3

# Now fetch the first entry with the tag "nx"
set q [Posting find first -cond {tags = nx}]

# The fetched entry should have the two comments:
? [list llength [$q cget -comments]] 2

# We add jet another tag and save it
$q tags add nsf
$q save

# We still have three entries in the database
? {Posting count} 3

Posting show

nx::mongo::db close

######################################################################
# Output
######################################################################
# {
#     _id: 4daaeb04727b2b1000000000, 
#     title: {Too Big to Fail}, 
#     comments: [ { 
#       author: {Ian White}, 
#       comment: {Great Article!} }, { 
#       replies: [ { 
#         author: {Jane Smith}, 
#         comment: scalable? } ], 
#       author: {Joe Smith}, 
#       comment: {But how fast is it?} } ], 
#     author: {John S.}, 
#     ts: {05-Nov-09 10:33}, 
#     tags: [ finance, economy ]
# }, {
#     _id: 4daaeb04727b2b1000000001, 
#     title: {Too Big to Fail}, 
#     comments: [ { 
#       author: {Ian White}, 
#       comment: {Great Article!} } ], 
#     author: {John S.}, 
#     ts: {05-Nov-09 10:33}, 
#     tags: [ finance, economy ]
# }, {
#     _id: 4daaeb04727b2b1000000002, 
#     title: {Too Big to Fail}, 
#     comments: [ { 
#       author: {Ian White}, 
#       comment: {Great Article!} }, { 
#       author: {Gustaf N}, 
#       comment: {This sounds pretty cool} } ], 
#     author: {John S.}, 
#     ts: {05-Nov-09 10:33}, 
#     tags: [ nsf, nx, finance, economy ]
# }
######################################################################

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