]> gitweb.factorcode.org Git - factor.git/blob - basis/db/db-docs.factor
77474fffbd883cb079b85c99baad54dd03830679
[factor.git] / basis / db / db-docs.factor
1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: classes kernel help.markup help.syntax sequences
4 alien assocs strings math quotations db.private ;
5 IN: db
6
7 HELP: db-connection
8 { $description "The " { $snippet "db-connection" } " class is the superclass of all other database classes. It stores a " { $snippet "handle" } " to the database as well as insert, update, and delete queries. Stores the current database object as a dynamic variable." } ;
9
10 HELP: new-db-connection
11 { $values { "class" class } { "obj" db-connection } }
12 { $description "Creates a new database object from a given class with caches for prepared statements. Does not actually connect to the database until " { $link db-open } " or " { $link with-db } " is called." }
13 { $notes "User-defined databases must call this constructor word instead of " { $link new } "." } ;
14
15 HELP: db-open
16 { $values { "db" "a database configuration object" } { "db-connection" db-connection } }
17 { $description "Opens a database using the configuration data stored in a " { $snippet "database configuration object" } "tuple. The database object now references a database handle that must be cleaned up. Therefore, it is better to use the " { $link with-db } " combinator than calling this word directly." } ;
18
19 HELP: db-close
20 { $values { "handle" alien } }
21 { $description "Closes a database using the handle provided. Use of the " { $link with-db } " combinator is preferred over manually opening and closing databases so that resources are not leaked." } ;
22
23 { db-open db-close with-db } related-words
24
25 HELP: dispose-statements
26 { $values { "assoc" assoc } }
27 { $description "Disposes an associative list of statements." } ;
28
29 HELP: statement
30 { $description "A " { $snippet "statement" } " stores the information about a statemen, such as the SQL statement text, the in/out parameters, and type information." } ;
31
32 HELP: result-set
33 { $description "An object encapsulating a raw SQL result object. There are two ways in which a result set can be accessed, but they are specific to the database backend in use."
34     { $subsection "db-random-access-result-set" }
35     { $subsection "db-sequential-result-set" }
36 } ;
37
38 HELP: new-result-set
39 { $values
40      { "query" "a query" } { "handle" alien } { "class" class }
41      { "result-set" result-set } }
42 { $description "Creates a new " { $link result-set } " object of type " { $snippet "class" } "." } ;
43
44 HELP: new-statement
45 { $values { "sql" string } { "in" sequence } { "out" sequence } { "class" class } { "statement" statement } }
46 { $description "Makes a new statement object from the given parameters." } ;
47
48 HELP: bind-statement
49 { $values
50      { "obj" object } { "statement" statement } }
51 { $description "Sets the statement's " { $slot "bind-params" } " and calls " { $link bind-statement* } " to do the database-specific bind. Sets " { $slot "bound?" } " to true if binding succeeds." } ;
52
53 HELP: bind-statement*
54 { $values
55      { "statement" statement } }
56 { $description "Does a low-level bind of the SQL statement's tuple parameters if the database requires. Some databases should treat this as a no-op and bind instead when the actual statement is run." } ;
57
58 HELP: <simple-statement>
59 { $values { "string" string } { "in" sequence } { "out" sequence }
60     { "statement" statement } }
61 { $description "Makes a new simple statement object from the given parameters.." }
62 { $warning "Using a simple statement can lead to SQL injection attacks in PostgreSQL. The Factor database implementation for SQLite only uses " { $link <prepared-statement> } " as the sole kind of statement; simple statements alias to prepared ones." } ;
63
64 HELP: <prepared-statement>
65 { $values { "string" string } { "in" sequence } { "out" sequence }
66     { "statement" statement } }
67 { $description "Makes a new prepared statement object from the given parameters. A prepared statement's parameters will be escaped by the database backend to avoid SQL injection attacks. Prepared statements should be preferred over simple statements." } ;
68
69 HELP: prepare-statement
70 { $values { "statement" statement } }
71 { $description "For databases which implement a method on this generic, it does some internal processing to ready the statement for execution." } ;
72
73 HELP: low-level-bind
74 { $values
75      { "statement" statement } }
76 { $description "For use with prepared statements, methods on this word should bind the datatype in the SQL spec to its identifier in the SQL string. To name bound variables, SQLite uses identifiers in the form of " { $snippet ":name" } ", while PostgreSQL uses increasing numbers beginning with a dollar sign, e.g. " { $snippet "$1" } "." } ;
77
78 HELP: query-results
79 { $values { "query" object }
80     { "result-set" result-set }
81 }
82 { $description "Returns a " { $link result-set } " object representing the results of a SQL query. See " { $link "db-result-sets" } "." } ;
83
84 HELP: #rows
85 { $values { "result-set" result-set } { "n" integer } }
86 { $description "Returns the number of rows in a result set." } ;
87
88 HELP: #columns
89 { $values { "result-set" result-set } { "n" integer } }
90 { $description "Returns the number of columns in a result set." } ;
91
92 HELP: row-column
93 { $values { "result-set" result-set } { "column" integer }
94     { "obj" object }
95 }
96 { $description "Returns the value indexed by " { $snippet "column" } " in the current row of a " { $link result-set } "." } ;
97
98 HELP: row-column-typed
99 { $values { "result-set" result-set } { "column" integer }
100     { "sql" "sql" } }
101 { $description "Returns the value indexed by " { $snippet "column" } " in the current row of a " { $link result-set } " and converts the result based on a type stored in the " { $link result-set } "'s " { $slot "out-params" } "." } ;
102
103 HELP: advance-row
104 { $values { "result-set" result-set } }
105 { $description "Advanced the pointer to an underlying SQL result set stored in a " { $link result-set } " object." } ;
106
107 HELP: more-rows?
108 { $values { "result-set" result-set } { "?" "a boolean" } }
109 { $description "Returns true if the " { $link result-set } " has more rows to traverse." } ;
110
111
112
113 HELP: begin-transaction
114 { $description "Begins a new transaction. User code should make use of the " { $link with-transaction } " combinator." } ;
115
116 HELP: commit-transaction
117 { $description "Commits a transaction. User code should make use of the " { $link with-transaction } " combinator." } ;
118
119 HELP: in-transaction
120 { $description "A variable that is set true when a transaction is in progress." } ;
121
122 HELP: in-transaction?
123 { $values
124      { "?" "a boolean" } }
125 { $description "Returns true if there is currently a transaction in progress in this scope." } ;
126
127 HELP: query-each
128 { $values
129      { "statement" statement } { "quot" quotation } }
130 { $description "A combinator that calls a quotation on a sequence of SQL statements to their results query results." } ;
131
132 HELP: query-map
133 { $values
134      { "statement" statement } { "quot" quotation }
135      { "seq" sequence } }
136 { $description "A combinator that maps a sequence of SQL statements to their results query results." } ;
137
138 HELP: rollback-transaction
139 { $description "Rolls back a transaction; no data is committed to the database. User code should make use of the " { $link with-transaction } " combinator." } ;
140
141 HELP: sql-command
142 { $values
143      { "sql" string } }
144 { $description "Executes a SQL string using the databse in the " { $link db-connection } " symbol." } ;
145
146 HELP: sql-query
147 { $values
148      { "sql" string }
149      { "rows" "an array of arrays of strings" } }
150 { $description "Runs a SQL query of raw text in the database in the " { $link db-connection } " symbol. Each row is returned as an array of strings; no type-conversions are done on the resulting data." } ;
151
152 { sql-command sql-query } related-words
153
154 HELP: sql-row
155 { $values
156      { "result-set" result-set }
157      { "seq" sequence } }
158 { $description "Returns the current row in a " { $link result-set } " as an array of strings." } ;
159
160 HELP: sql-row-typed
161 { $values
162      { "result-set" result-set }
163      { "seq" sequence } }
164 { $description "Returns the current row in a " { $link result-set } " as an array of typed Factor objects." } ;
165
166 { sql-row sql-row-typed } related-words
167
168 HELP: with-db
169 { $values
170      { "db" "a database configuration object" } { "quot" quotation } }
171 { $description "Calls the quotation with a database bound to the " { $link db-connection } " symbol. See " { $link "db-custom-database-combinators" } " for help setting up database access." } ;
172
173 HELP: with-transaction
174 { $values
175      { "quot" quotation } }
176 { $description "Calls the quotation inside a database transaction and commits the result to the database after the quotation finishes. If the quotation throws an error, the transaction is aborted." } ;
177
178 ARTICLE: "db" "Database library"
179 "Accessing a database:"
180 { $subsection "db-custom-database-combinators" }
181 "Higher-level database help:"
182 { $vocab-subsection "Database types" "db.types" }
183 { $vocab-subsection "High-level tuple/database integration" "db.tuples" }
184 "Low-level database help:"
185 { $subsection "db-protocol" }
186 { $subsection "db-result-sets" }
187 { $subsection "db-lowlevel-tutorial" }
188 "Supported database backends:"
189 { $vocab-subsection "SQLite" "db.sqlite" }
190 { $vocab-subsection "PostgreSQL" "db.postgresql" } ;
191
192 ARTICLE: "db-random-access-result-set" "Random access result sets"
193 "Random-access result sets do not have to be traversed in order. For instance, PostgreSQL's result set object can be accessed as a matrix with i,j coordinates."
194 $nl
195 "Databases which work in this way must provide methods for the following traversal words:"
196 { $subsection #rows }
197 { $subsection #columns }
198 { $subsection row-column }
199 { $subsection row-column-typed } ;
200
201 ARTICLE: "db-sequential-result-set" "Sequential result sets"
202 "Sequential result sets can be iterated one element after the next. SQLite's result sets offer this method of traversal."
203 $nl
204 "Databases which work in this way must provide methods for the following traversal words:"
205 { $subsection more-rows? }
206 { $subsection advance-row }
207 { $subsection row-column }
208 { $subsection row-column-typed } ;
209
210 ARTICLE: "db-result-sets" "Result sets"
211 "Result sets are the encapsulated, database-specific results from a SQL query."
212 $nl
213 "Two possible protocols for iterating over result sets exist:"
214 { $subsection "db-random-access-result-set" }
215 { $subsection "db-sequential-result-set" }
216 "Query the number of rows or columns:"
217 { $subsection #rows }
218 { $subsection #columns }
219 "Traversing a result set:"
220 { $subsection advance-row }
221 { $subsection more-rows? }
222 "Pulling out a single row of results:"
223 { $subsection row-column }
224 { $subsection row-column-typed } ;
225
226 ARTICLE: "db-protocol" "Low-level database protocol"
227 "The high-level protocol (see " { $vocab-link "db.tuples" } ") uses this low-level protocol for executing statements and queries." $nl
228 "Opening a database:"
229 { $subsection db-open }
230 "Closing a database:"
231 { $subsection db-close }
232 "Creating statements:"
233 { $subsection <simple-statement> }
234 { $subsection <prepared-statement> }
235 "Using statements with the database:"
236 { $subsection prepare-statement }
237 { $subsection bind-statement* }
238 { $subsection low-level-bind }
239 "Performing a query:"
240 { $subsection query-results }
241 "Handling query results:"
242 { $subsection "db-result-sets" }
243 ;
244 ! { $subsection bind-tuple }
245
246 ARTICLE: "db-lowlevel-tutorial" "Low-level database tutorial"
247 "Although Factor makes integrating a database with its object system easy (see " { $vocab-link "db.tuples" } "), sometimes you may want to write SQL directly and get the results back as arrays of strings, for instance, when interfacing with a legacy database that doesn't easily map to " { $snippet "tuples" } "." $nl
248 "Executing a SQL command:"
249 { $subsection sql-command }
250 "Executing a query directly:"
251 { $subsection sql-query }
252 "Here's an example usage where we'll make a book table, insert some objects, and query them." $nl
253 "First, let's set up a custom combinator for using our database. See " { $link "db-custom-database-combinators" } " for more details."
254 { $code """
255 USING: db.sqlite db io.files io.files.temp ;
256 : with-book-db ( quot -- )
257     "book.db" temp-file <sqlite-db> swap with-db ; inline" }
258 "Now let's create the table manually:"
259 { $code " "create table books
260     (id integer primary key, title text, author text, date_published timestamp,
261      edition integer, cover_price double, condition text)"
262     [ sql-command ] with-book-db""" }
263 "Time to insert some books:"
264 { $code """
265 "insert into books
266     (title, author, date_published, edition, cover_price, condition)
267     values('Factor for Sheeple', 'Mister Stacky Pants', date('now'), 1, 13.37, 'mint')"
268 [ sql-command ] with-book-db""" }
269 "Now let's select the book:"
270 { $code """
271 "select id, title, cover_price from books;" [ sql-query ] with-book-db""" }
272 "Notice that the result of this query is a Factor array containing the database rows as arrays of strings. We would have to convert the " { $snippet "cover_price" } " from a string to a number in order to use it in a calculation." $nl
273 "In conclusion, this method of accessing a database is supported, but it is fairly low-level and generally specific to a single database. The " { $vocab-link "db.tuples" } " vocabulary is a good alternative to writing SQL by hand." ;
274
275 ARTICLE: "db-custom-database-combinators" "Custom database combinators"
276 "Every database library requires some effort on the programmer's part to initialize and open a database. SQLite uses files on your harddisk, so a simple pathname is all the setup required. With PostgreSQL, you log in to a networked server as a user on a specfic port." $nl
277
278 "Make a " { $snippet "with-" } " combinator to open and close a database so that resources are not leaked." $nl
279
280 "SQLite example combinator:"
281 { $code """
282 USING: db.sqlite db io.files io.files.temp ;
283 : with-sqlite-db ( quot -- )
284     "my-database.db" temp-file <sqlite-db> swap with-db ; inline""" } 
285
286 "PostgreSQL example combinator:"
287 { $code """USING: db.postgresql db ;
288 : with-postgresql-db ( quot -- )
289     <postgresql-db>
290         "localhost" >>host
291         5432 >>port
292         "erg" >>username
293         "secrets?" >>password
294         "factor-test" >>database
295     swap with-db ; inline"""
296 } ;
297
298 ABOUT: "db"