6 SDB (Database)
(require (planet gh/aws:1:=5/sdb)) |
SimpleDB is a “schema-less” database. You should review the SDB docs to understand the basic concepts and names. For example an SDB domain is like a SQL table, an SDB item is like a SQL row, and an SDB item name is like a SQL primary key value to unqiuely identify a row.
Instead of columns, each item has attributes. Each attribute is a key/value hash. In other words, unlike a SQL column which has one value, each SDB attribute may have multiple values. For example an attribute with the key "Sizes" might have the values "Small", "Medium", and "Large". The values should be considered a strict set (just one occurrence of each unique value).
6.1 Making requests to SDB
parameter
(sdb-endpoint v) → void? v : endpoint?
procedure
(create-domain name) → void?
name : string?
Tip: Although you may put non alpha-numeric characters in a name, and most of the API will work, the select procedures won’t, unless you bracket the domain name to make it legal SQL.
procedure
(delete-domain name) → void?
name : string?
procedure
(list-domains) → (listof (list/c 'DomainName string?))
parameter
(always-replace? always?) → void? always? : boolean?
procedure
(put-attributes domain-name item-name attributes) → any domain-name : string? item-name : string? attributes : (listof (list/c symbol? string?))
procedure
(get-attributes domain-name item-name)
→ (listof (list/c symbol? string?)) domain-name : string? item-name : string?
procedure
(delete-attributes domain-name item-name attributes) → void? domain-name : string? item-name : string? attributes : (listof (list/c symbol? string?))
procedure
(delete-item domain-name item-name) → void?
domain-name : string? item-name : string?
6.2 Batch
procedure
(batch-put-attributes domain-name xs) → any
domain-name : string? xs : (listof (cons/c string? (listof (list/c symbol? string?))))
procedure
(batch-delete-attributes domain-name xs) → void?
domain-name : string? xs : (listof (cons/c string? (listof (list/c symbol? string?))))
6.3 Hash/Set style
procedure
(put-attributes-hash domain item attribs) → void?
domain : string? item : string? attribs : (hash/c symbol? (set/c string?))
procedure
(get-attributes-hash domain item)
→ (hash/c symbol? (set/c string?)) domain : string? item : string?
procedure
(select-hash expr) → (listof item?)
expr : string?
struct
(struct item (name attribs) #:extra-constructor-name make-item) name : string? attribs : (hash/c symbol? (set/c string?))
These procedures provide a set-oriented interface. For a multi-valued attribute,
you get and set all its values together as one set. The attribute’s values are
represented as (set/c string?). A collection of attributes is
(hash/c symbol? (set/c string?)). When you get a multi-valued
attribute, all of its values are grouped and presented as a (set/c string?). When you put the attribute set, all of its existing values in SDB
are replaced by the new set of values you supply. (At a lower level, this means
the first attribute is put to SDB using parameter Replace=true—
6.4 Values as strings
SDB stores all values as strings. You choose how a number is represented as a string. Your choice matters for sorts and compares. The SDB docs recommend:
pad numbers with leading zeroes
and apply an offset to negative numbers so they are stored as a nonnegative number
Analgesic below.
procedure
(int<->str [width offset pad-char])
→
(number? -> string?) (string? -> number) width : exact-positive-integer? = 5 offset : exact-nonnegative-integer? = 0 pad-char : character? = #\0
procedure
(str->int/u8 s) → number?
s : string?
procedure
(int->str/u8 n) → string?
n : number?
procedure
(str->int/s8 s) → number?
s : string?
procedure
(int->str/s8 n) → string?
n : number?
procedure
(str->int/u16 s) → number?
s : string?
procedure
(int->str/u16 n) → string?
n : number?
procedure
(str->int/s16 s) → number?
s : string?
procedure
(int->str/s16 n) → string?
n : number?
procedure
(str->int/u32 s) → number?
s : string?
procedure
(int->str/u32 n) → string?
n : number?
procedure
(str->int/s32 s) → number?
s : string?
procedure
(int->str/s32 n) → string?
n : number?
> (int->str/u8 0) "000" > (int->str/u8 255) "255" > (int->str/s8 -128) "000" > (int->str/s8 0) "128" > (int->str/s8 127) "255" > (int->str/u32 0) "0000000000" > (int->str/u32 (expt 2 32)) "4294967296" > (int->str/s32 (- (expt 2 31))) "0000000000" > (int->str/s32 0) "2147483648" > (int->str/s32 (+ (expt 2 31))) "4294967296"
6.5 SDB Examples
In the examples below, the reason for using sleep is that SDB has an “eventual consistency” model. As a result, there may be a short delay before the values we set are available to get.
(require (planet gh/aws/keys) |
(planet gh/aws/sdb)) |
(ensure-have-keys) |
(define test-domain "TestDomain") |
(delete-domain test-domain) |
(create-domain test-domain) |
(sleep 1) |
(member? `(DomainName ,test-domain) (list-domains)) |
(domain-metadata test-domain) |
(define attribs '((BPM "130") |
(Genre "Disco"))) |
(put-attributes test-domain "item" attribs) |
(sleep 1) |
(get-attributes test-domain "item") |
(select (string-append "select Genre from " test-domain)) |
(delete-attributes test-domain "item" attribs) |
(sleep 1) |
(get-attributes test-domain "item") |
(define cnt 5) |
(for ([n (in-range cnt)]) |
(put-attributes test-domain |
(format "Item~a" n) |
`((n ,(format "~a" n))))) |
(for ([n (in-range cnt)]) |
(displayln (get-attributes test-domain (format "Item~a" n)))) |
(select (string-append "SELECT Count(*) FROM " test-domain)) |
(select (string-append "SELECT * FROM " test-domain)) |
(for ([n (in-range cnt)]) |
(delete-attributes test-domain |
(format "Item~a" n) |
`((n ,(format "~a" n))))) |
(for ([n (in-range cnt)]) |
(displayln (get-attributes test-domain (format "Item~a" n)))) |
;; BatchXxxAttributes |
(define (batch-attribs n) |
(for/list ([i (in-range 6)]) |
(list (string->symbol (format "key/~a/~a" n i)) |
(format "val/~a/~a" n i)))) |
(define batch-item-count 5) |
(define (batch-items) |
(for/list ([n (in-range batch-item-count)]) |
(cons (format "item~a" n) |
(batch-attribs n)))) |
(batch-put-attributes test-domain (batch-items)) |
(sleep 3) |
(for ([n (in-range batch-item-count)]) |
(printf "item~a:\n" n) |
(displayln (get-attributes test-domain (format "item~a" n)))) |
(batch-delete-attributes test-domain (batch-items)) |
(sleep 3) |
(for ([n (in-range batch-item-count)]) |
(displayln (get-attributes test-domain (format "item~a" n)))) |
;; hash style |
(define attribs/hash (hash 'bpm (set "100") |
'genre (set "Rock" "Metal"))) |
(put-attributes-hash test-domain "itemHash" attribs/hash) |
(sleep 1) |
(get-attributes-hash test-domain "itemHash") |
(select-hash (format "SELECT * FROM ~a WHERE ItemName() = 'itemHash'" |
test-domain)) |
(delete-domain test-domain) |