Skip to content

rudolph-miller/dyna

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dyna

Build Status Quicklisp dist

Dyna is an AWS DynamoDB ORM for Common Lisp.

Usage

(defvar *dyna* (make-dyna :credentials (cons (asdf::getenv "AWS_ACCESS_KEY")
                                             (asdf::getenv "AWS_SECRET_KEY"))
                 :region "ap-northeast-1"))
 
(defclass thread ()
  ((forum-name :key-type :hash
               :attr-name "ForumName"
               :initarg :forum-name
               :accessor thread-forum-name)
   (subject :key-type :range
            :attr-name "Subject"
            :initarg :subject
            :accessor thread-subject))
  (:dyna *dyna*)
  (:table-name "Thread")
  (:metaclass <dyna-table-class>))

(migrate-dyna-teble 'thread)
;; => T

(save-dyna (make-instance 'thread :forum-name "Amazon DynamoDB"
                                  :subject "Really useful"))
;; => T

(find-dyna 'thread "Amazon DynamoDB" "Really useful")
;; => #<THREAD :forum-name "Amazon DynamoDB" :subject "Really useful">



;;; The operations below is the samples of Low Level API.

(fetch (dyna-credentials *dyna*) "local" "ListTables" "{}")
;; => #(...)

(put-item *dyna* :table-name "aliens"
                 :item (("Name" . "LispAlien") ("Feature" . "They talk Lisp.")))
;; => T

(get-item *dyna* :table-name "aliens" :key (("Name" . "LispAlien"))))
;; => (("Name" . "LispAlien") ("Feature" . "They talk Lisp."))

Installasion

(ql:quickload :dyna)

API

dyna

(make-dyna :credentials (cons "access-key" "secret-key")
           :region "ap-northeast-1")
  • dyna object is a object for setting up.
  • make-dyna creates dyna object.
  • :credentials is a dotted pair of AccessKey and SecretKey.
  • :region is a region of your DynamoDB.
  • If you want to access you local DynamoDB Local,
    you can setup :region "local" and (setf *local-port* 8000).

(defclass thread ()
  ((forum-name :key-type :hash
               :attr-name "ForumName"
               :attr-type :S
               :initarg :forum-name
               :accessor thread-forum-name)
   (subject :key-type :range
            :attr-name "Subject"
            :attr-type :S
            :initarg :subject
            :accessor thread-subject)
   (owner :attr-name "Owner"
          :attr-type :S
          :initarg :owner
          :accessor thread-owner)
   (last-post-date-time :attr-name "LastPostDateTime"
                        :attr-type :S
                        :initarg :last-post-date-time
                        :accessor thread-last-post-date-time))
  (:dyna *dyna*)
  (:table-name "Thread")
  (:throughput (:read 1 :wirte 1)
  (:lsi lat-post-date-time)
  (:gsi (:hash owner :read 5 :write 5))
  (:metaclass <dyna-table-class>))

;; Simpler Style

(defclass thread ()
  ((forum-name :key-type :hash
               :attr-type :S
               :initarg :forum-name
               :accessor thread-forum-name)
   (subject :key-type :range
            :attr-type :S
            :initarg :subject
            :accessor thread-subject))
  (:dyna *dyna*)
  (:metaclass <dyna-table-class>))
  • You can create class haveing as :metaclass.
  • :dyna can take dyna object.
  • :table-name can take table name of DynamoDB's table. (Optional)
  • :throughput is the ProvisionedThroughput of the table. (Optional)
  • You can create table without :throughput,
    then the first value of ProvisionedThroughput will be *default-throughput*,
    and you can adjust ProvisionedThroughput with AWS Console.
  • :lsi is columns of LocalSecondaryIndexes.
  • :gsi is columns of GlobalSecondaryIndexes.
  • You can create :gsi without :read nor :write,
    then the first value of ProvisionedThroughput in GlobalSecondaryIndexes will be
    *default-throughput*, and you can adjust ProvisionedThroughput with AWS Console.
  • :key-type in slot should be :hash or :range and is the same as DynamoDB's table.
  • :attr-name in slot is AttributeName of Item in DynamoDB's table. (Optional)
  • :attr-type in slot is AttributeType of Item in DynamoDB's table. (Optional)
  • You must attach :attr-type with Attributes used in Indexes.

create-dyna-table

(create-dyna-table 'thread)
;; => T
  • can return T if the table is successfully created.

update-dyna-table

(defclass thread ()
  ((forum-name :key-type :hash
               :attr-name "ForumName"
               :attr-type :S
               :initarg :forum-name
               :accessor thread-forum-name)
   (subject :key-type :range
            :attr-name "Subject"
            :attr-type :S
            :initarg :subject
            :accessor thread-subject))
  (:dyna *dyna*)
  (:table-name "Thread")
  (:throughput (:read 10 :wirte 10)
  (:metaclass <dyna-table-class>))
(update-dyna-table 'thread)
;; => T

(update-dyna-table 'thread)
;; => NIL
  • can return T if the table is successfully updated.
  • can return NIL if the table has no changs.

migrate-dyna-table

(migrate-dyna-table 'thread)
=> T
  • can create the table if the table doesn't exist.
  • can update the table if the table definitions are chagned.
  • can return NIL if the table has no changes.

find-dyna

(find-dyna 'thread "Amazon DynamoDB" "Really useful")
;; => #<THREAD :forum-name "Amazon DynamoDB" :subject "Really useful">
  • can return a object if matching Item exists.

select-dyna

(select-dyna 'thread)
;; => (#<THREAD > <#THREAD >)

(selet-dyna 'thread (where (:= :forum-name "Amazon DynamoDB")))
;; => (#<THREAD >)

(selet-dyna 'thread (where (:or (:= :forum-name "Amazon S3")
                                (:= :forum-name "Amazon DynamoDB"))))
;; => (#<THREAD > #<THREAD >)

(selet-dyna 'thread (where (:in :forum-name '("Amazon S3" "Amazon DynamoDB"))))
;; => (#<THREAD > #<THREAD >)

(selet-dyna 'thread (where (:in :forum-name '("Amazon S3" "Amazon DynamoDB")))
                    :limit 1)
;; => (#<THREAD >)

(selet-dyna 'thread (where (:in :forum-name '("Amazon S3" "Amazon DynamoDB")))
                    (limit 1))
;; => (#<THREAD >)

(select-dyna 'thread :segments 4)
;; => (#<THREAD > <#THREAD >)
  • returns the list of objects.
  • can handle Extended Where Clause of SxQL.
  • can handle LastEvaluatedKey in the response.
  • :limit can restrict the number of results.
  • can handle Limit Clause of SxQL.
  • :segments can make scan request divided.

save-dyna

(save-dyna (make-instance 'thread :forum-name "Amazon DynamoDB"
                                  :subject "Really useful"))
;; =>
  • can return T if the object is successfully saved.

Low Level API

Most Low Level API return multiple values, the formaer is formatted result, and the latter is raw result.

fetch

(fetch (cons "access-key" "secret-key") "ap-northeast-1" "ListTables" "{}")
;; => #(...)
  • returns raw octets of reponse.

batch-get-item

(batch-get-item dyna :request-items '(("Forum" . (("Keys" . ((("Id" . 1))
                                                             (("Id" . 2))))
                                                  ("ProjectionExpression" . "Id, Title, Author")))
                                      ("Thread" . (("Keys" . ((("ForumName" . "Amazon DynamoDB")
                                                               ("Subject" . "Concurrent reads"))))
                                                  ("AttributesToGet" . "ForumName, Subject"))))
                     :return-consumed-capacity "TOTAL")))
;; => (("Forum" (("Id" . 1) ("Title" . "Enjoy Lisp") ("Author" . "Rudolph-Miller"))
;;              (("Id" . 2) ("Title" . "Sophisticated Programming Language") ("Author" . "Lisp-Alien")))
;;     ("Thread" (("ForumName" . "Amazon DynamoDB") ("Subject" . "Concurrent reads"))))
  • returns the list of alists.
  • Support
    • :request-items
    • :return-consumed-capacity

batch-write-item

(batch-write-item dyna :request-items '(("Forum" . ((("PutRequest" . (("Item" . (("Name" . "Amazon DynamoDB")
                                                                                 ("Category" . "Amazon Web Services"))))))
                                                    (("PutRequest" . (("Item" . (("Name" . "Amazon RDS")
                                                                                 ("Category" . "Amazon Web Services"))))))))
                                        ("Thread" . ((("PutRequest" . (("Item" . (("ForumName" . "Amazon DynamoDB")
                                                                                  ("Subject" . "Concurrent reads")))))))))
                       :return-consumed-capacity "TOTAL")
