bomdb 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,26 @@
1
+ require 'json'
2
+
3
+ module BomDB
4
+ module Import
5
+ class Editions < Import::Base
6
+ tables :editions
7
+
8
+ # Expected data format is:
9
+ # [
10
+ # [edition_year:Integer, edition_name:String],
11
+ # ...
12
+ # ]
13
+ def import_json(data, **args)
14
+ data.each do |year, name|
15
+ @db[:editions].insert(
16
+ edition_year: year,
17
+ edition_name: name
18
+ )
19
+ end
20
+ Import::Result.new(success: true)
21
+ rescue Sequel::UniqueConstraintViolation => e
22
+ Import::Result.new(success: false, error: e)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,65 @@
1
+ require 'json'
2
+
3
+ module BomDB
4
+ module Import
5
+ class Refs < Import::Base
6
+ tables :refs
7
+
8
+ # Expected data format is:
9
+ # {
10
+ # (ref_name:String): [
11
+ # {
12
+ # "book":String,"chapter":Int,"verse":Int,
13
+ # "ref_book":String,"ref_chapter":Int,"ref_verse":Int,
14
+ # "is_parallel":Bool,"is_quotation":Bool
15
+ # }
16
+ # ...
17
+ # ]
18
+ # }
19
+ def import_json(data, **args)
20
+ data.each_pair do |ref_name, rows|
21
+ rows.each do |r|
22
+ verse = @db[:verses].
23
+ join(:books, :book_id => :book_id).
24
+ where(
25
+ book_name: r['book'],
26
+ verse_chapter: r['chapter'],
27
+ verse_number: r['verse'],
28
+ verse_heading: nil).
29
+ first
30
+ if verse.nil?
31
+ return Import::Result.new(
32
+ success: false,
33
+ error: "Unable to find verse #{r['book']} #{r['chapter']}:#{r['verse']}"
34
+ )
35
+ end
36
+
37
+ @db[:refs].insert(
38
+ verse_id: verse[:verse_id],
39
+ ref_name: ref_name,
40
+ ref_book: r['ref_book'],
41
+ ref_chapter: r['ref_chapter'],
42
+ ref_verse: r['ref_verse'],
43
+ ref_is_parallel: r['is_parallel'],
44
+ ref_is_quotation: r['is_quotation']
45
+ )
46
+ end
47
+ end
48
+ Import::Result.new(success: true)
49
+ rescue Sequel::UniqueConstraintViolation => e
50
+ Import::Result.new(success: false, error: e)
51
+ end
52
+
53
+ # def list
54
+ # @db[
55
+ # "SELECT book_name, verse_chapter, verse_number, ref_name, ref_book, ref_chapter, ref_verse " +
56
+ # "FROM `verses` v " +
57
+ # "JOIN `books` b ON b.book_id = v.book_id " +
58
+ # "JOIN `refs` r ON r.verse_id = v.verse_id " +
59
+ # "ORDER BY ref_book, ref_chapter, ref_verse"
60
+ # ].map(&:inspect).join("\n")
61
+ # end
62
+
63
+ end
64
+ end
65
+ end
@@ -1,62 +1,43 @@
1
+ require 'json'
2
+ require 'bomdb/models/verse'
3
+
1
4
  module BomDB
2
5
  module Import
3
6
  class Verses < Import::Base
4
- TABLES = [:books, :verses, :versions, :contents]
5
-
6
- def reset
7
- schema.reset(*(TABLES - [:books]))
8
- end
9
-
10
- def json(data)
11
- if schema.has_tables?(*TABLES)
12
- ensure_parsed_json(data).each_pair do |book_name, year_versions|
13
- year_versions.each do |year_version|
14
- year_version.each_pair do |year, d|
15
- m = d["meta"]
16
-
17
- book = @db[:books].where(:book_name => book_name).first
18
- if book.nil?
19
- return Import::Result.new(success: false, error: "Unable to find book '#{book_name}'")
20
- end
7
+ tables :books, :verses
21
8
 
