Class: JekyllSQlite::Generator
- Inherits:
-
Jekyll::Generator
- Object
- Jekyll::Generator
- JekyllSQlite::Generator
- Defined in:
- lib/jekyll-sqlite/generator.rb
Overview
Main generator class rubocop:disable Metrics/ClassLength
Instance Method Summary collapse
-
#_prepare_query(stmt, params) ⇒ Object
Prepare the query by binding the parameters Since we don’t know if the query needs them we ignore all errors about “no such bind parameter”.
-
#attach_nested_data(root, path_segments, db, query) ⇒ Object
Recursively attach query results to nested data structures Supports arbitrary levels of nesting (e.g., regions.territories.EmployeeIDs) Handles both arrays and hashes at each level.
- #build_collection_doc(collection, row, idx) ⇒ Object
- #close_all_databases ⇒ Object
- #column_string(row, key) ⇒ Object
-
#gen(root, config_holder) ⇒ Object
Generate the data from the configuration Takes as input the root where the data will be attached and a configuration holder, where the sqlite key can be found Root is either site.data or page.data and config_holder is either site.config or page itself.
-
#generate(site) ⇒ Object
Entrpoint to the generator, called by Jekyll.
-
#generate_collection_from_config(config) ⇒ Object
Build documents from query rows and append them to the named site collection.
- #generate_data_from_config(root, config) ⇒ Object
-
#get_bind_params(dict) ⇒ Object
pick bindable parameters from the root All primitive values are bound to the query Arrays and Hashes are ignored.
- #get_database(file) ⇒ Object
-
#synth_doc_path(collection, row, idx) ⇒ Object
Build a synthetic document path from optional ‘name` and `path` columns.
-
#valid_config?(config) ⇒ Boolean
Validate given configuration object.
Instance Method Details
#_prepare_query(stmt, params) ⇒ Object
Prepare the query by binding the parameters Since we don’t know if the query needs them we ignore all errors about “no such bind parameter”
53 54 55 56 57 58 59 60 61 |
# File 'lib/jekyll-sqlite/generator.rb', line 53 def _prepare_query(stmt, params) stmt.named_params.each do |key| val = params[key] unless [Integer, String, Float, SQLite3::Blob, nil].include? val.class Jekyll.logger.error "#{key} type is #{val.class} in query: #{stmt.get_sql}" end stmt.bind_param key, params[key] end end |
#attach_nested_data(root, path_segments, db, query) ⇒ Object
Recursively attach query results to nested data structures Supports arbitrary levels of nesting (e.g., regions.territories.EmployeeIDs) Handles both arrays and hashes at each level
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/jekyll-sqlite/generator.rb', line 27 def attach_nested_data(root, path_segments, db, query) return 0 if path_segments.empty? if path_segments.size == 1 key = path_segments.first db.prepare(query) do |stmt| _prepare_query(stmt, get_bind_params(root)) root[key] = stmt.execute.to_a end return root[key].size end first, *remaining = path_segments current_level = root[first] if current_level.is_a?(Array) current_level.sum { |item| attach_nested_data(item, remaining, db, query) } else attach_nested_data(current_level, remaining, db, query) end end |
#build_collection_doc(collection, row, idx) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/jekyll-sqlite/generator.rb', line 147 def build_collection_doc(collection, row, idx) doc = Jekyll::Document.new(synth_doc_path(collection, row, idx), site: @site, collection: collection) row.each do |k, v| next unless k.is_a?(String) v = Time.parse(v) if k == "date" && v.is_a?(String) doc.data[k] = v end # Jekyll's :title permalink placeholder reads data["slug"], not data["title"]. # Auto-populate slug from title so SQL-provided titles show up in URLs. doc.data["slug"] ||= doc.data["title"] doc.content = row.key?("content") ? row["content"].to_s : "" doc end |
#close_all_databases ⇒ Object
19 20 21 |
# File 'lib/jekyll-sqlite/generator.rb', line 19 def close_all_databases @db.each_value(&:close) end |
#column_string(row, key) ⇒ Object
163 164 165 166 |
# File 'lib/jekyll-sqlite/generator.rb', line 163 def column_string(row, key) v = row[key] v.is_a?(String) && !v.empty? ? v : nil end |
#gen(root, config_holder) ⇒ Object
Generate the data from the configuration Takes as input the root where the data will be attached and a configuration holder, where the sqlite key can be found Root is either site.data or page.data and config_holder is either site.config or page itself.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/jekyll-sqlite/generator.rb', line 102 def gen(root, config_holder) (config_holder["sqlite"] || []).each do |config| unless valid_config?(config) Jekyll.logger.error "Jekyll SQLite:", "Invalid Configuration. Skipping" next end if config["collection"] generate_collection_from_config(config) else generate_data_from_config(root, config) end end end |
#generate(site) ⇒ Object
Entrpoint to the generator, called by Jekyll
170 171 172 173 174 175 176 177 178 179 |
# File 'lib/jekyll-sqlite/generator.rb', line 170 def generate(site) @db = {} @site = site gen(site.data, site.config) site.pages.each do |page| gen(page.data, page) end ensure close_all_databases end |
#generate_collection_from_config(config) ⇒ Object
Build documents from query rows and append them to the named site collection.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/jekyll-sqlite/generator.rb', line 119 def generate_collection_from_config(config) name = config["collection"] collection = @site.collections[name] unless collection Jekyll.logger.error "Jekyll SQLite:", "Collection '#{name}' not declared in _config.yml" return end db = get_database(config["file"]) db.results_as_hash = config.fetch("results_as_hash", true) rows = db.execute(config["query"]) rows.each_with_index { |row, idx| collection.docs << build_collection_doc(collection, row, idx) } Jekyll.logger.info "Jekyll SQLite:", "Loaded collection #{name}. Count=#{rows.size}" end |
#generate_data_from_config(root, config) ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/jekyll-sqlite/generator.rb', line 84 def generate_data_from_config(root, config) key = config["data"] query = config["query"] file = config["file"] db = get_database(file) db.results_as_hash = config.fetch("results_as_hash", true) path_segments = key.split(".") count = attach_nested_data(root, path_segments, db, query) Jekyll.logger.info "Jekyll SQLite:", "Loaded #{key}. Count=#{count}" end |
#get_bind_params(dict) ⇒ Object
pick bindable parameters from the root All primitive values are bound to the query Arrays and Hashes are ignored
80 81 82 |
# File 'lib/jekyll-sqlite/generator.rb', line 80 def get_bind_params(dict) dict.select { |_key, value| !value.is_a?(Array) && !value.is_a?(Hash) } end |
#get_database(file) ⇒ Object
13 14 15 16 17 |
# File 'lib/jekyll-sqlite/generator.rb', line 13 def get_database(file) return @db[file] if @db.key?(file) @db[file] = SQLite3::Database.new file, readonly: true end |
#synth_doc_path(collection, row, idx) ⇒ Object
Build a synthetic document path from optional ‘name` and `path` columns. Falls back to a 1-based row id (idx+1) when `name` is missing, and to no subdirectory when `path` is missing. The `name` and `path` SQL columns are what feed Jekyll’s :name and :path permalink placeholders.
138 139 140 141 142 143 144 145 |
# File 'lib/jekyll-sqlite/generator.rb', line 138 def synth_doc_path(collection, row, idx) name = column_string(row, "name") || (idx + 1).to_s subdir = column_string(row, "path") parts = ["_#{collection.label}"] parts << subdir if subdir parts << "#{name}.md" File.join(@site.source, *parts) end |
#valid_config?(config) ⇒ Boolean
Validate given configuration object. A config is valid when it is a Hash with a query, a readable file, and either a data: or collection: target.
67 68 69 70 71 72 73 74 |
# File 'lib/jekyll-sqlite/generator.rb', line 67 def valid_config?(config) return false unless config.is_a? Hash return false unless config.key?("query") return false unless config["file"] && File.exist?(config["file"]) return false unless config.key?("data") || config.key?("collection") true end |