;; => T
  • returns t if the operation succeeded.
  • Support
    • :request-items
    • :return-consumed-capacity
    • :return-item-collection-metrics

create-table

(create-table dyna :table-name "Thread"
                   :key-schema '((("AttributeName" . "ForumName") ("KeyType" . "HASH"))
                                 (("AttributeName" . "Subject") ("KeyType" . "RANGE")))
                   :attribute-definitions '((("AttributeName" . "ForumName") ("AttributeType" . "S"))
                                            (("AttributeName" . "Subject") ("AttributeType" . "S"))
                                            (("AttributeName" . "LastPostDateTime") ("AttributeType" . "S")))
                   :local-secondary-indexes '((("IndexName" . "LastPostIndex")
                                               ("KeySchema" . ((("AttributeName" . "ForumName")
                                                                ("KeyType" . "HASH"))
                                                               (("AttributeName" . "LastPostDateTime")
                                                                ("KeyType" . "RANGE"))))
                                               ("Projection" . (("ProjectionType" . "KEYS_ONLY")))))
                   :provisioned-throughput '(("ReadCapacityUnits" . 5)
                                             ("WriteCapacityUnits" . 5)))
;; => T
  • returns t if the operation succeeded.
  • Support
    • :table-name
    • :attribute-definitions
    • :key-schema
    • :global-secondary-indexes
    • :local-secondary-indexes
    • :provisioned-throughput

