jekyll-sqlite 0.1.4 → 0.2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -3
- data/CHANGELOG.md +21 -0
- data/Gemfile +5 -8
- data/README.md +10 -127
- data/Rakefile +19 -3
- data/docs/.gitignore +5 -0
- data/docs/404.html +8 -0
- data/docs/CHANGELOG.md +1 -0
- data/docs/Gemfile +5 -0
- data/docs/_config.yml +44 -0
- data/docs/demo.md +29 -0
- data/docs/img/northwind-1.jpg +0 -0
- data/docs/img/northwind-2.jpg +0 -0
- data/docs/index.md +26 -0
- data/docs/install.md +23 -0
- data/docs/usage/datapage.md +73 -0
- data/docs/usage/dynamic.md +54 -0
- data/docs/usage/index.md +20 -0
- data/docs/usage/nested.md +44 -0
- data/docs/usage/per-page.md +41 -0
- data/docs/usage/writing-queries.md +32 -0
- data/jekyll-sqlite.gemspec +2 -3
- data/lib/jekyll-sqlite/generator.rb +44 -66
- data/lib/jekyll-sqlite/version.rb +1 -1
- metadata +22 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85c5327f559510f9baa0eef20116398123e50254da7d75924c8d08e8883c7505
|
4
|
+
data.tar.gz: 29329e963af9d41a2059fc91f2a56088f8a5e038ae890985028bec086c5a253d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f96eb487a5177930b82a19ef0ca5916f51bb4f6f89bfac8317d00dbb7be6ecf6700660765a13d5b5f34b4a6a3244658ced390d4b284ec0ccbf0d97cb6229af7d
|
7
|
+
data.tar.gz: e74fb0ee889375285a718879f72cfea1a2c69899846ea62fd44d325b0154c65b8d8070ead3c33f48d458fcffe985864e7ec2dc665ed1a5639e9c156075ff62c9
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
|
1
|
+
plugins: rubocop-rake
|
2
2
|
AllCops:
|
3
|
-
TargetRubyVersion: 3.
|
3
|
+
TargetRubyVersion: 3.2
|
4
4
|
NewCops: enable
|
5
5
|
Exclude:
|
6
6
|
- "node_modules/**/*"
|
@@ -8,6 +8,7 @@ AllCops:
|
|
8
8
|
- "vendor/**/*"
|
9
9
|
- ".git/**/*"
|
10
10
|
- "test/_plugins/jekyll_sqlite_generator.rb"
|
11
|
+
- "docs/**/*"
|
11
12
|
Style/StringLiterals:
|
12
13
|
Enabled: true
|
13
14
|
EnforcedStyle: double_quotes
|
@@ -20,4 +21,6 @@ Layout/LineLength:
|
|
20
21
|
Max: 120
|
21
22
|
|
22
23
|
Metrics/AbcSize:
|
23
|
-
Max:
|
24
|
+
Max: 20
|
25
|
+
Metrics/MethodLength:
|
26
|
+
Max: 100
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
|
+
---
|
2
|
+
title: Changelog
|
3
|
+
nav_order: "ZZZ"
|
4
|
+
---
|
5
|
+
|
6
|
+
All notable changes to this project will be documented in this file.
|
7
|
+
|
8
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
9
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
10
|
+
|
1
11
|
## [Unreleased]
|
2
12
|
|
13
|
+
## [0.2.0] - 2025-08-23
|
14
|
+
- Multiple-levels of nesting is now supported
|
15
|
+
- Slight performance improvement by keeping database open for entire plugin run
|
16
|
+
|
17
|
+
## [0.1.6] - 2025-07-31
|
18
|
+
- Drop Ruby 3.1
|
19
|
+
- sqlite3 requirement to `2.7.3`
|
20
|
+
|
21
|
+
## [0.1.5] - 2024-07-31
|
22
|
+
- sqlite3 requirement changed to `1.6`
|
23
|
+
|
3
24
|
## [0.1.4] - 2024-07-17
|
4
25
|
- Per-page queries are now supported via a `sqlite` config block in the front matter.
|
5
26
|
- Documents support for existing site data being used within queries.
|
data/Gemfile
CHANGED
@@ -6,12 +6,9 @@ source "https://rubygems.org"
|
|
6
6
|
gemspec
|
7
7
|
|
8
8
|
# These are development dependencies
|
9
|
-
gem "jekyll", "~> 4.
|
10
|
-
gem "rake", "~> 13.
|
11
|
-
gem "rubocop", "~> 1.
|
12
|
-
gem "rubocop-rake", "~> 0.
|
9
|
+
gem "jekyll", "~> 4.4", ">= 4.4.1"
|
10
|
+
gem "rake", "~> 13.3"
|
11
|
+
gem "rubocop", "~> 1.80"
|
12
|
+
gem "rubocop-rake", "~> 0.7"
|
13
13
|
|
14
|
-
|
15
|
-
gem "base64", "~> 0.2.0"
|
16
|
-
gem "bigdecimal", "~> 3.1"
|
17
|
-
gem "csv", "~> 3.3"
|
14
|
+
gem "logger", "~> 1.7"
|
data/README.md
CHANGED
@@ -5,140 +5,23 @@ A Jekyll generator plugin to lets you use SQLite database instead of data files
|
|
5
5
|
It supports site-level queries, per-page queries, and prepared queries that can
|
6
6
|
use existing data (possibly generated via more queries) as parameters.
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
```ruby
|
15
|
-
gem 'jekyll-sqlite'
|
16
|
-
```
|
17
|
-
|
18
|
-
And then add this line to your site's `_config.yml`:
|
19
|
-
|
20
|
-
```yml
|
21
|
-
plugins:
|
22
|
-
- jekyll_sqlite
|
23
|
-
```
|
24
|
-
|
25
|
-
:warning: If you are using Jekyll < 3.5.0 use the `gems` key instead of `plugins`.
|
26
|
-
|
27
|
-
## Usage
|
28
|
-
|
29
|
-
Update your `_config.yml` to define your data sources with your SQLite database. Please see
|
30
|
-
the `test` directory for a functional example with the [Northwind database](https://github.com/jpwhite3/northwind-SQLite3).
|
31
|
-
|
32
|
-
```yml
|
33
|
-
...
|
34
|
-
sqlite:
|
35
|
-
- data: customers
|
36
|
-
file: *db
|
37
|
-
query: SELECT * from Customers
|
38
|
-
```
|
39
|
-
|
40
|
-
Then, you can use the `site.data` attributes accordingly:
|
41
|
-
|
42
|
-
```liquid
|
43
|
-
{{ site.data.customers | jsonify }}
|
44
|
-
```
|
45
|
-
|
46
|
-
## Prepared Queries
|
47
|
-
|
48
|
-
This plugin supports prepared queries with parameter binding. This lets you
|
49
|
-
use existing data from a previous query, or some other source (such as
|
50
|
-
`site.data.*` or `page.*`) as a parameter in your query.
|
51
|
-
|
52
|
-
Say you have a YAML file defining your items (`data/books.yaml`):
|
53
|
-
|
54
|
-
```yaml
|
55
|
-
- id: 31323952-2708-42dc-a995-6006a23cbf00
|
56
|
-
name: Time Travel with a Rubber Band
|
57
|
-
- id: 5c8e67a0-d490-4743-b5b8-8e67bd1f95a2
|
58
|
-
name: The Art of Cache Invalidation
|
59
|
-
```
|
60
|
-
and the prices for the items in your SQLite database, the following configuration will enrich the `items` array with the price:
|
61
|
-
|
62
|
-
```yaml
|
63
|
-
sql:
|
64
|
-
- data: items.books
|
65
|
-
query: SELECT price, author FROM pricing WHERE id =:id
|
66
|
-
db: books.db
|
67
|
-
```
|
68
|
-
This would allow the following Liquid loop to be written:
|
8
|
+
The primary usecase is to **avoid Liquid Hell**, wherein you're left mangling
|
9
|
+
multiple data sources from CSV/JSON/YAML files using liquid templating by
|
10
|
+
saving temporary variables, creating maps, and so on. SQL is a decent language
|
11
|
+
for reshaping datasets - supporting joins, filters, and aggregations. So this
|
12
|
+
allows you to use SQL for reshaping your data, and then use liquid
|
13
|
+
for what it was meant for - presentation and templating.
|
69
14
|
|
70
|
-
|
71
|
-
{% for item in site.data.items %}
|
72
|
-
{{item.meta.price}}, {{item.meta.author}}
|
73
|
-
{% endfor %}
|
74
|
-
```
|
75
|
-
|
76
|
-
## Per Page Queries
|
77
|
-
|
78
|
-
The exact same syntax can be used on a per-page basis to generate data within
|
79
|
-
each page. This is helpful for keeping page-specific queries within the page
|
80
|
-
itself. Here's an example:
|
81
|
-
|
82
|
-
```yaml
|
83
|
-
---
|
84
|
-
FeaturedSupplierID: 2
|
85
|
-
sqlite:
|
86
|
-
- data: suppliers
|
87
|
-
file: "_db/northwind.db"
|
88
|
-
query: "SELECT CompanyName, SupplierID FROM suppliers ORDER BY SupplierID"
|
89
|
-
- data: suppliers.products
|
90
|
-
# This is a prepared query, where SupplierID is coming from the previous query.
|
91
|
-
file: "_db/northwind.db"
|
92
|
-
query: "SELECT ProductName, CategoryID,UnitPrice FROM products WHERE SupplierID = :SupplierID"
|
93
|
-
# :FeaturedSupplierID is picked up automatically from the page frontmatter.
|
94
|
-
- data: FeaturedSupplier
|
95
|
-
file: "_db/northwind.db"
|
96
|
-
query: "SELECT * SupplierID = :FeaturedSupplierID"
|
97
|
-
---
|
98
|
-
{{page.suppliers|jsonify}}
|
99
|
-
```
|
100
|
-
|
101
|
-
This will generate a `page.suppliers` array with all the suppliers, and a `page.FeaturedSupplier` object with the details of the featured supplier.
|
102
|
-
|
103
|
-
Each supplier will have a `products` array with all the products for that supplier.
|
104
|
-
|
105
|
-
## Generating Pages
|
106
|
-
|
107
|
-
It works well with the `datapage_gen` plugin:
|
108
|
-
|
109
|
-
See the [datapage_gen](https://github.com/avillafiorita/jekyll-datapage_gen) docs for more details.
|
110
|
-
|
111
|
-
Here's a sample configuration:
|
112
|
-
|
113
|
-
```yaml
|
114
|
-
sqlite:
|
115
|
-
restaurants:
|
116
|
-
file: _db/reviews.db
|
117
|
-
sql: SELECT id, name, last_review_date > 1672531200 as active, address FROM restaurants;
|
118
|
-
page_gen:
|
119
|
-
- data: restaurants
|
120
|
-
template: restaurant
|
121
|
-
name: id
|
122
|
-
title: name
|
123
|
-
filter: active
|
124
|
-
```
|
125
|
-
|
126
|
-
This will automatically generate a file for each restaurant
|
127
|
-
restaurants/#{id}.html file with the layout `_layouts/restaurant.html` and page.id, page.name, page.active set and page.title set to restaurant name
|
128
|
-
|
129
|
-
Note that the `datapage_gen` plugin will run _after_ the `jekyll-sqlite` plugin,
|
130
|
-
if you generate any pages with per-page queries, these queries will not execute.
|
131
|
-
|
132
|
-
## Development
|
133
|
-
|
134
|
-
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
15
|
+
[](https://github.com/captn3m0/jekyll-sqlite/actions/workflows/main.yml) [](https://badge.fury.io/rb/jekyll-sqlite)
|
135
16
|
|
136
|
-
|
17
|
+
Documentation is now maintained at <https://captnemo.in/jekyll-sqlite/>.
|
137
18
|
|
138
19
|
## Contributing
|
139
20
|
|
140
21
|
Bug reports and pull requests are welcome on GitHub at https://github.com/captn3m0/jekyll-sqlite. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/captn3m0/jekyll-sqlite/blob/main/CODE_OF_CONDUCT.md).
|
141
22
|
|
23
|
+
Note that only maintained versions of [Jekyll](https://endoflife.date/jekyll) and [Ruby](https://endoflife.date/ruby) are supported.
|
24
|
+
|
142
25
|
## Code of Conduct
|
143
26
|
|
144
27
|
Everyone interacting in the Jekyll::Sqlite project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/captn3m0/jekyll-sqlite/blob/main/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
@@ -19,7 +19,6 @@ def query_db(query)
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# rubocop:disable Metrics/AbcSize
|
22
|
-
# rubocop:disable Metrics/MethodLength
|
23
22
|
def validate_json
|
24
23
|
file = "_site/data.json"
|
25
24
|
data = JSON.parse(File.read(file))
|
@@ -54,9 +53,25 @@ def validate_page_json
|
|
54
53
|
fs = query_db("SELECT * FROM Suppliers WHERE SupplierID = 6")
|
55
54
|
assert read_data["focusSupplier"][0] == fs, "Focus Supplier doesn't match"
|
56
55
|
end
|
57
|
-
# rubocop:enable Metrics/AbcSize
|
58
|
-
# rubocop:enable Metrics/MethodLength
|
59
56
|
|
57
|
+
def validate_employees_json
|
58
|
+
file = "_site/employees.json"
|
59
|
+
regions = JSON.parse(File.read(file))
|
60
|
+
assert regions.size == 4
|
61
|
+
assert regions[0]["RegionID"] == 1, "First RegionID should be 1"
|
62
|
+
assert regions[0]["RegionDescription"] == "Eastern", "First Region is Eastern"
|
63
|
+
assert regions[-1]["RegionID"] == 4, "Four zotal Regions"
|
64
|
+
assert regions[0]["territories"].size == 19, "There should be 19 territories in Eastern"
|
65
|
+
assert regions[0]["territories"][0]["TerritoryID"] == "01730", "First TerritoryID should be 1"
|
66
|
+
assert regions[0]["territories"][0]["TerritoryDescription"] == "Bedford", "First TerritoryID should be Bedford"
|
67
|
+
bedford = regions[0]["territories"][0]
|
68
|
+
assert bedford == {
|
69
|
+
"TerritoryID" => "01730",
|
70
|
+
"TerritoryDescription" => "Bedford",
|
71
|
+
"EmployeeIDs" => [{ "EmployeeID" => 2, "FirstName" => "Andrew", "LastName" => "Fuller" }]
|
72
|
+
}, "Bedford should have Andrew Fuller"
|
73
|
+
end
|
74
|
+
# rubocop:enable Metrics/AbcSize
|
60
75
|
task default: :rubocop
|
61
76
|
|
62
77
|
desc "Build Test Site"
|
@@ -65,4 +80,5 @@ task :test do
|
|
65
80
|
Jekyll::Site.new(Jekyll.configuration).process
|
66
81
|
validate_json
|
67
82
|
validate_page_json
|
83
|
+
validate_employees_json
|
68
84
|
end
|
data/docs/.gitignore
ADDED
data/docs/404.html
ADDED
data/docs/CHANGELOG.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
../CHANGELOG.md
|
data/docs/Gemfile
ADDED
data/docs/_config.yml
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
theme: just-the-docs
|
2
|
+
title: Jekyll SQLite
|
3
|
+
description: >-
|
4
|
+
generator plugin to lets you use SQLite database instead of data files as a
|
5
|
+
data source. It lets you easily create APIs and websites from a SQLite
|
6
|
+
database, by linking together a database file, your template, and the relevant
|
7
|
+
queries.
|
8
|
+
baseurl: "/jekyll-sqlite"
|
9
|
+
url: "https://captnemo.in"
|
10
|
+
github_username: captn3m0
|
11
|
+
# https://just-the-docs.com/docs/configuration/
|
12
|
+
favicon_ico: https://jekyllrb.com/favicon.ico
|
13
|
+
aux_links:
|
14
|
+
GitHub:
|
15
|
+
- "https://github.com/captn3m0/jekyll-sqlite/"
|
16
|
+
RubyGems:
|
17
|
+
- "https://rubygems.org/gems/jekyll-sqlite"
|
18
|
+
gh_edit_link: true
|
19
|
+
gh_edit_link_text: "Edit this page on GitHub."
|
20
|
+
gh_edit_repository: "https://github.com/captn3m0/jekyll-sqlite" # the github URL for your repo
|
21
|
+
gh_edit_branch: "main"
|
22
|
+
gh_edit_source: docs
|
23
|
+
gh_edit_view_mode: "edit"
|
24
|
+
|
25
|
+
callouts:
|
26
|
+
demo:
|
27
|
+
color: green
|
28
|
+
opacity: 0.5
|
29
|
+
note:
|
30
|
+
color: yellow
|
31
|
+
opacity: 0.3
|
32
|
+
# https://jekyllrb.com/docs/configuration/front-matter-defaults/
|
33
|
+
defaults:
|
34
|
+
- scope:
|
35
|
+
path: ""
|
36
|
+
values:
|
37
|
+
layout: default
|
38
|
+
encoding: utf-8
|
39
|
+
markdown: kramdown
|
40
|
+
strict_front_matter: true
|
41
|
+
# Silence Saas deprecation warnings, to be removed after this is fixed in just-the-docs
|
42
|
+
sass:
|
43
|
+
quiet_deps: true # https://github.com/just-the-docs/just-the-docs/issues/1541
|
44
|
+
silence_deprecations: ['import']
|
data/docs/demo.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
---
|
2
|
+
title: Demo
|
3
|
+
permalink: /demo.html
|
4
|
+
---
|
5
|
+
|
6
|
+
🏁 A fully-functional demo website that uses this plugin is available at
|
7
|
+
[northwind.captnemo.in](https://northwind.captnemo.in). The source code for
|
8
|
+
the demo is available at [captn3m0/northwind](https://github.com/captn3m0/northwind).
|
9
|
+
You can find more details at the demo page.
|
10
|
+
|
11
|
+
Here is a screenshot:
|
12
|
+
|
13
|
+

|
14
|
+
|
15
|
+
It relies on all features of the plugin, along with using `jekyll-datapage_gen`
|
16
|
+
plugin to generate individual pages for each data item.
|
17
|
+
|
18
|
+
1. A [per-page query](usage/#per-page-queries) is used on the restock page to generate list of
|
19
|
+
products that need to be restocked. [source](https://github.com/captn3m0/northwind/blob/main/restock.md?plain=1)
|
20
|
+
2. Customers, Orders, Products, Categories are set as global data items
|
21
|
+
in [config.yml](https://github.com/captn3m0/northwind/blob/main/_config.yml)
|
22
|
+
3. `site.data.categories[*].products` is filled using a parameterised query
|
23
|
+
in [`config.yml`](https://github.com/captn3m0/northwind/blob/main/_config.yml#L47-L49)
|
24
|
+
4. Featured Product and Employee of the Month, shown on homepage are set by a query
|
25
|
+
in `config.yml`, but the query parameters are set in [`_data`](https://github.com/captn3m0/northwind/tree/main/_data)
|
26
|
+
directory as YML files.
|
27
|
+
5. The datapage plugin config generates a page for every product and customer.
|
28
|
+
|
29
|
+
The database is a trimmed-version of the northwind database from https://github.com/jpwhite3/northwind-SQLite3.
|
Binary file
|
Binary file
|
data/docs/index.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
---
|
2
|
+
title: Home
|
3
|
+
nav_order: 0
|
4
|
+
---
|
5
|
+
|
6
|
+
A Jekyll generator plugin to lets you use SQLite databases instead of [Data Files][df] as a
|
7
|
+
data source. It lets you easily create APIs and websites from a SQLite
|
8
|
+
database, by linking together a database file, your template, and the relevant
|
9
|
+
queries.
|
10
|
+
|
11
|
+
Jekyll's Data Files are great, but they are limited to YAML/JSON/TSV/CSV file
|
12
|
+
formats - this plugin gives you another option: SQLite databases.
|
13
|
+
|
14
|
+
It supports site-level queries, per-page queries, and prepared queries that can
|
15
|
+
use existing data (possibly generated via more queries) as parameters.
|
16
|
+
|
17
|
+
The primary usecase is to **avoid Liquid Hell**, wherein you're left mangling
|
18
|
+
multiple data sources from CSV/JSON/YAML files using liquid templating by
|
19
|
+
saving temporary variables, creating maps, and so on. SQL is a decent language
|
20
|
+
for reshaping datasets - supporting joins, filters, and aggregations. So this
|
21
|
+
allows you to use SQL for reshaping your data, and then use liquid
|
22
|
+
for what it was meant for - presentation and templating.
|
23
|
+
|
24
|
+
[](https://github.com/captn3m0/jekyll-sqlite/actions/workflows/main.yml) [](https://badge.fury.io/rb/jekyll-sqlite)
|
25
|
+
|
26
|
+
[df]: https://jekyllrb.com/docs/datafiles/ "Data Files at Jekyll Docs site"
|
data/docs/install.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
title: Installation
|
3
|
+
---
|
4
|
+
|
5
|
+
Add this line to your site's `Gemfile`:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'jekyll-sqlite'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then add this line to your site's `_config.yml`:
|
12
|
+
|
13
|
+
```yml
|
14
|
+
plugins:
|
15
|
+
- jekyll_sqlite
|
16
|
+
```
|
17
|
+
|
18
|
+
See [Usage](/jekyll-sqlite/usage/) for next steps.
|
19
|
+
|
20
|
+
---
|
21
|
+
|
22
|
+
Note that only supported versions of [Ruby](https://endoflife.date/ruby)
|
23
|
+
and [Jekyll](https://endoflife.date/ruby) are supported.
|
@@ -0,0 +1,73 @@
|
|
1
|
+
---
|
2
|
+
title: Using with Datapage Plugin
|
3
|
+
parent: Usage
|
4
|
+
nav_order: 2
|
5
|
+
---
|
6
|
+
|
7
|
+
The Jekyll [Datapage Generator](https://github.com/avillafiorita/jekyll-datapage_gen)
|
8
|
+
plugin allows you to specify data files for which we want to
|
9
|
+
generate one page per record.
|
10
|
+
|
11
|
+
You can use it alongside this plugin to generate data from a SQLite database,
|
12
|
+
and generate a page per row of your resultset.
|
13
|
+
|
14
|
+
This is how a simple configuration would look:
|
15
|
+
|
16
|
+
```yaml
|
17
|
+
# for the sqlite plugin
|
18
|
+
sqlite:
|
19
|
+
- data: restaurants
|
20
|
+
file: _db/reviews.db
|
21
|
+
query: SELECT id, name, last_review_date > 1672531200 as active, address FROM restaurants;
|
22
|
+
|
23
|
+
# for the datapage_gen plugin
|
24
|
+
page_gen:
|
25
|
+
- data: restaurants
|
26
|
+
# The layout used for each generated page _layouts/restaurant.html
|
27
|
+
template: restaurant
|
28
|
+
page_data_prefix: restaurants
|
29
|
+
name: id
|
30
|
+
title: name
|
31
|
+
filter: active
|
32
|
+
```
|
33
|
+
|
34
|
+
This will automatically generate a file for each restaurant `restaurants/#
|
35
|
+
{id}.html` file with the layout `_layouts/restaurant.html` and page.id,
|
36
|
+
page.name, page.active set and page.title set to restaurant name. Query data is
|
37
|
+
accessed in the page template via `{%raw%}{{ page.restaurants.address }}{%endraw%}` - the
|
38
|
+
namespace set in `page_data_prefix`.
|
39
|
+
|
40
|
+
Note that the `datapage_gen` plugin will run _after_ the `jekyll-sqlite` plugin, if you generate any pages with per-page queries, these queries will not execute.
|
41
|
+
|
42
|
+
## Demo Example
|
43
|
+
|
44
|
+
The following example comes from the [Demo](../demo/).
|
45
|
+
|
46
|
+
The following datapage configuration in `_config.yml`:
|
47
|
+
|
48
|
+
```yml
|
49
|
+
page_gen:
|
50
|
+
- data: products
|
51
|
+
template: product # _layouts/product.html
|
52
|
+
page_data_prefix: product
|
53
|
+
title: ProductName
|
54
|
+
name: ProductID
|
55
|
+
extension: html
|
56
|
+
```
|
57
|
+
|
58
|
+
will generate a page for each product in the `site.data.products` array.
|
59
|
+
|
60
|
+
In order to get data into the array, we can use:
|
61
|
+
|
62
|
+
```yml
|
63
|
+
sqlite:
|
64
|
+
- data: products
|
65
|
+
file: _db/northwind.db
|
66
|
+
query: SELECT * from Products
|
67
|
+
```
|
68
|
+
|
69
|
+
Here's a screenshot of how it looks:
|
70
|
+
|
71
|
+

|
72
|
+
|
73
|
+
See it in action at <https://northwind.captnemo.in/products/1.html>
|
@@ -0,0 +1,54 @@
|
|
1
|
+
---
|
2
|
+
title: Dynamic DB File
|
3
|
+
parent: Usage
|
4
|
+
nav_order: 3
|
5
|
+
---
|
6
|
+
|
7
|
+
If you want to select the database filename via an environment variable,
|
8
|
+
you can use the following options as a workaround:
|
9
|
+
|
10
|
+
## Using `envsubst` from GNU gettext
|
11
|
+
|
12
|
+
You can install it via [brew](https://formulae.brew.sh/formula/gettext)
|
13
|
+
or [on linux](https://repology.org/project/gettext/versions).
|
14
|
+
|
15
|
+
First, define your database filename,
|
16
|
+
and create a new configuration template file.
|
17
|
+
|
18
|
+
```sh
|
19
|
+
export JEKYLL_DB=events-blr.db
|
20
|
+
cp _config.yml _config.txt
|
21
|
+
```
|
22
|
+
|
23
|
+
Then, use the database name in your new ocnfig file
|
24
|
+
|
25
|
+
```yaml
|
26
|
+
sqlite:
|
27
|
+
data: events
|
28
|
+
file: $JEKYLL_DB
|
29
|
+
query: SELECT * FROM events
|
30
|
+
```
|
31
|
+
|
32
|
+
Then, use `envsubst` to generate the `_config.yml`
|
33
|
+
|
34
|
+
```bash
|
35
|
+
envsubst < "_config.txt" > "_config.yml"
|
36
|
+
```
|
37
|
+
|
38
|
+
## Using multiple configuration files
|
39
|
+
|
40
|
+
You can define your `sqlite` parameter multiple times
|
41
|
+
across multiple files, using different database filenames
|
42
|
+
|
43
|
+
For eg, `_config-blr.yml` could only include:
|
44
|
+
|
45
|
+
```
|
46
|
+
sqlite:
|
47
|
+
data: events
|
48
|
+
file: events-blr.db
|
49
|
+
query: SELECT * FROM events
|
50
|
+
```
|
51
|
+
|
52
|
+
And you can run jekyll using `jekyll --config _config.yml,_config-blr.yml`
|
53
|
+
|
54
|
+
However, this requires duplicating your query across multiple files.
|
data/docs/usage/index.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
title: Usage
|
3
|
+
has_toc: false
|
4
|
+
permalink: /usage/
|
5
|
+
---
|
6
|
+
Update your `_config.yml` to define your data sources with your SQLite database.
|
7
|
+
|
8
|
+
```yml
|
9
|
+
...
|
10
|
+
sqlite:
|
11
|
+
- data: customers
|
12
|
+
file: *db
|
13
|
+
query: SELECT * from Customers
|
14
|
+
```
|
15
|
+
|
16
|
+
Then, you can use the `site.data` attributes accordingly:
|
17
|
+
|
18
|
+
```liquid{%raw%}
|
19
|
+
{{ site.data.customers | jsonify }}{%endraw%}
|
20
|
+
```
|
@@ -0,0 +1,44 @@
|
|
1
|
+
---
|
2
|
+
title: Nested Queries
|
3
|
+
parent: Usage
|
4
|
+
nav_order: 4
|
5
|
+
---
|
6
|
+
Starting from `0.2.0`, queries can be nested infinitely.
|
7
|
+
|
8
|
+
The following configuration is used in the [demo](../demo/):
|
9
|
+
|
10
|
+
```yaml
|
11
|
+
sqlite:
|
12
|
+
- data: regions
|
13
|
+
file: *db
|
14
|
+
query: |
|
15
|
+
SELECT RegionID, RegionDescription FROM Regions
|
16
|
+
ORDER BY RegionID
|
17
|
+
|
18
|
+
- data: regions.territories
|
19
|
+
file: *db
|
20
|
+
query: |
|
21
|
+
SELECT TerritoryID, TerritoryDescription FROM Territories
|
22
|
+
WHERE RegionID = :RegionID
|
23
|
+
ORDER BY TerritoryDescription
|
24
|
+
|
25
|
+
- data: regions.territories.EmployeeIDs
|
26
|
+
file: *db
|
27
|
+
query: |
|
28
|
+
SELECT T.EmployeeID as EmployeeID, FirstName,LastName
|
29
|
+
FROM EmployeeTerritories T,Employees
|
30
|
+
WHERE T.TerritoryID = :TerritoryID
|
31
|
+
AND T.EmployeeID = Employees.EmployeeID
|
32
|
+
```
|
33
|
+
|
34
|
+
The first query generates `site.data.regions` as a list. The second query
|
35
|
+
sets territories inside each of the regions, and the third query
|
36
|
+
sets the list of employees inside each territory.
|
37
|
+
|
38
|
+
{: .note }
|
39
|
+
> Per Page Query
|
40
|
+
>
|
41
|
+
> On the Demo website, you can see the result at
|
42
|
+
> [the regions page](https://northwind.captnemo.in/regions.html)
|
43
|
+
> where each region is broken into territories, with the name
|
44
|
+
> of the employee under each region.
|
@@ -0,0 +1,41 @@
|
|
1
|
+
---
|
2
|
+
title: Per-page Queries
|
3
|
+
nav_order: 0
|
4
|
+
parent: Usage
|
5
|
+
---
|
6
|
+
|
7
|
+
The exact same syntax can be used on a per-page basis to generate data within
|
8
|
+
each page. This is helpful for keeping page-specific queries within the page
|
9
|
+
itself. Here's an example:
|
10
|
+
|
11
|
+
```yaml
|
12
|
+
---
|
13
|
+
FeaturedSupplierID: 2
|
14
|
+
sqlite:
|
15
|
+
- data: suppliers
|
16
|
+
file: "_db/northwind.db"
|
17
|
+
query: "SELECT CompanyName, SupplierID FROM suppliers ORDER BY SupplierID"
|
18
|
+
- data: suppliers.products
|
19
|
+
# This is a prepared query, where SupplierID is coming from the previous query.
|
20
|
+
file: "_db/northwind.db"
|
21
|
+
query: "SELECT ProductName, CategoryID,UnitPrice FROM products WHERE SupplierID = :SupplierID"
|
22
|
+
# :FeaturedSupplierID is picked up automatically from the page frontmatter.
|
23
|
+
- data: FeaturedSupplier
|
24
|
+
file: "_db/northwind.db"
|
25
|
+
query: "SELECT * SupplierID = :FeaturedSupplierID"
|
26
|
+
---
|
27
|
+
{%raw%}{{page.suppliers|jsonify}}{%endraw%}
|
28
|
+
```
|
29
|
+
|
30
|
+
This will generate a `page.suppliers` array with all the suppliers, and a `page.FeaturedSupplier` object with the details of the featured supplier.
|
31
|
+
|
32
|
+
Each supplier will have a `products` array with all the products for that supplier.
|
33
|
+
|
34
|
+
{: .note }
|
35
|
+
> Per Page Query
|
36
|
+
>
|
37
|
+
> On the Demo website, a per-page query
|
38
|
+
> is used on the restock page to generate
|
39
|
+
> list of products that need to be restocked. You can see the
|
40
|
+
> [source](https://github.com/captn3m0/northwind/blob/main/restock.md?plain=1)
|
41
|
+
> and the [resulting page](https://northwind.captnemo.in/restock.html)
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
title: Parametrized Queries
|
3
|
+
parent: Usage
|
4
|
+
nav_order: 1
|
5
|
+
---
|
6
|
+
This plugin supports prepared queries with parameter binding. This lets you
|
7
|
+
use existing data from a previous query, or some other source (such as
|
8
|
+
`site.data.*` or `page.*`) as a parameter in your query.
|
9
|
+
|
10
|
+
Say you have a YAML file defining your items (`data/books.yaml`):
|
11
|
+
|
12
|
+
```yaml
|
13
|
+
- id: 31323952-2708-42dc-a995-6006a23cbf00
|
14
|
+
name: Time Travel with a Rubber Band
|
15
|
+
- id: 5c8e67a0-d490-4743-b5b8-8e67bd1f95a2
|
16
|
+
name: The Art of Cache Invalidation
|
17
|
+
```
|
18
|
+
and the prices for the items in your SQLite database, the following configuration will enrich the `items` array with the price:
|
19
|
+
|
20
|
+
```yaml
|
21
|
+
sql:
|
22
|
+
- data: items.books
|
23
|
+
file: books.db
|
24
|
+
query: SELECT price, author FROM pricing WHERE id =:id
|
25
|
+
```
|
26
|
+
This would allow the following Liquid loop to be written:
|
27
|
+
|
28
|
+
```liquid{%raw%}
|
29
|
+
{% for item in site.data.items %}
|
30
|
+
{{item.meta.price}}, {{item.meta.author}}
|
31
|
+
{% endfor %}{%endraw%}
|
32
|
+
```
|
data/jekyll-sqlite.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = "A Jekyll plugin to use SQLite databases as a data source."
|
13
13
|
spec.homepage = "https://github.com/captn3m0/jekyll-sqlite"
|
14
|
-
spec.required_ruby_version = ">= 3.
|
14
|
+
spec.required_ruby_version = ">= 3.2.0"
|
15
15
|
|
16
16
|
spec.metadata["homepage_uri"] = spec.homepage
|
17
17
|
spec.metadata["source_code_uri"] = spec.homepage
|
@@ -27,7 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.bindir = "exe"
|
28
28
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
29
|
spec.require_paths = ["lib"]
|
30
|
-
|
31
|
-
spec.add_dependency "sqlite3", "~> 1.6"
|
30
|
+
spec.add_dependency "sqlite3", "~> 2.7.3"
|
32
31
|
spec.metadata["rubygems_mfa_required"] = "true"
|
33
32
|
end
|
@@ -8,22 +8,40 @@ module JekyllSQlite
|
|
8
8
|
# Set to high to be higher than the Jekyll Datapages Plugin
|
9
9
|
priority :high
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
def get_database(file)
|
12
|
+
return @db[file] if @db.key?(file)
|
13
|
+
|
14
|
+
@db[file] = SQLite3::Database.new file, readonly: true
|
15
|
+
end
|
16
|
+
|
17
|
+
def close_all_databases
|
18
|
+
@db.each_value(&:close)
|
16
19
|
end
|
17
20
|
|
18
21
|
##
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
# Recursively attach query results to nested data structures
|
23
|
+
# Supports arbitrary levels of nesting (e.g., regions.territories.EmployeeIDs)
|
24
|
+
# Handles both arrays and hashes at each level
|
25
|
+
def attach_nested_data(root, path_segments, db, query)
|
26
|
+
return 0 if path_segments.empty?
|
27
|
+
|
28
|
+
if path_segments.size == 1
|
29
|
+
key = path_segments.first
|
30
|
+
db.prepare(query) do |stmt|
|
31
|
+
_prepare_query(stmt, get_bind_params(root))
|
32
|
+
root[key] = stmt.execute.to_a
|
33
|
+
end
|
34
|
+
return root[key].size
|
35
|
+
end
|
36
|
+
|
37
|
+
first, *remaining = path_segments
|
38
|
+
current_level = root[first]
|
39
|
+
|
40
|
+
if current_level.is_a?(Array)
|
41
|
+
current_level.sum { |item| attach_nested_data(item, remaining, db, query) }
|
42
|
+
else
|
43
|
+
attach_nested_data(current_level, remaining, db, query)
|
25
44
|
end
|
26
|
-
root
|
27
45
|
end
|
28
46
|
|
29
47
|
##
|
@@ -38,38 +56,9 @@ module JekyllSQlite
|
|
38
56
|
end
|
39
57
|
end
|
40
58
|
|
41
|
-
##
|
42
|
-
# Internal function to generate data given
|
43
|
-
# root: a Hash-Like root object (site.data, site.data.*, page.data)
|
44
|
-
# key: string as the key to use to attach the data to the root
|
45
|
-
# db: SQLite3 Database object to execute the query on
|
46
|
-
# query: string containing the query to execute
|
47
|
-
# Sets root[db_name] = ResultSet of the query, as an array
|
48
|
-
# Returns the count of the result set
|
49
|
-
def _gen_data(root, key, db, query)
|
50
|
-
db.prepare(query) do |stmt|
|
51
|
-
_prepare_query stmt, get_bind_params(root)
|
52
|
-
root[key] = stmt.execute.to_a
|
53
|
-
end
|
54
|
-
root[key].count
|
55
|
-
end
|
56
|
-
|
57
|
-
##
|
58
|
-
# Calls _gen_data for the given root
|
59
|
-
# iterates through the array if root is an array
|
60
|
-
def gen_data(root, ...)
|
61
|
-
if root.is_a? Array
|
62
|
-
# call gen_data for each item in the array
|
63
|
-
# and return the sum of all the counts
|
64
|
-
root.map { |item| gen_data(item, ...) }.sum
|
65
|
-
else
|
66
|
-
_gen_data(root, ...)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
59
|
##
|
71
60
|
# Validate given configuration object
|
72
|
-
def
|
61
|
+
def valid_config?(config)
|
73
62
|
return false unless config.is_a? Hash
|
74
63
|
return false unless config.key?("query")
|
75
64
|
return false unless File.exist?(config["file"])
|
@@ -86,31 +75,16 @@ module JekyllSQlite
|
|
86
75
|
dict.select { |_key, value| !value.is_a?(Array) && !value.is_a?(Hash) }
|
87
76
|
end
|
88
77
|
|
89
|
-
##
|
90
|
-
# Given a configuration, generate the data
|
91
|
-
# and attach it to the given data_root
|
92
78
|
def generate_data_from_config(root, config)
|
93
79
|
key = config["data"]
|
94
80
|
query = config["query"]
|
95
81
|
file = config["file"]
|
96
|
-
SQLite3::Database.new file, readonly: true do |db|
|
97
|
-
db.results_as_hash = config.fetch("results_as_hash", true)
|
98
82
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
##
|
108
|
-
# Iterate through all the pages in the site
|
109
|
-
# and generate the data from the configuration
|
110
|
-
def gen_pages(site)
|
111
|
-
site.pages.each do |page|
|
112
|
-
gen(page.data, page)
|
113
|
-
end
|
83
|
+
db = get_database(file)
|
84
|
+
db.results_as_hash = config.fetch("results_as_hash", true)
|
85
|
+
path_segments = key.split(".")
|
86
|
+
count = attach_nested_data(root, path_segments, db, query)
|
87
|
+
Jekyll.logger.info "Jekyll SQLite:", "Loaded #{key}. Count=#{count}"
|
114
88
|
end
|
115
89
|
|
116
90
|
##
|
@@ -120,9 +94,8 @@ module JekyllSQlite
|
|
120
94
|
# Root is either site.data or page.data
|
121
95
|
# and config_holder is either site.config or page itself.
|
122
96
|
def gen(root, config_holder)
|
123
|
-
|
124
|
-
|
125
|
-
unless validate_config(config)
|
97
|
+
(config_holder["sqlite"] || []).each do |config|
|
98
|
+
unless valid_config?(config)
|
126
99
|
Jekyll.logger.error "Jekyll SQLite:", "Invalid Configuration. Skipping"
|
127
100
|
next
|
128
101
|
end
|
@@ -133,8 +106,13 @@ module JekyllSQlite
|
|
133
106
|
##
|
134
107
|
# Entrpoint to the generator, called by Jekyll
|
135
108
|
def generate(site)
|
109
|
+
@db = {}
|
136
110
|
gen(site.data, site.config)
|
137
|
-
|
111
|
+
site.pages.each do |page|
|
112
|
+
gen(page.data, page)
|
113
|
+
end
|
114
|
+
ensure
|
115
|
+
close_all_databases
|
138
116
|
end
|
139
117
|
end
|
140
118
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-sqlite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nemo
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: sqlite3
|
@@ -16,15 +15,14 @@ dependencies:
|
|
16
15
|
requirements:
|
17
16
|
- - "~>"
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
18
|
+
version: 2.7.3
|
20
19
|
type: :runtime
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
23
|
- - "~>"
|
25
24
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
-
description:
|
25
|
+
version: 2.7.3
|
28
26
|
email:
|
29
27
|
- jekyll-sqlite@captnemo.in
|
30
28
|
executables: []
|
@@ -37,6 +35,22 @@ files:
|
|
37
35
|
- Gemfile
|
38
36
|
- README.md
|
39
37
|
- Rakefile
|
38
|
+
- docs/.gitignore
|
39
|
+
- docs/404.html
|
40
|
+
- docs/CHANGELOG.md
|
41
|
+
- docs/Gemfile
|
42
|
+
- docs/_config.yml
|
43
|
+
- docs/demo.md
|
44
|
+
- docs/img/northwind-1.jpg
|
45
|
+
- docs/img/northwind-2.jpg
|
46
|
+
- docs/index.md
|
47
|
+
- docs/install.md
|
48
|
+
- docs/usage/datapage.md
|
49
|
+
- docs/usage/dynamic.md
|
50
|
+
- docs/usage/index.md
|
51
|
+
- docs/usage/nested.md
|
52
|
+
- docs/usage/per-page.md
|
53
|
+
- docs/usage/writing-queries.md
|
40
54
|
- jekyll-sqlite.gemspec
|
41
55
|
- lib/jekyll-sqlite/generator.rb
|
42
56
|
- lib/jekyll-sqlite/version.rb
|
@@ -49,7 +63,6 @@ metadata:
|
|
49
63
|
source_code_uri: https://github.com/captn3m0/jekyll-sqlite
|
50
64
|
changelog_uri: https://github.com/captn3m0/jekyll-sqlite/blob/master/CHANGELOG.md
|
51
65
|
rubygems_mfa_required: 'true'
|
52
|
-
post_install_message:
|
53
66
|
rdoc_options: []
|
54
67
|
require_paths:
|
55
68
|
- lib
|
@@ -57,15 +70,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
70
|
requirements:
|
58
71
|
- - ">="
|
59
72
|
- !ruby/object:Gem::Version
|
60
|
-
version: 3.
|
73
|
+
version: 3.2.0
|
61
74
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
75
|
requirements:
|
63
76
|
- - ">="
|
64
77
|
- !ruby/object:Gem::Version
|
65
78
|
version: '0'
|
66
79
|
requirements: []
|
67
|
-
rubygems_version: 3.
|
68
|
-
signing_key:
|
80
|
+
rubygems_version: 3.6.9
|
69
81
|
specification_version: 4
|
70
82
|
summary: A Jekyll plugin to use SQLite databases as a data source.
|
71
83
|
test_files: []
|