22
- verse = @db[:verses].where(
23
- :book_id => book[:book_id],
24
- :verse_chapter => m["chapter"],
25
- :verse_number => m["verse"],
26
- :verse_heading => m["heading"] ? 0 : nil
27
- ).first
28
- verse_id = (verse && verse[:verse_id]) || @db[:verses].insert(
29
- book_id: book[:book_id],
30
- verse_chapter: m["chapter"],
31
- verse_number: m["verse"],
32
- verse_heading: m["heading"] ? 0 : nil
33
- )
34
-
35
- version = @db[:versions].where(:version_year => year).first
36
- version_id = (version && version[:version_id]) || @db[:versions].insert(
37
- version_name: year.to_s,
38
- version_year: year
39
- )
9
+ # Expected data format is:
10
+ # [
11
+ # {
12
+ # "book": String,
13
+ # "chapter": Int,
14
+ # "verses": Int
15
+ # },
16
+ # ...
17
+ # ]
18
+ def import_json(data, **args)
19
+ data.each do |r|
20
+ # Create a heading per chapter
21
+ Models::Verse.new(@db).find_or_create(
22
+ chapter: r['chapter'],
23
+ verse: nil,
24
+ book_name: r['book'],
25
+ heading: true
26
+ )
40
27
 
41
- @db[:contents].insert(
42
- version_id: version_id,
43
- verse_id: verse_id,
44
- content_body: d["content"]
45
- )
46
- end
47
- end
28
+ # Create as many verses as is called for per chapter
29
+ (1..r['verses']).each do |verse_number|
30
+ Models::Verse.new(@db).find_or_create(
31
+ chapter: r['chapter'],
32
+ verse: verse_number,
33
+ book_name: r['book']
34
+ )
48
35
  end
49
- Import::Result.new(success: true)
50
- else
51
- Import::Result.new(
52
- success: false,
53
- error: "Database tables #{TABLES.join(', ')} not ready. Try again with --reset."
54
- )
55
36
  end
37
+ Import::Result.new(success: true)
56
38
  rescue Sequel::UniqueConstraintViolation => e
57
39
  Import::Result.new(success: false, error: e)
58
40
  end
59
-
60
41
  end
61
42
  end
62
- end
43
+ end
@@ -0,0 +1,27 @@
1
+ module BomDB
2
+ module Models
3
+ class Edition
4
+ def initialize(db)
5
+ @db = db
6
+ end
7
+
8
+ # Find an edition and return a hash, or nil if not found
9
+ def find(edition_name_prefix)
10
+ @db[:editions].
11
+ where(Sequel.like(:edition_name, "#{edition_name_prefix}%")).
12
+ or(:edition_year => edition_name_prefix).
13
+ first
14
+ end
15
+
16
+ # Returns an edition_id, either found in the db, or created as necessary
17
+ def find_or_create(year, name)
18
+ found = @db[:editions].where(edition_year: year, edition_name: name).first
19
+ return found[:edition_id] if found
20
+ @db[:editions].insert(
21
+ edition_year: year,
22
+ edition_name: name
23
+ )
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,47 @@
1
+ module BomDB
2
+ module Models
3
+ class Verse
4
+ def initialize(db)
5
+ @db = db
6
+ end
7
+
8
+ # Find a verse and return a hash, or nil if not found
9
+ def find(chapter:, verse:, book_name: nil, book_id: nil, heading: false)
10
+ @db[:verses].where(
11
+ book_id: book_by_name_or_id(book_name, book_id),
12
+ verse_chapter: chapter,
13
+ verse_number: verse,
14
+ verse_heading: heading ? 0 : nil
15
+ ).first
16
+ end
17
+
18
+ # Create a verse and return its verse_id
19
+ def create(chapter:, verse:, book_name: nil, book_id: nil, heading: false)
20
+ @db[:verses].insert(
21
+ book_id: book_by_name_or_id(book_name, book_id),
22
+ verse_chapter: chapter,
23
+ verse_number: verse,
24
+ verse_heading: heading ? 0 : nil
25
+ )
26
+ end
27
+
28
+ # Returns a verse_id after finding or creating the verse
29
+ def find_or_create(**args)
30
+ verse = find(**args)
31
+ (verse && verse[:verse_id]) || create(**args)
32
+ end
33
+
34
+ protected
35
+
36
+ def book_by_name_or_id(book_name, book_id)
37
+ if book_id.nil? and book_name.nil?
38
+ raise ArgumentError, "book_name or book_id is required"
39
+ elsif book_id.nil?
40
+ @db[:books].where(book_name: book_name).first[:book_id]
41
+ else
42
+ book_id
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
data/lib/bomdb/query.rb CHANGED
@@ -1,40 +1,51 @@
1
+ require 'bomdb/models/edition'
2
+
1
3
  module BomDB