delete-item

(delete-item dyna :table-name "Thread"
                  :key '(("ForumName" . "Amazon DynamoDB"))
                  :condition-expression "attribute_not_exists(Replies)"
                  :return-values "ALL_OLD")
;; => T
  • returns t if the operation succeeded.
  • Support
    • :table-name
    • :key
    • :condition-expression
    • :return-values
    • :expression-attribute-names
    • :expression-attribute-values
    • :return-consumed-capacity
    • :return-item-collection-metrics

delete-table

(delete-table dyna :table-name "Thread")
;; => T
  • returns t if the operation succeeded.
  • Support
    • :table-name

describe-table

(describe-table dyna :table-name "Thread")
  • returns the jsown object of table description.
  • Support
    • :table-name

get-item

(get-item dyna :table-name "Thread"
               :key '(("Tags" . ("Multiple Items" "HelpMe")))
               :consistent-read t
               :return-consumed-capacity "TOTAL")
;; => (("Tags" "Multiple Items" "HelpMe") ("ForumName" . "Amazon DynamoDB"))
  • returns the alist of item.
  • Support
    • :table-name
    • :key
    • :projection-expression
    • :consistent-read
    • :return-consumed-capacity
    • :expression-attribute-names

list-tables

(list-tables-content dyna)
;; => ("Thread")
  • returns the list of table names.
  • Support
    • :exclusive-start-table-name
    • :limit

put-item

(put-item dyna :table-name "Thread"
                :item '(("Tags" . ("Multiple Items" "HelpMe"))
                        ("ForumName" . "Amazon DynamoDB"))
                :condition-expression "ForumName <> :f and Subject <> :s"
                :expression-attribute-values '((":f" . "Amazon DynamoDB")
                                               (":s" . "update multiple items")))
;; => T
  • returns t if the operation succeeded.
  • Support
    • :table-name
    • :item
    • :on-expression
    • :expression-attribute-values
    • :expression-attribute-names
    • :return-consumed-capacity
    • :return-item-collection-metrics
    • :return-values

query

