/readme.md

http://github.com/budu/lobos · Markdown · 291 lines · 222 code · 69 blank · 0 comment · 0 complexity · 261d684e85cb6a89fae5c7b83fa00684 MD5 · raw file

  1. # Lobos
  2. [![Continuous Integration status](https://secure.travis-ci.org/budu/lobos.png)](http://travis-ci.org/budu/lobos)
  3. **Lobos** is a SQL database schema manipulation and migration library
  4. written in [Clojure]. It currently support supports H2, MySQL,
  5. PostgreSQL, SQLite and SQL Server.
  6. If you have any questions, please join the [mailing list].
  7. ## Features
  8. * A comprehensive data definition language DSL.
  9. * Migrations for schema changes.
  10. * An analyzer to query the schema.
  11. ## Installation
  12. Lobos is available through [Clojars].
  13. For the latest release, in Cake/Leiningen, use:
  14. #### `project.clj`
  15. ```clojure
  16. :dependencies [[lobos "1.0.0-beta3"]]
  17. ```
  18. or in Maven:
  19. #### `pom.xml`
  20. ```xml
  21. <dependency>
  22. <groupId>lobos</groupId>
  23. <artifactId>lobos</artifactId>
  24. <version>1.0.0-beta3</version>
  25. </dependency>
  26. ```
  27. ## Usage
  28. Here's a small tutorial on how to use Lobos.
  29. ### Basic Example
  30. Start by creating a new project with your preferred tool. Assuming a
  31. [Leiningen] compatible project file, add **Lobos** and a database driver
  32. to the `dependencies` section:
  33. ```clojure
  34. :dependencies [...
  35. [lobos "1.0.0-beta1"]
  36. [postgresql "9.1-901.jdbc4"]]
  37. ```
  38. Once you have your dependencies downloaded, open up a REPL and load
  39. these namespaces:
  40. ```clojure
  41. (use '(lobos connectivity core schema))
  42. ```
  43. You'll get warnings about some already defined function, just ignore
  44. this for now.
  45. Then you'll need to create a connection, the following snippet define
  46. one and makes it the default global connection:
  47. ```clojure
  48. (def db
  49. {:classname "org.postgresql.Driver"
  50. :subprotocol "postgresql"
  51. :user "test"
  52. :password "test123"
  53. :subname "//localhost:5432/test"})
  54. (open-global db)
  55. ```
  56. You can now send DDL statements (called *actions*) directly like this:
  57. ```clojure
  58. (create (table :users (integer :id :unique)))
  59. ```
  60. You can omit the connection altogether. In that case, actions will use
  61. the connection bound by `lobos.connectivity/with-connection` or the
  62. default one.
  63. ```clojure
  64. (drop (table :users))
  65. ```
  66. Now that you've tested the basics of **Lobos** at the REPL, let's try
  67. out a more real-world example.
  68. ### Real-world Example
  69. By *real-world*, I'm not talking about a production ready database
  70. schema, it's about how to integrate **Lobos** into your real
  71. projects. We'll continue using the previously created test project, but
  72. this time we'll use files. In your `src/` directory, create a directory
  73. named `lobos` and a file called `config.clj` inside it.
  74. #### `src/lobos/config.clj`
  75. ```clojure
  76. (ns lobos.config
  77. (:use lobos.connectivity))
  78. (def db
  79. {:classname "org.postgresql.Driver"
  80. :subprotocol "postgresql"
  81. :user "test"
  82. :password "test123"
  83. :subname "//localhost:5432/test"})
  84. (open-global db)
  85. ```
  86. Next, we'll see how to create helpers that will show the composable
  87. nature of the **Lobos** DSL. This part is entirely optional.
  88. Add a new file called `helpers.clj`
  89. #### `src/lobos/helpers.clj`
  90. ```clojure
  91. (ns lobos.helpers
  92. (:refer-clojure :exclude [bigint boolean char double float time])
  93. (:use (lobos schema)))
  94. ```
  95. The above namespace declaration exclude some `clojure.core` definitions
  96. that clashes with data-type functions, this prevents warnings from being
  97. shown.
  98. Every schema element definition is a simple function that return an
  99. intermediate representation that abstract real database schema element.
  100. This allow you to make your own functions (and macros) that can help
  101. define a database schema more concisely.
  102. Now, let's define a bunch of useful helpers:
  103. #### `src/lobos/helpers.clj`
  104. ```clojure
  105. (defn surrogate-key [table]
  106. (integer table :id :auto-inc :primary-key))
  107. (defn timestamps [table]
  108. (-> table
  109. (timestamp :updated_on)
  110. (timestamp :created_on (default (now)))))
  111. (defn refer-to [table ptable]
  112. (let [cname (-> (->> ptable name butlast (apply str))
  113. (str "_id")
  114. keyword)]
  115. (integer table cname [:refer ptable :id :on-delete :set-null])))
  116. ```
  117. The first one add a standardized surrogate key called `id` to the
  118. specified table. The second takes a table definition and add two
  119. generally useful columns to it. Finally, the third one create a
  120. foreign-key column to another table given its name. We can use these
  121. helpers in the same way as already existing column definition functions.
  122. To wrap it up, we'll add a macro that we'll use instead of the included
  123. `table` macro. It will help us create tables which implicitly include a
  124. surrogate key and the timestamp columns.
  125. #### `src/lobos/helpers.clj`
  126. ```clojure
  127. (defmacro tbl [name & elements]
  128. `(-> (table ~name)
  129. (timestamps)
  130. ~@(reverse elements)
  131. (surrogate-key)))
  132. ```
  133. We have everything set up in place to create our first migrations, so
  134. let's do that.
  135. ### Migrations
  136. By default all migrations are kept in the `lobos.migrations`
  137. namespace. It'll get automatically loaded by migration commands, so
  138. there's no need to load it yourself. Thus, to use another namespace you
  139. must change the `lobos.migration/*migrations-namespace*` dynamic
  140. variable. This is a normal Clojure source file so if you prefer having
  141. only one migration per file, just do that and require these files in the
  142. migrations namespace.
  143. #### `src/lobos/migrations.clj`
  144. ```clojure
  145. (ns lobos.migrations
  146. (:refer-clojure :exclude [alter drop
  147. bigint boolean char double float time])
  148. (:use (lobos [migration :only [defmigration]] core schema
  149. config helpers)))
  150. ```
  151. Migrations are defined using the `defmigration` macro which is composed
  152. of two bodies, one making whatever changes you want to do, the other
  153. reverting those changes.
  154. #### `src/lobos/migrations.clj`
  155. ```clojure
  156. (defmigration add-users-table
  157. (up [] (create
  158. (tbl :users
  159. (varchar :name 100 :unique)
  160. (check :name (> (length :name) 1)))))
  161. (down [] (drop (table :users))))
  162. (defmigration add-posts-table
  163. (up [] (create
  164. (tbl :posts
  165. (varchar :title 200 :unique)
  166. (text :content)
  167. (refer-to :users))))
  168. (down [] (drop (table :posts))))
  169. (defmigration add-comments-table
  170. (up [] (create
  171. (tbl :comments
  172. (text :content)
  173. (refer-to :users)
  174. (refer-to :posts))))
  175. (down [] (drop (table :comments))))
  176. ```
  177. Each migrations must have a unique name that will be used by **Lobos**
  178. to figure out which ones have been applied.
  179. To apply all pending migrations, use the `migrate` function in a REPL:
  180. ```clojure
  181. (migrate)
  182. ;=> add-users-table
  183. ;=> add-posts-table
  184. ;=> add-comments-table
  185. ```
  186. This function can take a bunch of migration names in which case it will
  187. only apply those.
  188. If, for some reason, you need to rollback some migrations, use the aptly
  189. named `rollback` function:
  190. ```clojure
  191. (rollback)
  192. ;=> add-comments-table
  193. ```
  194. By default it will rollback only the most recently applied migration. It
  195. can also take migration names, an integer or the `:all` keyword and
  196. perform the appropriate rollback.
  197. ### Analyzer
  198. Lobos includes a database analyzer which use the database meta-data or
  199. information schema to construct an abstract schema definition from an
  200. actual database schema.
  201. Here's an interactive session that show some possible uses:
  202. ```clojure
  203. (use 'lobos.analyzer)
  204. ;=> nil
  205. (-> (analyze-schema) :tables keys)
  206. ;=> (:comments :lobos_migrations :posts :users)
  207. (-> (analyze-schema) :tables :users :columns :name :data-type :name)
  208. ;=> :varchar
  209. (-> (analyze-schema) :tables :posts :constraints :posts_unique_title :columns)
  210. ;=> [:title]
  211. ```
  212. ### Documentation
  213. For more detailed information on **Lobos**, please refer to the
  214. [documentation].
  215. ## License
  216. Distributed under the [Eclipse Public License], the same as Clojure.
  217. [Clojure]: http://clojure.org/
  218. [mailing list]: http://groups.google.com/group/lobos-library
  219. [Clojars]: http://clojars.org/lobos
  220. [Leiningen]: https://github.com/technomancy/leiningen
  221. [Eclipse Public License]: http://budu.github.com/lobos/epl-v10.html
  222. [documentation]: http://budu.github.com/lobos/documentation.html