The oook Reference Manual

Next: , Previous: , Up: (dir)   [Contents][Index]

The oook Reference Manual

This is the oook Reference Manual, version 0.2.0, generated automatically by Declt version 4.0 beta 2 "William Riker" on Wed Jun 15 05:28:09 2022 GMT+0.

Table of Contents


1 Introduction

OOOK!

Quicklisp License: MIT

OOOK is some data manipulation magic on top of the venerable CL-SQL package, which has been providing a solid SQL abstraction in Common Lisp for years.

The goal of OOOK is to greatly decrease "standard" database-driven web application development time with the trade-off of slightly less flexiblity. With that in mind, some of the features include:

Note: Database design should be driven by the data, not by the code that uses it! To encourage this, OOOK will never have functionality to manipulate the database schema.

Also, OOOK is still under development and the API is changing fairly frequently. It is regularly used in its present state, however, and is mostly stable.

Overview

Create models of tables in the database with defmodel:

(oook:defmodel post (:belongs-to user)
  "Some interesting prose, full of wisdom"
  (date_published :type clsql:wall-time)
  (title :column "post-title")
  content)

(oook:defmodel user (:has-many posts)
  "Someone who writes posts"
  name
  (level :type integer :documentation "Skill level"))

This creates two CLOS classes which model the "post" and "user" database tables, including the relationship between the two. The models have brief dostrings, custom slots (including types) and associations with other models.

Note: the defmodel macro creates two CLSQL view-classes, using clsql:def-view-class, containing the specified slots and a number of additional slots for managing the joins.

Example Workflow:

Create a new user using the standard CLOS make-instance:

(defvar wizzard
  (make-instance 'user :name "Rincewind" :level 0))

Create a new post and add it to the user:

(push (posts wizzard) (make-instance 'post :title "On Staying Alive")))

Save the new user (and post) in the database:

(oook:save wizzard)  ; Will save both the user and his post

Find something, either by ID with the built-in find-by-id helper, or construct a CLSQL statement for more complex queries (OOOK provides a few other helpers, see the documentation).

(oook:find-by-id 'post 2)  ; Find the post row with ID == 2
(clsql:select 'user)  ; Select all users

POST/JSON serialisation

OOOK makes it simple to build a model instance given a set of POST data, as long as the POST data is constructed according to a few rules. If you use the HTML generation helpers below, this is handled automatically!

More documentation coming soon... But have a look at serialise.lisp!

HTML Generation

OOOK provides some utilties for viewing and editing model data. In the simplest form, you can generate an HTML form to modify a model with a few lines:

(let ((the-post (make-instance 'post :title "New Post")))
  (oook:get-edit-form the-post "/save"))

With the previous definition of post, this returns the following HTML.

<form class="ui form" action=/save method=POST>
 <div class=field>
  <label>Content</label>
  <input type=text name=post[content]> 
 </div>
 <div class=field>
  <label>Title</label>
  <input type=text name=post[title] value="New Post"> 
 </div>
 <div class=field>
  <label>Date_Published</label>
  <input type=date name=post[date_published]> 
 </div>
 <div class=field>
  <label>User Id</label>
  <input type=number name=post[user_id]> 
 </div>
 <button class="ui primary button" type=submit>Save</button> 
</form>

Things to note

Custom Built Forms

OOOK provides a context manager, with-record-type to make it easier to build custom forms.

Documentation coming soon... But have a look at html.lisp!

Utilities

Enhanced printing

Use oook:def-enhanced-printer to quickly enhance the printed representations of models.

CL-USER> (oook:def-enhanced-printer post :slot 'title)
...
CL-USER> (format t (oook:find-by-id 'post 5))
#<POST "The Joys of Boredom">

Models Implementation Notes

Overview

Like another well known library, all tables are expected to have at least these three columns:

These have historically been found to be useful in typical web applications. The id field is always required, and will be an index into the table. The second two can be disabled by passing :timestamped nil to defmodel.

In addition, models you define will typically have a number of other fields, corresponding to columns in the table, and possibly a number of associated models.

Associated models

A model can be associated to other models in a number of ways.

Models are selected exactly as you would with CL-SQL, and, by default, the joins are lazily loaded (i.e. a "join" slot is only populated from the DB when it is accessed).

The fun part is saving.

oook:save will save any associated models that belong to the instance it is called with. New rows will be created as necessary.

has-one (FK in Left)

Left requires one instance of Right, but Right doesn't care or know about this relationship. (e.g. ingredient -> unit).

owns-one (FK in right) - use with belongs-to (blargh redundancy)

Left owns one Right, and Right knows it. Left cannot have more than one Right. (e.g. user <- config)

belongs-to (FK in Left) - use with owns-many or owns-one

Left is owned by one Right. Left cannot have more than one owner. (e.g. config <- user). However Right might have more than one Left (e.g. step* <- recipe)

owns-many (FK in Right) - use with belongs-to

Left has many Rights, and the Rights know which Left they belong to. (e.g. recipe <- step*)

many-to-many (intersection table)

Not implemented yet

Left references many instances of Right, and Right might be referenced by many instances of Left. (e.g. programmer <-> project, a programmer is part of many projects and a project has many programmers)

Get: do not try to resolve the parent relation (circular dep)

LICENSE

MIT License

Copyright (c) 2017 Ricardo M. H. da Silva

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


2 Systems

The main system appears first, followed by any subsystem dependency.


Previous: , Up: Systems   [Contents][Index]

2.1 oook

Some magic on the shoulders of CLSQL

Author

Ric da Silva <ric@rmhsilva.com>

License

MIT

Version

0.2.0

Dependencies
  • alexandria (system).
  • anaphora (system).
  • cl-inflector (system).
  • closer-mop (system).
  • clsql (system).
  • jonathan (system).
  • parse-number (system).
  • semantic-spinneret (system).
  • spinneret (system).
Source

oook.asd.

Child Component

src (module).


Next: , Previous: , Up: The oook Reference Manual   [Contents][Index]

3 Modules

Modules are listed depth-first from the system components tree.


Previous: , Up: Modules   [Contents][Index]

3.1 oook/src

Source

oook.asd.

Parent Component

oook (system).

Child Components

4 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Previous: , Up: Files   [Contents][Index]

4.1 Lisp


Next: , Previous: , Up: Lisp   [Contents][Index]

4.1.1 oook/oook.asd

Source

oook.asd.

Parent Component

oook (system).

ASDF Systems

oook.


Next: , Previous: , Up: Lisp   [Contents][Index]

4.1.2 oook/src/package.lisp

Source

oook.asd.

Parent Component

src (module).

Packages

4.1.3 oook/src/utils.lisp

Source

oook.asd.

Parent Component

src (module).

Public Interface
Internals

4.1.4 oook/src/serialise.lisp

Source

oook.asd.

Parent Component

src (module).

Public Interface
Internals

get-slot-type (function).


4.1.5 oook/src/html.lisp

Source

oook.asd.

Parent Component

src (module).

Public Interface
Internals

4.1.6 oook/src/methods.lisp

Source

oook.asd.

Parent Component

src (module).

Public Interface
Internals

Previous: , Up: Lisp   [Contents][Index]

4.1.7 oook/src/macro.lisp

Source

oook.asd.

Parent Component

src (module).

Public Interface
Internals

5 Packages

Packages are listed by definition order.


Next: , Previous: , Up: Packages   [Contents][Index]

5.1 oook.methods

Source

package.lisp.

Use List

common-lisp.

Public Interface
Internals

Next: , Previous: , Up: Packages   [Contents][Index]

5.2 oook

Source

package.lisp.

Use List

common-lisp.


Next: , Previous: , Up: Packages   [Contents][Index]

5.3 oook.utils

Source

package.lisp.

Use List

common-lisp.

Public Interface
Internals

Next: , Previous: , Up: Packages   [Contents][Index]

5.4 oook.macro

Defines the ‘defmodel’ macro, and the associated functions

Source

package.lisp.

Nickname

macro

Use List

common-lisp.

Public Interface
Internals

Previous: , Up: Packages   [Contents][Index]

5.5 oook.serialise

A set of serialisation utilities, including to/from alists, to json (using jonathan)

Source

package.lisp.

Use List

common-lisp.

Public Interface
Internals

6 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

6.1 Public Interface


Next: , Previous: , Up: Public Interface   [Contents][Index]

6.1.1 Special variables

Special Variable: *default-slot-type*
Package

oook.macro.

Source

macro.lisp.

Special Variable: *serialisation-options*

Options that control how objects are serialised

Package

oook.serialise.

Source

serialise.lisp.


6.1.2 Macros

Macro: def-enhanced-printer (type &key slot)

Enhances ‘print-object’ for ‘type’, adding the ‘slot’ attribute to it

Package

oook.utils.

Source

utils.lisp.

Macro: defmodel (model-name (&key table timestamped has-one owns-one owns-many belongs-to) &body fields)

Define a class that models DB structure

Package

oook.macro.

Source

macro.lisp.

Macro: with-record-type ((class) &body body)
Package

oook.serialise.

Source

html.lisp.

Macro: with-serialisation-options ((&rest options) &body body)

Execute ‘body’ with json options set to ‘options’

Package

oook.serialise.

Source

serialise.lisp.


6.1.3 Ordinary functions

Function: destroy (inst)

Delete ‘inst’ and associated models

Package

oook.methods.

Source

methods.lisp.

Function: filter ()
Package

oook.methods.

Source

methods.lisp.

Function: find-by-id (type id)

Find a model with ‘id’

Package

oook.methods.

Source

methods.lisp.

Function: from-alist (class alist &key include-joins)

Create an instance of ‘class’, given ‘alist’ containing mapping of slots to values, in caveman2 parsed params format.

Package

oook.serialise.

Source

serialise.lisp.

Function: gen-html-table (records &key exclude-slots table-classes)

Print an HTML table listing the data in ‘records’

Package

oook.serialise.

Source

html.lisp.

Function: get-edit-form (record action &key exclude-slots)
Package

oook.serialise.

Source

html.lisp.

Function: parse-as-type (value type)

Try to parse ‘type’ from input ‘value’

Package

oook.utils.

Source

utils.lisp.

Function: pprint-model (inst &key stream slots include-joins)

Pretty print ‘inst’

Package

oook.serialise.

Source

serialise.lisp.

Function: save (inst)

Save ‘inst’ and associated models

Package

oook.methods.

Source

methods.lisp.

Function: search-like (model column &key like singlep fmt)

Search the DB for ‘model’ using LIKE to match column. If ‘singlep’ is t, only one result is returned

Package

oook.utils.

Source

utils.lisp.

Function: sql-field (symbol)

Make ‘symbol’ suitable for SQL name

Package

oook.utils.

Source

utils.lisp.

Function: to-alist (inst &key include-joins)

Return an a-list representation of ‘inst’

Package

oook.serialise.

Source

serialise.lisp.


6.1.4 Generic functions

Generic Function: created-at (inst)
Package

oook.macro.

Source

macro.lisp.

Generic Function: foreign-key (inst)
Package

oook.macro.

Source

macro.lisp.

Generic Function: id (inst)

Read the ‘id’ attribute

Package

oook.macro.

Source

macro.lisp.

Generic Function: join-fks (inst)

Return the foreign keys for models in has-one and belongs-to

Package

oook.macro.

Source

macro.lisp.

Generic Function: last-modified (inst)
Package

oook.macro.

Source

macro.lisp.

Generic Function: owns-many (inst)
Package

oook.macro.

Source

macro.lisp.

Generic Function: owns-one (inst)
Package

oook.macro.

Source

macro.lisp.

Generic Function: serialisable-fields (inst)

Return the slots in ‘inst’ that will be included when ‘to-alist’ is called

Package

oook.macro.

Source

macro.lisp.

Generic Function: serialisable-joins (inst)
Package

oook.macro.

Source

macro.lisp.


6.2 Internals


Next: , Previous: , Up: Internals   [Contents][Index]

6.2.1 Macros

Macro: do-each-owns-many ((inst right value) &body body)

For each model in the owns-many relation of ‘inst’, execute ‘body’ with the symbol ‘right’ bound to the model type, and the symbol ‘value’ bound to the current slot-value of the relation

Package

oook.methods.

Source

methods.lisp.

Macro: ensure-slot-type (inst slot type)

Create form to ensure that ‘slot’ in ‘inst’ is of type ‘type’

Package

oook.utils.

Source

utils.lisp.


Previous: , Up: Internals   [Contents][Index]

6.2.2 Ordinary functions

Function: all-same-type-p (records)

Check everything in ‘records’ is the same type

Package

oook.serialise.

Source

html.lisp.

Function: ensure-integer (thing)

Return ‘thing’ as an integer

Package

oook.utils.

Source

utils.lisp.

Function: field-for-normal-slot (class slot &optional value)
Package

oook.serialise.

Source

html.lisp.

Function: field-label-for (slot)
Package

oook.serialise.

Source

html.lisp.

Function: field-name-for (container-name slot)
Package

oook.serialise.

Source

html.lisp.

Function: get-slot-type (class slot)

Get the type of ‘slot’ in ‘class’

Package

oook.serialise.

Source

serialise.lisp.

Function: make-clsql-base-slot (slot)

Create a clsql base slot form from ‘slot’

Package

oook.macro.

Source

macro.lisp.

Function: make-clsql-join-slot (name &key model home foreign set)
Package

oook.macro.

Source

macro.lisp.

Function: make-clsql-key-slot (name)

Create a clsql foreign key slot form from ‘slot’

Package

oook.macro.

Source

macro.lisp.

Function: make-foreign-key (symbol)

Create a foreign key (append _id) for symbol

Package

oook.macro.

Source

macro.lisp.

Function: new-row-p (inst)

Return T if ‘inst’ does not have a row in the DB

Package

oook.methods.

Source

methods.lisp.

Function: slot-type-without-null (class slot)

If a slot type is something like (OR NULL BOOLEAN), return just BOOLEAN

Package

oook.serialise.

Source

html.lisp.

Function: sql-field-keyword (symbol)

Make ‘symbol’ suitable for a field name as a keyword

Package

oook.utils.

Source

utils.lisp.

Function: update-owns-many (inst right new)

Remove all olds that are no longer in new, and add the new!

Package

oook.methods.

Source

methods.lisp.

Function: update-timestamps (inst)

Update the ‘created-at’ and ‘last-modified’ timestamps in ‘inst’

Package

oook.methods.

Source

methods.lisp.


Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts


Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   A   C   D   E   F   G   I   J   L   M   N   O   P   S   T   U   W  
Index Entry  Section

A
all-same-type-p: Private ordinary functions

C
created-at: Public generic functions

D
def-enhanced-printer: Public macros
defmodel: Public macros
destroy: Public ordinary functions
do-each-owns-many: Private macros

E
ensure-integer: Private ordinary functions
ensure-slot-type: Private macros

F
field-for-normal-slot: Private ordinary functions
field-label-for: Private ordinary functions
field-name-for: Private ordinary functions
filter: Public ordinary functions
find-by-id: Public ordinary functions
foreign-key: Public generic functions
from-alist: Public ordinary functions
Function, all-same-type-p: Private ordinary functions
Function, destroy: Public ordinary functions
Function, ensure-integer: Private ordinary functions
Function, field-for-normal-slot: Private ordinary functions
Function, field-label-for: Private ordinary functions
Function, field-name-for: Private ordinary functions
Function, filter: Public ordinary functions
Function, find-by-id: Public ordinary functions
Function, from-alist: Public ordinary functions
Function, gen-html-table: Public ordinary functions
Function, get-edit-form: Public ordinary functions
Function, get-slot-type: Private ordinary functions
Function, make-clsql-base-slot: Private ordinary functions
Function, make-clsql-join-slot: Private ordinary functions
Function, make-clsql-key-slot: Private ordinary functions
Function, make-foreign-key: Private ordinary functions
Function, new-row-p: Private ordinary functions
Function, parse-as-type: Public ordinary functions
Function, pprint-model: Public ordinary functions
Function, save: Public ordinary functions
Function, search-like: Public ordinary functions
Function, slot-type-without-null: Private ordinary functions
Function, sql-field: Public ordinary functions
Function, sql-field-keyword: Private ordinary functions
Function, to-alist: Public ordinary functions
Function, update-owns-many: Private ordinary functions
Function, update-timestamps: Private ordinary functions

G
gen-html-table: Public ordinary functions
Generic Function, created-at: Public generic functions
Generic Function, foreign-key: Public generic functions
Generic Function, id: Public generic functions
Generic Function, join-fks: Public generic functions
Generic Function, last-modified: Public generic functions
Generic Function, owns-many: Public generic functions
Generic Function, owns-one: Public generic functions
Generic Function, serialisable-fields: Public generic functions
Generic Function, serialisable-joins: Public generic functions
get-edit-form: Public ordinary functions
get-slot-type: Private ordinary functions

I
id: Public generic functions

J
join-fks: Public generic functions

L
last-modified: Public generic functions

M
Macro, def-enhanced-printer: Public macros
Macro, defmodel: Public macros
Macro, do-each-owns-many: Private macros
Macro, ensure-slot-type: Private macros
Macro, with-record-type: Public macros
Macro, with-serialisation-options: Public macros
make-clsql-base-slot: Private ordinary functions
make-clsql-join-slot: Private ordinary functions
make-clsql-key-slot: Private ordinary functions
make-foreign-key: Private ordinary functions

N
new-row-p: Private ordinary functions

O
owns-many: Public generic functions
owns-one: Public generic functions

P
parse-as-type: Public ordinary functions
pprint-model: Public ordinary functions

S
save: Public ordinary functions
search-like: Public ordinary functions
serialisable-fields: Public generic functions
serialisable-joins: Public generic functions
slot-type-without-null: Private ordinary functions
sql-field: Public ordinary functions
sql-field-keyword: Private ordinary functions

T
to-alist: Public ordinary functions

U
update-owns-many: Private ordinary functions
update-timestamps: Private ordinary functions

W
with-record-type: Public macros
with-serialisation-options: Public macros

Jump to:   A   C   D   E   F   G   I   J   L   M   N   O   P   S   T   U   W