2
4
  class Query
3
- def initialize(edition:, exclude: nil)
5
+ def initialize(edition:, exclude: nil, headings: false)
4
6
  @edition = edition
5
7
  @exclude = exclude
8
+ @headings = headings
6
9
  end
7
10
 
8
- def query(headings: false)
11
+ def query
9
12
  db = BomDB.db
13
+ edition_model = Models::Edition.new(db)
14
+ edition = edition_model.find(@edition)
15
+ if edition.nil?
16
+ raise "Unable to find edition: #{@edition}"
17
+ end
10
18
  q = db[:verses].
11
19
  join(:books, :book_id => :book_id).
12
- join(:versions).
13
- join(:contents, :version_id => :version_id, :verse_id => :verses__verse_id).
20
+ join(:editions).
21
+ join(:contents, :edition_id => :edition_id, :verse_id => :verses__verse_id).
14
22
  order(:book_sort, :verse_heading, :verse_chapter, :verse_number).
15
23
  select(:book_name, :verse_chapter, :verse_number, :content_body)
16
- q.where!(:version_name => @edition) if @edition
17
- q.where!(:verse_heading => nil) unless headings
24
+ q.where!(:editions__edition_id => edition[:edition_id]) if @edition
25
+ q.where!(:verse_heading => nil) unless @headings
18
26
  q.exclude!(:verses__verse_id => db[:refs].select(:verse_id).where(:ref_name => @exclude)) if @exclude
19
- # require 'byebug'; byebug
20
- # p q
21
27
  q
22
28
  end
23
29
 
24
- def print(book: true, chapter: true, verse: true, sep: ' ')
30
+ def each(&block)
31
+ query.each(&block)
32
+ end
33
+
34
+ def print(verse_format: nil, body_format: nil, sep: ' ', linesep: "\n", io: $stdout)
25
35
  shown = false
36
+ verse_format ||= lambda{ |book, chapter, verse| "#{book}#{sep}#{chapter}:#{verse}" }
37
+ body_format ||= lambda{ |body| body + linesep }
26
38
  query.each do |row|
27
39
  shown = true
28
- puts [
29
- book && row[:book_name] || nil,
30
- (chapter || verse) && [
31
- chapter && row[:verse_chapter] || nil,
32
- verse && row[:verse_number] || nil
33
- ].compact.join(":") || nil,
34
- row[:content_body]
35
- ].compact.join(sep)
40
+ io.print verse_format[
41
+ row[:book_name],
42
+ row[:verse_chapter],
43
+ row[:verse_number]
44
+ ]
45
+ io.print sep
46
+ io.print body_format[ row[:content_body] ]
36
47
  end
37
- puts "Nothing found" unless shown
48
+ io.puts "Nothing found" unless shown
38
49
  end
39
50
  end
40
51
  end
data/lib/bomdb/schema.rb CHANGED
@@ -1,62 +1,61 @@
1
1
  require 'set'