(query dyna
       :table-name "Thread"
       :select "SPECIFIC_ATTRIBUTES"
       :attributes-to-get '("ForumName" "Subject")
       :limit 3
       :key-conditions '(("ForumName" . (("AttributeValueList" . ("Amazon DynamoDB"))
                                         ("ComparisonOperator" . "EQ"))))
       :return-consumed-capacity "TOTAL")
;; => ((("ForunName" . "Amazon DynamoDB") ("Subject" . "Concurrent reads")))
  • returns list of alists.
  • Support
    • :table-name
    • :key-conditions
    • :return-consumed-capacity
    • :attributes-to-get
    • :index-name
    • :select
    • :limit
    • :consistent-read
    • :conditional-operator
    • :exclusive-start-key
    • :expression-attribute-values
    • :expression-attribute-names
    • :filter-expression
    • :projection-expression
    • :query-filter
    • :scan-index-forward

scan

(scan dyna :table-name "Thread"
           :projection-expression "ForumName,Subject"
           :limit 3
           :filter-expression "Replies > :num"
           :expression-attribute-values '((":num" . 10))
           :scan-index-forward t
           :return-consumed-capacity "TOTAL")
;; => ((("ForunName" . "Amazon DynamoDB") ("Subject" . "Concurrent reads")))
  • returns list of alists.
  • Support
    • :table-name
    • :key-conditions
    • :return-consumed-capacity
    • :attributes-to-get
    • :index-name
    • :select
    • :limit
    • :consistent-read
    • :conditional-operator
    • :exclusive-start-key
    • :expression-attribute-values
    • :expression-attribute-names
    • :filter-expression
    • :projection-expression
    • :scan-filter
    • :scan-index-forward
    • :segment
    • :total-segments

update-item

(update-item dyna :table-name "Thread"
                  :key '(("ForumName" . "Amazon DynamoDB"))
                  :update-expression "set Replies = Replies + :num"
                  :expression-attribute-values '((":num" . 1))
                  :return-values "NONE")
;; => T
  • returns t if the operation succeeded.
  • Support
    • :table-name
    • :key
    • :update-expression
    • :expression-attribute-names
    • :expression-attribute-values
    • :return-values
    • :return-consumed-capacity
    • :return-item-collection-metrics

update-table

(update-table dyna :table-name "Thread"
                   :attribute-definitions '((("AttributeName" . "ForumName")
                                            ("AttributeType" . "S"))
                                            (("AttributeName" . "Subject")
                                            ("AttributeType" . "S"))
                                            (("AttributeName" . "LastPostDateTime")
                                            ("AttributeType" . "S")))
                   :provisioned-throughput '(("ReadCapacityUnits" . 5)
                                             ("WriteCapacityUnits" . 5))
                   :global-secondary-index-updates '((("Create" . (("IndexName" . "LastPostIndex")
                                                                   ("KeySchema" . ((("AttributeName" . "Subject")
                                                                                    ("KeyType" . "HASH"))
                                                                                   (("AttributeName" . "LastPostDateTime")
                                                                                    ("KeyType" . "RANGE"))))
                                                                   ("Projection" .(("ProjectionType" . "ALL")))
                                                                   ("ProvisionedThroughput" . (("ReadCapacityUnits" . 5)
                                                                                    ("WriteCapacityUnits" . 5))))))))
;; => T
  • returns t if the operation succeeded.
  • Support
    • :table-name
    • :attribute-definitions
    • :provisioned-throughput
    • :global-secondary-index-updates

Extended Where Clause

  • You can use ordinary operators.
  • Extended operators are below. (:between, :begins-with, :contains, :list=, :list-in)
(where (:between :forum-name '("A" "Z")))
(where (:begins-with :forum-name "Amazon"))
(where (:contains :forum-name "RDS"))

;; If Attribute Type of "Tags" is "SS", you query := and :in with :list= and :list-in respectively.
(where (:list= :tags '("AWS" "Easy")))
(where (:list-in :tags '(("AWS" "Easy") ("Scalable"))))

See Also

  • SxQL - A SQL generator.

Author

Copyright

Copyright (c) 2015 Rudolph-Miller ([email protected])

License

Licensed under the MIT License.

About

Dyna is an AWS DynamoDB ORM for Common Lisp.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published