The code below (src/book.cr) defines 2 classes.
require "sqlite3"
module Book
alias BookFields = {id: Int64, title: String, author: String}
class Books
def initialize(@conn : DB::Connection)
end
def add(@author : String, @title : String)
@conn.exec("INSERT INTO book (title, author) values(?, ?)", @title, @author)
end
def fetch
books = [] of Book
@conn.query_all("SELECT id FROM book", as: Int64).each do |id|
books << Book.new(@conn, id)
end
books
end
end
class Book
@book : BookFields? = nil
{% for method in BookFields.keys %}
def {{method.id}}
book[:{{method.id}}]
end
{% end %}
def initialize(@conn : DB::Connection, @id : Int64)
end
def book : BookFields
@book ||= @conn.query_one "SELECT * FROM book WHERE id='#{@id}'", as: BookFields.types
end
def to_s(io : IO)
io << title << " (" << author << ")"
end
end
end
and some additional lines to test them.
cnn = DB.connect("sqlite3://%3Amemory%3A")
sql = %(CREATE TABLE IF NOT EXISTS "book" (
"id" integer,
"author" text NOT NULL UNIQUE COLLATE nocase,
"title" text COLLATE nocase,
PRIMARY KEY("id")
))
cnn.exec sql
books = Book::Books.new(cnn)
books.add("De bello gallico", "Caesar Julius")
books.add("De Brevitate Vitæ", "Seneca")
books.fetch.sort { |a, b| a.author <=> b.author }.each do |bk|
puts bk.to_s
end
cnn.close
Everything works as expected.
If I use these last lines in a test file (spec/book_spec.cr) by inserting them in a describe block, everything is still OK.
require "sqlite3"
require "./spec_helper"
require "../src/book"
cnn = DB.connect("sqlite3://%3Amemory%3A")
sql = %(CREATE TABLE IF NOT EXISTS "book" (
"id" integer,
"author" text NOT NULL UNIQUE COLLATE nocase,
"title" text COLLATE nocase,
PRIMARY KEY("id")
))
cnn.exec sql
describe Book do
books = Book::Books.new(cnn)
books.add("De bello gallico", "Caesar Julius")
books.add("De Brevitate Vitæ", "Seneca")
books.fetch.sort { |a, b| a.author <=> b.author }.each do |bk|
puts bk.to_s
end
end
cnn.close
However, if I enclose the books.fetch
block in an it
block, the compilation fails.
describe Book do
books = Book::Books.new(cnn)
books.add("De bello gallico", "Caesar Julius")
books.add("De Brevitate Vitæ", "Seneca")
it "does not compile" do
books.fetch.sort { |a, b| a.author <=> b.author }.each do |bk|
puts bk.to_s
end
end
end
$ crystal spec spec/
EFailures:
Book does not compile
bad parameter or other API misuse (SQLite3::Exception)
from lib/sqlite3/src/sqlite3/statement.cr:81:5 in ‘check’
from lib/sqlite3/src/sqlite3/statement.cr:4:5 in ‘initialize’
from lib/sqlite3/src/sqlite3/statement.cr:2:3 in ‘new’
from lib/sqlite3/src/sqlite3/connection.cr:18:5 in ‘build_prepared_statement’
from lib/db/src/db/connection.cr:40:40 in ‘fetch_or_build_prepared_statement’
from lib/db/src/db/session_methods.cr:23:9 in ‘build’
from lib/db/src/db/query_methods.cr:46:7 in ‘query:args’
from lib/db/src/db/query_methods.cr:61:7 in ‘query_all:as’
from src/book.cr:22:7 in ‘fetch’
from spec/book_spec.cr:18:5 in ‘->’
from /usr/lib/crystal/primitives.cr:266:3 in ‘internal_run’
from /usr/lib/crystal/spec/example.cr:33:16 in ‘run’
from /usr/lib/crystal/spec/context.cr:18:23 in ‘internal_run’
from /usr/lib/crystal/spec/context.cr:339:7 in ‘run’
from /usr/lib/crystal/spec/context.cr:18:23 in ‘internal_run’
from /usr/lib/crystal/spec/context.cr:156:7 in ‘run’
from /usr/lib/crystal/spec/dsl.cr:220:7 in ‘->’
from /usr/lib/crystal/primitives.cr:266:3 in ‘run’
from /usr/lib/crystal/crystal/main.cr:50:14 in ‘exit’
from /usr/lib/crystal/crystal/main.cr:45:5 in ‘main’
from /usr/lib/crystal/crystal/main.cr:127:3 in ‘main’
from /usr/lib/libc.so.6 in ‘__libc_start_main’
from /home/hubert/.cache/crystal/crystal-run-spec.tmp in ‘_start’
from ???Finished in 890 microseconds
1 examples, 0 failures, 1 errors, 0 pendingFailed examples:
crystal spec spec/book_spec.cr:17 # Book does not compile
Bug, or did I miss something about the use of Spec?