2
+ require 'sequel'
3
+ require 'fileutils'
2
4
 
3
5
  module BomDB
4
6
  class Schema
7
+ attr_reader :db
8
+
5
9
  def initialize(db)
6
10
  @db = db
7
11
  end
8
12
 
9
- def has_tables?(*table_names)
10
- Set.new(@db.tables) >= Set.new(table_names)
11
- end
12
-
13
- def reset(*table_names)
14
- drop_tables(table_names)
15
- create_tables(table_names)
13
+ # create a new database
14
+ def self.create(db_path, tables = :all)
15
+ FileUtils.rm(db_path) if File.exist?(db_path)
16
+ new(Sequel.sqlite(db_path)).create_tables(tables)
16
17
  end
17
18
 
18
- def drop_tables(table_names = nil)
19
- (table_names || @db.tables).each do |name|
20
- @db.drop_table(name) if @db.tables.include?(name)
21
- end
19
+ def has_tables?(tables)
20
+ Set.new(@db.tables) >= Set.new(tables)
22
21
  end
23
22
 
24
- def create_tables(table_names = nil)
23
+ def create_tables(tables = :all)
25
24
  @db.create_table(:books) do
26
25
  primary_key :book_id
27
26
 
28
27
  string :book_name, :unique => true
29
28
  string :book_group
30
29
  integer :book_sort
31
- end if include?(table_names, :books)
30
+ end if include?(tables, :books)
32
31
 
33
32
  @db.create_table(:verses) do
34
33
  primary_key :verse_id
35
34
  foreign_key :book_id, :books
36
35
 
37
36
  integer :verse_chapter, :null => true
38
- integer :verse_number, :null => true
37
+ integer :verse_number, :null => true
39
38
  integer :verse_heading, :null => true
40
39
 
41
40
  index [:book_id, :verse_chapter, :verse_number, :verse_heading], :unique => true
42
- end if include?(table_names, :verses)
41
+ end if include?(tables, :verses)
43
42
 
44
- @db.create_table(:versions) do
45
- primary_key :version_id
43
+ @db.create_table(:editions) do
44
+ primary_key :edition_id
46
45
 
47
- string :version_name
48
- integer :version_year
49
- end if include?(table_names, :versions)
46
+ integer :edition_year
47
+ string :edition_name, :unique => true
48
+ end if include?(tables, :editions)
50
49
 
51
50
  @db.create_table(:contents) do
52
51
  primary_key :content_id
53
- foreign_key :version_id, :versions
52
+ foreign_key :edition_id, :editions
54
53
  foreign_key :verse_id, :verses
55
54
 
56
55
  string :content_body
57
56
 
58
- index [:version_id, :verse_id], :unique => true
59
- end if include?(table_names, :contents)
57
+ index [:edition_id, :verse_id], :unique => true
58
+ end if include?(tables, :contents)
60
59
 
61
60
  @db.create_table(:refs) do
62
61
  primary_key :ref_id
@@ -71,7 +70,7 @@ module BomDB
71
70
  integer :ref_page_end
72
71
  boolean :ref_is_parallel
73
72
  boolean :ref_is_quotation
74
- end if include?(table_names, :refs)
73
+ end if include?(tables, :refs)
75
74
 
76
75
  @db.create_table(:notes) do
77
76
  primary_key :note_id
@@ -79,14 +78,15 @@ module BomDB
79
78
 
80
79
  string :note_highlight
81
80
  string :note_body
82
- end if include?(table_names, :notes)
81
+ end if include?(tables, :notes)
82
+
83
+ self
83
84
  end
84
85
 
85
86
  protected
86
87
 
87
- def include?(table_names, name)
88
- table_names.nil? ||
89
- table_names.map{ |n| n.to_sym }.include?(name.to_sym)
88
+ def include?(tables, name)
89
+ tables == :all || tables.map{ |n| n.to_sym }.include?(name.to_sym)
90
90
  end
91
91
  end
92
92
  end