# -*- tcl -*- # # An example for the usage of the nx mongo object mapping with # input/export functions for variables not following the standard # nx-mapping of properties. # # The MongoDB nx package supports special codec (encoding/decoding) # functions which perform the mapping from instance variables to bson # and vice versa. These special mappings can be defined via the # attribute "rep" for :variable and :property. The predefined # representations for "array" and "dict" are included here. The rep # mechanism is extensible, users can define on the application layer # their own representations. # 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 foos ###################################################################### # nx-mongo has a built-in special representation for Tcl arrays which # can be used via e.g. # # :variable -rep array a # # The "array" representation differs from a string representation by # requiring a different method in tcl to read its values, and by # saving the tcl array in mongoDB in a different notation. The chosen # representation of the array in mongoDB is an array of key/value # pairs. # # Similarly we provide here a "dict" mapping, which transforms a dict # to a a form similar to a nested object. Just the first level of the # dict is transformed. ###################################################################### # # Extend ::nx::mongo::Class to handle rep codecs "array" and "dict" # ::nx::mongo::Class eval { # # rep codec "array" # :public method "bson rep encode array" {slot obj name} { set body {} set c 0 foreach {k v} [$obj eval [list array get :$name]] { lappend body [incr c] document [list k string $k v string $v] } return [list array $body] } :public method "bson rep decode array" {slot name bsontype value} { set av "" foreach {pos type entry} $value { lappend av [lindex $entry 2] [lindex $entry 5] } return "array set :$name [list $av]" } # # rep codec "dict" # :public method "bson rep encode dict" {slot obj name} { set body {} dict for {k v} [$obj eval [list set :$name]] { lappend body $k string $v } return [list document $body] } :public method "bson rep decode dict" {slot name bsontype value} { set result "" foreach {k type v} $value { lappend result $k $v } return "set :$name \[dict create $result\]" } } ###################################################################### # # Define an application class Foo, using the rep type "array" for # instance variable "a" and the rep type "dict" for instance variable # "d". # nx::mongo::Class create Foo { :index tags :property title :property -incremental tags:0..n :variable -rep array a :variable -rep dict d :public method bar {} {return [lsort [array names :a]]} :public method baz {key} {dict get ${:d} $key} } ###################################################################### # Build a composite Posting instance based on the example above. # set p [Foo new -title "Hello World" { :tags add a set :a(1) a set :a(2) b set :d [dict create first_name Walter second_name White] }] ? {$p bar} "1 2" ? {$p baz first_name} "Walter" # # When we save the item, the instances variables are transformed into # a mongoDB representation, using the rep types defined above. # ? {nx::mongo::db is_oid [$p save]} 1 $p destroy ? {nsf::is object $p} 0 # Now fetch the first entry set q [Foo find first] ? {$q bar} "1 2" ? {$q baz first_name} "Walter" Foo show puts stderr "====EXIT [info script]" ###################################################################### # Output ###################################################################### # # { # _id: 5301d307249bc51c00000000, # d: { # first_name: Walter, # second_name: White }, # a: [ { # k: 1, # v: a }, { # k: 2, # v: b } ], # title: {Hello World}, # tags: [ a ] # } ###################################################################### # # Local variables: # mode: tcl # tcl-indent-level: 2 # indent-tabs-mode: nil # End: