From 2c4c9fa410cb112d534847a25946017fb3058c64 Mon Sep 17 00:00:00 2001 From: Craig Oates Date: Sat, 18 Dec 2021 05:01:43 +0000 Subject: [PATCH] apply Chapter 5 changes (working with mito and templates). This is an extention of Chapter 4. In Chapter 4, the aim was to set-up a database and successfully connect to it. This chapter was more about querying the database and displaying the results in the '.html' templates. I do not know why, but I was having a lot of trouble with naming conflicts for hours. I could not work it out and in the end I do not what I changed which caused the code to start working. One of the tactics I used was replace ':' with '#:' in the 'defpackages' and '.asd' file. Like I said, I do not know if this change caused the code to start working. But, if you are wondering why the sudden change in the code base, that is why. --- app.lisp | 26 +++---- rails-to-caveman.asd | 26 +++---- src/config.lisp | 31 ++++---- src/db.lisp | 22 +++--- src/main.lisp | 18 ++--- src/model.lisp | 137 +---------------------------------- src/view.lisp | 55 +++++++------- src/web.lisp | 43 ++++++++--- static/css/main.css | 37 ++++++++++ templates/shared/header.html | 2 +- 10 files changed, 164 insertions(+), 233 deletions(-) diff --git a/app.lisp b/app.lisp index 5e507f6..01f294e 100644 --- a/app.lisp +++ b/app.lisp @@ -1,19 +1,19 @@ (ql:quickload :rails-to-caveman) (defpackage rails-to-caveman.app - (:use :cl) - (:import-from :lack.builder - :builder) - (:import-from :ppcre - :scan - :regex-replace) - (:import-from :rails-to-caveman.web - :*web*) - (:import-from :rails-to-caveman.config - :config - :productionp - :*static-directory*)) -(in-package :rails-to-caveman.app) + (:use #:cl) + (:import-from #:lack.builder + #:builder) + (:import-from #:ppcre + #:scan + #:regex-replace) + (:import-from #:rails-to-caveman.web + #:*web*) + (:import-from #:rails-to-caveman.config + #:config + #:productionp + #:*static-directory*)) +(in-package #:rails-to-caveman.app) ;;; ORIGINAL -- WITHOUT CLACK-ERRORS PACKAGE ADDED ;; (builder diff --git a/rails-to-caveman.asd b/rails-to-caveman.asd index 9662ba3..731d45f 100644 --- a/rails-to-caveman.asd +++ b/rails-to-caveman.asd @@ -1,25 +1,25 @@ -(defsystem "rails-to-caveman" +(defsystem #:rails-to-caveman :version "0.1.0" :author "Craig Oates" :license "MIT" - :depends-on ("clack" - "lack" - "clack-errors" ; <--- Added in Chapter 1. - "caveman2" - "envy" - "cl-ppcre" - "uiop" + :depends-on (#:clack + #:lack + #:clack-errors ; <--- Added in Chapter 1. + #:caveman2 + #:envy + #:cl-ppcre + #:uiop ;; for @route annotation - "cl-syntax-annot" + #:cl-syntax-annot ;; HTML Template - "djula" + #:djula ;; for DB - "datafly" - "sxql" - "mito" ; <--- Added in Chapter 4. + #:mito ; <--- Added in Chapter 4. + #:datafly + #:sxql ) :components ((:module "src" :components diff --git a/src/config.lisp b/src/config.lisp index 38a8ab1..e406ad5 100644 --- a/src/config.lisp +++ b/src/config.lisp @@ -1,17 +1,17 @@ -(in-package :cl-user) +(in-package #:cl-user) (defpackage rails-to-caveman.config - (:use :cl) - (:import-from :envy - :config-env-var - :defconfig) - (:export :config - :*application-root* - :*static-directory* - :*template-directory* - :appenv - :developmentp - :productionp)) -(in-package :rails-to-caveman.config) + (:use #:cl) + (:import-from #:envy + #:config-env-var + #:defconfig) + (:export #:config + #:*application-root* + #:*static-directory* + #:*template-directory* + #:appenv + #:developmentp + #:productionp)) +(in-package #:rails-to-caveman.config) (setf (config-env-var) "APP_ENV") @@ -34,7 +34,7 @@ #| EXCERPT TAKEN FROM TUTORIAL (CHAPTER 4): ============================================ Initially: I set the database-name to “your-app”, but later when I - tried to access the database, I got angry with CANTOPEN. So I + tried to access the database, I got angry with CAN'T OPEN. So I changed the name to “your_app” and it worked fine. Apparently, words separated by . Dashes Are Capitalized At The Beginning . The Name Specified In The Code Here Is "Your-App", But The Registered File @@ -51,7 +51,8 @@ also a "db "directory in the project directory, so I don't wonder if it will do it well. I think it's unfriendly to have no documentation. |# - `(:databases ((:maindb :sqlite3 :database-name "rails-to-caveman.db")))) + `(:databases ((:maindb :sqlite3 :database-name ,(merge-pathnames #P"db/rails_to_caveman.db" + *application-root*))))) (defconfig |development| '()) diff --git a/src/db.lisp b/src/db.lisp index 1023c75..12c4607 100644 --- a/src/db.lisp +++ b/src/db.lisp @@ -1,16 +1,16 @@ -(in-package :cl-user) +(in-package #:cl-user) (defpackage rails-to-caveman.db (:use :cl) - (:import-from :rails-to-caveman.config - :config) - (:import-from :datafly - :*connection*) - (:import-from :cl-dbi - :connect-cached) - (:export :connection-settings - :db - :with-connection)) -(in-package :rails-to-caveman.db) + (:import-from #:rails-to-caveman.config + #:config) + (:import-from #:datafly + #:*connection*) + (:import-from #:cl-dbi + #:connect-cached) + (:export #:connection-settings + #:db + #:with-connection)) +(in-package #:rails-to-caveman.db) (defun connection-settings (&optional (db :maindb)) (cdr (assoc db (config :databases)))) diff --git a/src/main.lisp b/src/main.lisp index 2555fda..b6dbe6d 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -1,13 +1,13 @@ -(in-package :cl-user) +(in-package #:cl-user) (defpackage rails-to-caveman - (:use :cl) - (:import-from :rails-to-caveman.config - :config) - (:import-from :clack - :clackup) - (:export :start - :stop)) -(in-package :rails-to-caveman) + (:use #:cl) + (:import-from #:rails-to-caveman.config + #:config) + (:import-from #:clack + #:clackup) + (:export #:start + #:stop)) +(in-package #:rails-to-caveman) (defvar *appfile-path* (asdf:system-relative-pathname :rails-to-caveman #P"app.lisp")) diff --git a/src/model.lisp b/src/model.lisp index 1ff2276..ae38f84 100644 --- a/src/model.lisp +++ b/src/model.lisp @@ -1,9 +1,8 @@ -;; (in-package :cl-user) ; Not sure if this needs to exist (Chapter 4) -(defpackage :rails-to-caveman.model +;;(in-package #:cl-user) ; Not sure if this needs to exist (Chapter 4) +(defpackage rails-to-caveman.model (:use #:cl - #:rails-to-caveman.db) - (:export #:seeds - #:ids)) + #:rails-to-caveman.db + #:mito)) (in-package #:rails-to-caveman.model) ;;; Defines the USER table class for the database. @@ -106,131 +105,3 @@ this tutorial was translated/ported from." (mapcar #'mito:object-id (mito:retrieve-dao 'rails-to-caveman.model::user)))) - -#| STAND ALONE BITS OF CODE -=========================== -The code below is to use in a live coding environment. Think of it as -a persistent scratch pad -- for when you close Emacs but still want -those little snippets of code which do not have a place in the main -code base but are useful for little tests/proof-of-concepts. - -When you have loaded the system in SLIME, use c-c c-c to run the code -below. -|# - -(with-connection (db) ; Creates a table in the database called 'user'. - (mito:ensure-table-exists 'user)) - -;; Retrieves the record with the specified Id. Change ':id' to -;; retrieve different entries from the database. -;; NOTE: EVAL. THIS IN SLIME BEFORE USING (DESCRIBE *) FURTHER DOWN -;; THE FILE. -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:find-dao 'rails-to-caveman.model::user :id 3)) - -;; Retrieves the database entry with the specified name. -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:find-dao 'rails-to-caveman.model::user :name "Taro")) - -#| SQLITE DATABASE BOOLEAN TYPES -================================ -Use multiple columns to specify with data you want to retrieve. -Because SQLite database does not have a Boolean type, - -:administrator : 0 = false -1 = true -:sex 1 = male -2 = female - -SQLite type quirk and how the tutorial decided to model the data in -the database. -|# -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:find-dao 'rails-to-caveman.model::user :sex 1 :administrator 1)) - -;; A common strategy to deal with SQLite Boolean types is to set -;; constants and refer to them instead of passing hard coded 1 & 0. -(defconstant +false+ 0) -(defconstant +true+ 1) - -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:retrieve-dao 'rails-to-caveman.model::user :administrator +false+)) - -(ids) ; Lists out all the Id's (in SLIME) in the 'users' table. - -(seeds) ; Populates the database with seeded data (in 'users') - -;; Drops the current table, creates a new one and populates it with -;; seeded data -- in the 'users' tables. -(rebuild) - -#| SEEING THE CONTENTS OF A DATABASE ENTRY IN SLIME. -==================================================== -This is a bit picky. First of all, you need to retrieve a database -entry (in SLIME) before checking the contents. Search for 'NOTE: -EVAL.' for the code. After you have retrieved the entry from the -database, calling (describe *) will produce something like the -following, - -[standard-object] Slots with -:INSTANCE allocation: -CREATED-AT = @yyyy-mm-ddThh:mm:ss.ms+tz -UPDATED-AT = @yyyy-mm-ddThh:mm:ss.ms+tz -SYNCED = T -ID = 3 -NUMBER = 12 -NAME = "Hana" -FULL-NAME = "高橋 花子" -EMAIL = "Hana@example.com" -BIRTHDAY = @yyyy-mm-ddThh:mm:ss.ms+tz -SEX = 2 -ADMINISTRATOR = NIL - -THIS IS SPECIFIC TO SBCL -- OTHER IMPLEMENTATIONS MIGHT PRODUCE -DIFFERENT OUTPUTS -|# -(describe *) - - -#| BUILD QUERIES WITH SXQL AND MITO -=================================== -If you want to build a complex query, use it in combination -MITO.DAO:SELECT-DAO with sxql . - -The one in the previous section MITO:RETRIEVE-DAOis equivalent to the -following code. - -COPY THE CODE BELOW INTO SLIME OR WORK THEM INTO A FUNCTION. -|# -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:select-dao 'rails-to-caveman.model::user - (sxql:where '(:= :administrator 0)))) - -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:select-dao 'rails-to-caveman.model::user - (sxql:where - '(:and (:= :name "Taro") - (:< :number 20))))) - -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:select-dao 'rails-to-caveman.model::user - (sxql:where '(:= :sex 2)) - (sxql:order-by :number))) - -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:select-dao 'rails-to-caveman.model::user - (sxql:where '(:= :sex 2)) - (sxql:order-by (:desc :number)))) - -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:select-dao 'rails-to-caveman.model::user - (sxql:where - `(:or ,@(mapcar (lambda(num) - `(:= :number ,num)) - '(15 17 19)))))) - -(rails-to-caveman.db:with-connection (rails-to-caveman.db:db) - (mito:select-dao 'rails-to-caveman.model::user - (sxql:where - `(:and (:<= 12 :number) - (:<= :number 14))))) diff --git a/src/view.lisp b/src/view.lisp index 1b91d5d..ddd8eeb 100644 --- a/src/view.lisp +++ b/src/view.lisp @@ -1,21 +1,21 @@ -(in-package :cl-user) +(in-package #:cl-user) (defpackage rails-to-caveman.view - (:use :cl) - (:import-from :rails-to-caveman.config - :*template-directory*) - (:import-from :caveman2 - :*response* - :response-headers) - (:import-from :djula - :add-template-directory - :compile-template* - :render-template* - :*djula-execute-package*) - (:import-from :datafly - :encode-json) - (:export :render - :render-json)) -(in-package :rails-to-caveman.view) + (:use #:cl) + (:import-from #:rails-to-caveman.config + #:*template-directory*) + (:import-from #:caveman2 + #:*response* + #:response-headers) + (:import-from #:djula + #:add-template-directory + #:compile-template* + #:render-template* + #:*djula-execute-package*) + (:import-from #:datafly + #:encode-json) + (:export #:render + #:render-json)) +(in-package #:rails-to-caveman.view) (djula:add-template-directory *template-directory*) @@ -32,27 +32,26 @@ (defun render-json (object) (setf (getf (response-headers *response*) :content-type) "application/json") - (encode-json object)) + (datafly:encode-json object)) ;; ;; Execute package definition (defpackage rails-to-caveman.djula - (:use :cl) - (:import-from :rails-to-caveman.config - :config - :appenv - :developmentp - :productionp) - (:import-from :caveman2 - :url-for) + (:use #:cl) + (:import-from #:rails-to-caveman.config + #:config + #:appenv + #:developmentp + #:productionp) + (:import-from #:caveman2 + #:url-for) (:export #:title!) ; Added in Chapter 3 (Mockup section). ) ;; in-package and let code added in Chapter 3, also. This is ;; preperation for Switching Layout Templates section. -(in-package - :rails-to-caveman.djula) ; Make sure this states your app name. +(in-package #:rails-to-caveman.djula) ; Make sure this states your app name. (let(title) (defun title! (&optional sub) (if sub diff --git a/src/web.lisp b/src/web.lisp index 30e2de7..b435482 100644 --- a/src/web.lisp +++ b/src/web.lisp @@ -1,14 +1,15 @@ -(in-package :cl-user) +(in-package #:cl-user) (defpackage rails-to-caveman.web - (:use :cl - :caveman2 - :rails-to-caveman.config - :rails-to-caveman.view - :rails-to-caveman.db - :datafly - :sxql) - (:export :*web*)) -(in-package :rails-to-caveman.web) + (:use #:cl + #:caveman2 + #:rails-to-caveman.config + #:rails-to-caveman.view + #:rails-to-caveman.db + #:rails-to-caveman.model + #:sxql + #:mito) + (:export #:*web*)) +(in-package #:rails-to-caveman.web) ;; for @route annotation (syntax:use-syntax :annot) @@ -34,6 +35,28 @@ '(:numbers (1 2 3 4 5)) )) +(defroute "/users/index"() + (render "users/index.html" + `(:users ,(with-connection (db) + (mito:select-dao 'rails-to-caveman.model::user + (sxql:order-by :number)))))) + +(defroute "/users/search" (&key |q|) + (render "users/index.html" + `(:users ,(with-connection (db) + (mito:select-dao 'rails-to-caveman.model::user + (sxql:where + `(:or (:like :name ,|q|) + (:like :full-name ,|q|))) + (sxql:order-by :number)))))) + +(defroute "/users/:id" (&key id) + (setf id (parse-integer id)) + (render "users/show.html" + `(:user ,(with-connection (db) + (mito:find-dao 'rails-to-caveman.model::user + :id id))))) + (defroute "/about" () ;; about.html should be in the /templates directory. (render #P"about.html" '(:page-title "About"))) diff --git a/static/css/main.css b/static/css/main.css index a0d04e0..a8c8a65 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -43,3 +43,40 @@ nav.menubar a:link { color: #ccc; } /* link of menubar (visited) */ nav.menubar a:visited { color: #ccc; } + +/* table */ +table.list, table.attr { + font-size: 90%; + width: 100%; +} + +table.list th, table.attr th { + background-color: #499; + color: white; + font-weight: normal; +} + +table.list td, table.list th, +table.attr td, table.attr th { + padding: 4px; +} + +table.list th { + text-align: left; +} + +table.attr th { + text-align: right; +} + +table.list td, table.attr td { + background-color: #cee; +} + +/* toolbar */ +ul.toolbar, +div.toolbar { + padding: 15px 0; + font-size: 90%; + text-align: right; +} diff --git a/templates/shared/header.html b/templates/shared/header.html index 7b58218..ae33bb2 100644 --- a/templates/shared/header.html +++ b/templates/shared/header.html @@ -5,7 +5,7 @@
  • Home
  • News
  • Blog
  • -
  • Members
  • +
  • Members
  • Settings