syntropy 0.35.0 → 0.36.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/TODO.md +0 -2
  4. data/cmd/new/template/Gemfile +1 -1
  5. data/cmd/new/template/app/_lib/storage.rb +13 -0
  6. data/examples/blog/app/_lib/posts.rb +3 -3
  7. data/examples/blog/app/_lib/storage.rb +13 -0
  8. data/lib/syntropy/module_loader.rb +1 -1
  9. data/lib/syntropy/{db → storage}/connection_pool.rb +2 -1
  10. data/lib/syntropy/storage/kv_store.rb +68 -0
  11. data/lib/syntropy/storage/prepared_query.rb +36 -0
  12. data/lib/syntropy/{db → storage}/schema.rb +1 -1
  13. data/lib/syntropy/{db → storage}/store.rb +1 -1
  14. data/lib/syntropy/storage.rb +6 -0
  15. data/lib/syntropy/test.rb +3 -1
  16. data/lib/syntropy/version.rb +1 -1
  17. data/lib/syntropy.rb +2 -4
  18. data/test/{test_db_connection_pool.rb → test_connection_pool.rb} +4 -4
  19. data/test/test_kv_store.rb +84 -0
  20. data/test/{test_db_schema.rb → test_schema.rb} +5 -5
  21. data/test/{test_db_store.rb → test_store.rb} +3 -3
  22. metadata +13 -32
  23. data/cmd/new/template/app/_lib/database.rb +0 -13
  24. data/cmd/new/template_old/site/.gitignore +0 -57
  25. data/cmd/new/template_old/site/Dockerfile +0 -32
  26. data/cmd/new/template_old/site/Gemfile +0 -3
  27. data/cmd/new/template_old/site/README.md +0 -0
  28. data/cmd/new/template_old/site/bin/console +0 -0
  29. data/cmd/new/template_old/site/bin/restart +0 -0
  30. data/cmd/new/template_old/site/bin/server +0 -0
  31. data/cmd/new/template_old/site/bin/start +0 -0
  32. data/cmd/new/template_old/site/bin/stop +0 -0
  33. data/cmd/new/template_old/site/docker-compose.yml +0 -51
  34. data/cmd/new/template_old/site/proxy/Dockerfile +0 -5
  35. data/cmd/new/template_old/site/proxy/etc/Caddyfile +0 -7
  36. data/cmd/new/template_old/site/proxy/etc/tls_auto +0 -2
  37. data/cmd/new/template_old/site/proxy/etc/tls_cloudflare +0 -4
  38. data/cmd/new/template_old/site/proxy/etc/tls_custom +0 -1
  39. data/cmd/new/template_old/site/proxy/etc/tls_selfsigned +0 -1
  40. data/cmd/new/template_old/site/site/_layout/default.rb +0 -11
  41. data/cmd/new/template_old/site/site/about.md +0 -6
  42. data/cmd/new/template_old/site/site/articles/cage.rb +0 -29
  43. data/cmd/new/template_old/site/site/articles/index.rb +0 -3
  44. data/cmd/new/template_old/site/site/assets/css/style.css +0 -40
  45. data/cmd/new/template_old/site/site/assets/img/syntropy.png +0 -0
  46. data/cmd/new/template_old/site/site/index.rb +0 -15
  47. data/examples/blog/app/_lib/database.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90b51e20e3a93a2b92bca677eddfe21efdd929d7378499f012dfb4c733336ddd
4
- data.tar.gz: 3f873ae675918b8601f8144daca4041b7f90c490dcdda1d32143ad9c1ab13d75
3
+ metadata.gz: f92ed1375642f12fb92654d872bfde1d07c7ad74be97507af3c1616390b6ce14
4
+ data.tar.gz: 5072d514bc07149f1d26bc900bcc9379970ebbbaf1b88eaa23933189fb684b37
5
5
  SHA512:
6
- metadata.gz: 40a3b22e7d24ab92be72b5552702ec5e6ca878ea8731537d552323e3dca5252b0ce965add0270a6bda710e8d20d32478060adee740f7acc33e386255daf44882
7
- data.tar.gz: 4129035e2daca7068eda05ced8b78604b10fbc39fd67aae20da3de5eb53b880b395c47d70795ec39e282cca50e65e2b3a878853ff8fd2e47e95bd2cb7cf80711
6
+ metadata.gz: f77aed02801a7b1c10f67a5ed7fbac9196580bd482c19ca660c81beaf5f2adcba86047635e35f9750d003538b12401962888193c058fbc3023ae88eae9038506
7
+ data.tar.gz: f923ab3aa4e535d5a85a563acf7f97534639ca1ed3d02e2c2b94d9cecef57e06cefc3a72a1ca782d0118b012189298bc3c743b017c0ee2d06be8bbf55d03dc89
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.36.0 2026-06-04
2
+
3
+ - Rename `DB` to `Storage`
4
+ - Add `PreparedQuery`, `KVStore`
5
+
1
6
  # 0.35.0 2026-06-04
2
7
 
3
8
  - Add `syntropy new` command
data/TODO.md CHANGED
@@ -40,8 +40,6 @@
40
40
  - [v] Frontend part of JSON API
41
41
  - [v] Auto-refresh page when file changes
42
42
  - [ ] SQLite database capabilities
43
- - [ ] Model API + tools
44
- - [ ] Do we need/want migrations?
45
43
  - [ ] Stores
46
44
  - [ ] KV store (with TTL)
47
45
  - [v] Examples
@@ -1,3 +1,3 @@
1
1
  source 'https://gem.coop'
2
2
 
3
- gem 'syntropy', '~>0.34.4'
3
+ gem 'syntropy', '~>0.36.0'
@@ -0,0 +1,13 @@
1
+ export self
2
+
3
+ def connection_pool
4
+ @connection_pool ||= Storage::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
5
+ end
6
+
7
+ def schema
8
+ Storage::Schema.new(module_loader: @module_loader, schema_root: '_schema')
9
+ end
10
+
11
+ def migrate!
12
+ schema.apply(connection_pool)
13
+ end
@@ -1,6 +1,6 @@
1
- DB = import '/_lib/database'
1
+ Storage = import '/_lib/storage'
2
2
 
3
- class PostStore < Syntropy::DB::Store
3
+ class PostStore < Syntropy::Storage::Store
4
4
  # @return [Integer] post id
5
5
  def create(title, body)
6
6
  query_single_value <<~SQL, title:, body:
@@ -46,4 +46,4 @@ class PostStore < Syntropy::DB::Store
46
46
  end
47
47
  end
48
48
 
49
- export PostStore.new(DB.connection_pool)
49
+ export PostStore.new(Storage.connection_pool)
@@ -0,0 +1,13 @@
1
+ export self
2
+
3
+ def connection_pool
4
+ @connection_pool ||= Storage::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
5
+ end
6
+
7
+ def schema
8
+ Storage::Schema.new(module_loader: @module_loader, schema_root: '_schema')
9
+ end
10
+
11
+ def migrate!
12
+ schema.apply(connection_pool)
13
+ end
@@ -200,7 +200,7 @@ module Syntropy
200
200
  m
201
201
  rescue SyntaxError => e
202
202
  env[:logger]&.error(message: "Error while loading module at #{fn}", error: e)
203
- STDERR.puts("\n#{e.message}")
203
+ STDERR.puts("\n#{e.message}") if !Syntropy.test_mode
204
204
 
205
205
  if (m = e.message.match(/^(.+)\: syntax/))
206
206
  location = m[1]
@@ -3,7 +3,8 @@
3
3
  require 'extralite'
4
4
 
5
5
  module Syntropy
6
- module DB
6
+ module Storage
7
+ # ConnectionPool implements concurrent access to an SQLite database.
7
8
  class ConnectionPool
8
9
  attr_reader :count
9
10
 
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'syntropy/storage/store'
4
+
5
+ module Syntropy
6
+ module Storage
7
+ # The KVStore class implements an SQLite-backed key-value store
8
+ class KVStore < Store
9
+ attr_reader :q_get, :q_set
10
+
11
+ def self.apply_schema(db, table_name)
12
+ db.execute <<~SQL
13
+ create table if not exists #{table_name} (key text primary key, value, expires float);
14
+ create index if not exists idx_#{table_name}_expires on #{table_name} (expires) where expires is not null;
15
+ SQL
16
+ end
17
+
18
+ def initialize(connection_pool, table_name)
19
+ super(connection_pool)
20
+ @table_name = table_name
21
+
22
+ setup_queries
23
+ end
24
+
25
+ def get(db, key)
26
+ db[@q_get].bind(key).next
27
+ end
28
+
29
+ def set(db, key, value)
30
+ db[@q_set].execute(key, value)
31
+ end
32
+
33
+ def setex(db, key, value, ttl)
34
+ db[@q_setex].execute(key, value, ttl ? Time.now.to_f + ttl : nil)
35
+ end
36
+
37
+ def sweep(db)
38
+ db[@q_sweep].execute(Time.now.to_f)
39
+ end
40
+
41
+ private
42
+
43
+ def setup_queries
44
+ @q_get = Storage.prepare_splat <<~SQL
45
+ select value from #{@table_name}
46
+ where key = ?
47
+ SQL
48
+
49
+ @q_set = Storage.prepare <<~SQL
50
+ insert into #{@table_name} (key, value)
51
+ values($1, $2)
52
+ on conflict (key) do update set value = $2, expires = null
53
+ SQL
54
+
55
+ @q_setex = Storage.prepare <<~SQL
56
+ insert into #{@table_name} (key, value, expires)
57
+ values($1, $2, $3)
58
+ on conflict (key) do update set value = $2, expires = $3
59
+ SQL
60
+
61
+ @q_sweep = Storage.prepare <<~SQL
62
+ delete from #{@table_name}
63
+ where expires < ?
64
+ SQL
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'extralite'
4
+
5
+ module Syntropy
6
+ module Storage
7
+ class << self
8
+ def prepare(sql)
9
+ PreparedQuery.new(sql)
10
+ end
11
+
12
+ def prepare_splat(sql)
13
+ PreparedQuery.new(sql, :prepare_splat)
14
+ end
15
+ end
16
+
17
+ # Represents information about a prepared query
18
+ class PreparedQuery
19
+ attr_reader :sql, :mode
20
+
21
+ def initialize(sql, mode = :prepare)
22
+ @sql = sql
23
+ @mode = mode
24
+ end
25
+ end
26
+
27
+ # Extensions for Extralite::Database
28
+ module ExtraliteDatabaseExtensions
29
+ def [](pq)
30
+ (@prepared_queries ||= {})[pq] ||= send(pq.mode, pq.sql)
31
+ end
32
+ end
33
+
34
+ ::Extralite::Database.include(ExtraliteDatabaseExtensions)
35
+ end
36
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Syntropy
4
- module DB
4
+ module Storage
5
5
  class Schema
6
6
  def initialize(module_loader: nil, schema_root: '_schema', &)
7
7
  @migrations = {}
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Syntropy
4
- module DB
4
+ module Storage
5
5
  # The Store class represents a data store based on one or more tables, and
6
6
  # connected to a database connection pool.
7
7
  class Store
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'syntropy/storage/connection_pool'
4
+ require 'syntropy/storage/schema'
5
+ require 'syntropy/storage/store'
6
+ require 'syntropy/storage/prepared_query'
data/lib/syntropy/test.rb CHANGED
@@ -118,7 +118,7 @@ module Syntropy
118
118
  )
119
119
  @test_harness = Syntropy::TestHarness.new(@app)
120
120
 
121
- @db = load_module('/_lib/database', raise_on_missing: false)
121
+ @db = load_module('/_lib/storage', raise_on_missing: false)
122
122
  @db&.migrate!
123
123
  end
124
124
 
@@ -241,3 +241,5 @@ module Syntropy
241
241
 
242
242
  Request.include TestRequestExtensions
243
243
  end
244
+
245
+ Syntropy.test_mode = true
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Syntropy
4
- VERSION = '0.35.0'
4
+ VERSION = '0.36.0'
5
5
  end
data/lib/syntropy.rb CHANGED
@@ -9,9 +9,7 @@ require 'syntropy/logger'
9
9
  require 'syntropy/http'
10
10
  require 'syntropy/mime_types'
11
11
  require 'syntropy/app'
12
- require 'syntropy/db/connection_pool'
13
- require 'syntropy/db/schema'
14
- require 'syntropy/db/store'
12
+ require 'syntropy/storage'
15
13
  require 'syntropy/errors'
16
14
  require 'syntropy/markdown'
17
15
  require 'syntropy/module_loader'
@@ -29,7 +27,7 @@ module Syntropy
29
27
  extend Utilities
30
28
 
31
29
  class << self
32
- attr_accessor :machine, :dev_mode
30
+ attr_accessor :machine, :dev_mode, :test_mode
33
31
 
34
32
  # Runs the given block on a separate thread. Use this method for running
35
33
  # code that is not fiber-aware (i.e. does not use UringMachine).
@@ -2,11 +2,11 @@
2
2
 
3
3
  require_relative 'helper'
4
4
 
5
- class DBConnectionPoolTest < Minitest::Test
5
+ class ConnectionPoolTest < Minitest::Test
6
6
  def setup
7
7
  @machine = UM.new
8
8
  @fn = "/tmp/#{rand(100000)}.db"
9
- @cp = Syntropy::DB::ConnectionPool.new(@machine, @fn, 4)
9
+ @cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
10
10
 
11
11
  FileUtils.rm(@fn) rescue nil
12
12
  @standalone_db = Extralite::Database.new(@fn)
@@ -19,7 +19,7 @@ class DBConnectionPoolTest < Minitest::Test
19
19
  @cp.close
20
20
  end
21
21
 
22
- def test_with_db
22
+ def test_connection_pool_with_db
23
23
  assert_equal 0, @cp.count
24
24
 
25
25
  @cp.with_db do |db|
@@ -74,7 +74,7 @@ class DBConnectionPoolTest < Minitest::Test
74
74
  assert_equal 4, @cp.count
75
75
  end
76
76
 
77
- def test_with_db_reentrant
77
+ def test_connection_pool_with_db_reentrant
78
78
  dbs = @cp.with_db do |db1|
79
79
  @cp.with_db do |db2|
80
80
  [db1, db2]
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require 'syntropy/storage/kv_store'
5
+
6
+ class KVStoreTest < Minitest::Test
7
+ def setup
8
+ @machine = UM.new
9
+ @fn = "/tmp/#{rand(100000)}.db"
10
+ FileUtils.rm(@fn) rescue nil
11
+ @cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
12
+ end
13
+
14
+ def teardown
15
+ @cp.close
16
+ end
17
+
18
+ def test_connection_pool_prepare
19
+ pq = Syntropy::Storage.prepare('select ? as a, 42 as b')
20
+ assert_kind_of Syntropy::Storage::PreparedQuery, pq
21
+ assert_equal 'select ? as a, 42 as b', pq.sql
22
+ assert_equal :prepare, pq.mode
23
+
24
+ assert_kind_of Extralite::Query, @cp.with_db { it[pq] }
25
+ assert_equal [{ a: 'foo', b: 42 }], @cp.with_db { it[pq].bind('foo').to_a }
26
+ end
27
+
28
+ def test_connection_pool_prepare_splat
29
+ pq = Syntropy::Storage.prepare_splat('select ?')
30
+ assert_kind_of Syntropy::Storage::PreparedQuery, pq
31
+ assert_equal 'select ?', pq.sql
32
+ assert_equal :prepare_splat, pq.mode
33
+
34
+ assert_kind_of Extralite::Query, @cp.with_db { it[pq] }
35
+ assert_equal ['foo'], @cp.with_db { it[pq].bind('foo').to_a }
36
+ end
37
+
38
+ def test_kv_store_apply_schema
39
+ assert_respond_to Syntropy::Storage::KVStore, :apply_schema
40
+
41
+ assert_raises(Extralite::SQLError) { @cp.query('select * from kv') }
42
+ Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
43
+ assert_equal [], @cp.query('select * from kv')
44
+ end
45
+
46
+ def test_kv_store_get_set
47
+ Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
48
+ kv_store = Syntropy::Storage::KVStore.new(@cp, 'kv')
49
+
50
+ @cp.with_db do |db|
51
+ assert_nil kv_store.get(db, 'foo')
52
+ assert_nil kv_store.get(db, 'bar')
53
+
54
+ kv_store.set(db, 'foo', '123')
55
+
56
+ assert_equal '123', kv_store.get(db, 'foo')
57
+ assert_nil kv_store.get(db, 'bar')
58
+
59
+ kv_store.set(db, 'bar', '456')
60
+ assert_equal '123', kv_store.get(db, 'foo')
61
+ assert_equal '456', kv_store.get(db, 'bar')
62
+ end
63
+ end
64
+
65
+ def test_kv_store_setex_sweep
66
+ Syntropy::Storage::KVStore.apply_schema(@cp, 'kv')
67
+ kv_store = Syntropy::Storage::KVStore.new(@cp, 'kv')
68
+
69
+ @cp.with_db do |db|
70
+ kv_store.set(db, 'foo', '123')
71
+ kv_store.setex(db, 'bar', '456', 0.05)
72
+ assert_equal 0, kv_store.sweep(db)
73
+
74
+ assert_equal '123', kv_store.get(db, 'foo')
75
+ assert_equal '456', kv_store.get(db, 'bar')
76
+
77
+ sleep 0.1
78
+ assert_equal 1, kv_store.sweep(db)
79
+
80
+ assert_equal '123', kv_store.get(db, 'foo')
81
+ assert_nil kv_store.get(db, 'bar')
82
+ end
83
+ end
84
+ end
@@ -2,12 +2,12 @@
2
2
 
3
3
  require_relative 'helper'
4
4
 
5
- class DBSchemaTest < Minitest::Test
5
+ class SchemaTest < Minitest::Test
6
6
  def setup
7
7
  @machine = UM.new
8
8
  @fn = "/tmp/#{rand(100000)}.db"
9
9
  FileUtils.rm(@fn) rescue nil
10
- @cp = Syntropy::DB::ConnectionPool.new(@machine, @fn, 4)
10
+ @cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
11
11
  end
12
12
 
13
13
  def teardown
@@ -15,7 +15,7 @@ class DBSchemaTest < Minitest::Test
15
15
  end
16
16
 
17
17
  def test_db_schema_initial
18
- schema = Syntropy::DB::Schema.new do
18
+ schema = Syntropy::Storage::Schema.new do
19
19
  initial do |db|
20
20
  db.execute <<~SQL
21
21
  create table posts (
@@ -35,7 +35,7 @@ class DBSchemaTest < Minitest::Test
35
35
  end
36
36
 
37
37
  def test_db_schema_version_blocks
38
- schema = Syntropy::DB::Schema.new do
38
+ schema = Syntropy::Storage::Schema.new do
39
39
  initial do |db|
40
40
  db.execute <<~SQL
41
41
  create table posts (
@@ -79,7 +79,7 @@ class DBSchemaTest < Minitest::Test
79
79
  module_loader = Syntropy::ModuleLoader.new({
80
80
  app_root: File.join(__dir__, 'fixtures/schema')
81
81
  })
82
- schema = Syntropy::DB::Schema.new(module_loader:, schema_root: '/')
82
+ schema = Syntropy::Storage::Schema.new(module_loader:, schema_root: '/')
83
83
 
84
84
  assert_nil schema.current_version(@cp)
85
85
  schema.apply(@cp)
@@ -2,12 +2,12 @@
2
2
 
3
3
  require_relative 'helper'
4
4
 
5
- class DBStoreTest < Minitest::Test
5
+ class StoreTest < Minitest::Test
6
6
  def setup
7
7
  @machine = UM.new
8
8
  @fn = "/tmp/#{rand(100000)}.db"
9
9
  FileUtils.rm(@fn) rescue nil
10
- @cp = Syntropy::DB::ConnectionPool.new(@machine, @fn, 4)
10
+ @cp = Syntropy::Storage::ConnectionPool.new(@machine, @fn, 4)
11
11
  end
12
12
 
13
13
  def teardown
@@ -15,7 +15,7 @@ class DBStoreTest < Minitest::Test
15
15
  end
16
16
 
17
17
  def test_db_store
18
- store = Syntropy::DB::Store.new(@cp)
18
+ store = Syntropy::Storage::Store.new(@cp)
19
19
 
20
20
  assert_equal [{a: 42}], store.query("select ? as a", 42)
21
21
  assert_equal({a: 42}, store.query_single_row("select ? as a", 42))
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syntropy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.35.0
4
+ version: 0.36.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -176,7 +176,7 @@ files:
176
176
  - cmd/new/template/Gemfile
177
177
  - cmd/new/template/README.md
178
178
  - cmd/new/template/app/_layout/default.rb
179
- - cmd/new/template/app/_lib/database.rb
179
+ - cmd/new/template/app/_lib/storage.rb
180
180
  - cmd/new/template/app/_schema/2026-01-01-initial.rb
181
181
  - cmd/new/template/app/assets/style.css
182
182
  - cmd/new/template/app/index.rb
@@ -186,29 +186,6 @@ files:
186
186
  - cmd/new/template/config/test.rb
187
187
  - cmd/new/template/docker-compose.yml
188
188
  - cmd/new/template/test/test_app.rb
189
- - cmd/new/template_old/site/.gitignore
190
- - cmd/new/template_old/site/Dockerfile
191
- - cmd/new/template_old/site/Gemfile
192
- - cmd/new/template_old/site/README.md
193
- - cmd/new/template_old/site/bin/console
194
- - cmd/new/template_old/site/bin/restart
195
- - cmd/new/template_old/site/bin/server
196
- - cmd/new/template_old/site/bin/start
197
- - cmd/new/template_old/site/bin/stop
198
- - cmd/new/template_old/site/docker-compose.yml
199
- - cmd/new/template_old/site/proxy/Dockerfile
200
- - cmd/new/template_old/site/proxy/etc/Caddyfile
201
- - cmd/new/template_old/site/proxy/etc/tls_auto
202
- - cmd/new/template_old/site/proxy/etc/tls_cloudflare
203
- - cmd/new/template_old/site/proxy/etc/tls_custom
204
- - cmd/new/template_old/site/proxy/etc/tls_selfsigned
205
- - cmd/new/template_old/site/site/_layout/default.rb
206
- - cmd/new/template_old/site/site/about.md
207
- - cmd/new/template_old/site/site/articles/cage.rb
208
- - cmd/new/template_old/site/site/articles/index.rb
209
- - cmd/new/template_old/site/site/assets/css/style.css
210
- - cmd/new/template_old/site/site/assets/img/syntropy.png
211
- - cmd/new/template_old/site/site/index.rb
212
189
  - cmd/serve.rb
213
190
  - cmd/test.rb
214
191
  - docker-compose.yml
@@ -222,8 +199,8 @@ files:
222
199
  - examples/basic/templates.rb
223
200
  - examples/blog/.gitignore
224
201
  - examples/blog/app/_layout/default.rb
225
- - examples/blog/app/_lib/database.rb
226
202
  - examples/blog/app/_lib/posts.rb
203
+ - examples/blog/app/_lib/storage.rb
227
204
  - examples/blog/app/_schema/2026-01-01-initial.rb
228
205
  - examples/blog/app/assets/style.css
229
206
  - examples/blog/app/index.rb
@@ -262,9 +239,6 @@ files:
262
239
  - lib/syntropy/applets/builtin/json_api.js
263
240
  - lib/syntropy/applets/builtin/ping.rb
264
241
  - lib/syntropy/applets/builtin/req.rb
265
- - lib/syntropy/db/connection_pool.rb
266
- - lib/syntropy/db/schema.rb
267
- - lib/syntropy/db/store.rb
268
242
  - lib/syntropy/dev_mode.rb
269
243
  - lib/syntropy/errors.rb
270
244
  - lib/syntropy/http.rb
@@ -288,6 +262,12 @@ files:
288
262
  - lib/syntropy/routing_tree.rb
289
263
  - lib/syntropy/session.rb
290
264
  - lib/syntropy/side_run.rb
265
+ - lib/syntropy/storage.rb
266
+ - lib/syntropy/storage/connection_pool.rb
267
+ - lib/syntropy/storage/kv_store.rb
268
+ - lib/syntropy/storage/prepared_query.rb
269
+ - lib/syntropy/storage/schema.rb
270
+ - lib/syntropy/storage/store.rb
291
271
  - lib/syntropy/test.rb
292
272
  - lib/syntropy/utils.rb
293
273
  - lib/syntropy/version.rb
@@ -340,23 +320,24 @@ files:
340
320
  - test/run.rb
341
321
  - test/test_app.rb
342
322
  - test/test_caching.rb
343
- - test/test_db_connection_pool.rb
344
- - test/test_db_schema.rb
345
- - test/test_db_store.rb
323
+ - test/test_connection_pool.rb
346
324
  - test/test_errors.rb
347
325
  - test/test_http_client.rb
348
326
  - test/test_http_client_connection.rb
349
327
  - test/test_http_protocol.rb
350
328
  - test/test_http_server_connection.rb
351
329
  - test/test_json_api.rb
330
+ - test/test_kv_store.rb
352
331
  - test/test_mock_adapter.rb
353
332
  - test/test_module_loader.rb
354
333
  - test/test_request.rb
355
334
  - test/test_request_session.rb
356
335
  - test/test_response.rb
357
336
  - test/test_routing_tree.rb
337
+ - test/test_schema.rb
358
338
  - test/test_server.rb
359
339
  - test/test_side_run.rb
340
+ - test/test_store.rb
360
341
  - test/test_test.rb
361
342
  homepage: https://github.com/digital-fabric/syntropy
362
343
  licenses:
@@ -1,13 +0,0 @@
1
- export self
2
-
3
- def connection_pool
4
- @connection_pool ||= DB::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
5
- end
6
-
7
- def schema
8
- DB::Schema.new(module_loader: @module_loader, schema_root: '_schema')
9
- end
10
-
11
- def migrate!
12
- schema.apply(connection_pool)
13
- end
@@ -1,57 +0,0 @@
1
- *.gem
2
- *.rbc
3
- /.config
4
- /coverage/
5
- /InstalledFiles
6
- /pkg/
7
- /spec/reports/
8
- /spec/examples.txt
9
- /test/tmp/
10
- /test/version_tmp/
11
- /tmp/
12
-
13
- # Used by dotenv library to load environment variables.
14
- # .env
15
-
16
- # Ignore Byebug command history file.
17
- .byebug_history
18
-
19
- ## Specific to RubyMotion:
20
- .dat*
21
- .repl_history
22
- build/
23
- *.bridgesupport
24
- build-iPhoneOS/
25
- build-iPhoneSimulator/
26
-
27
- ## Specific to RubyMotion (use of CocoaPods):
28
- #
29
- # We recommend against adding the Pods directory to your .gitignore. However
30
- # you should judge for yourself, the pros and cons are mentioned at:
31
- # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
- #
33
- # vendor/Pods/
34
-
35
- ## Documentation cache and generated files:
36
- /.yardoc/
37
- /_yardoc/
38
- /doc/
39
- /rdoc/
40
-
41
- ## Environment normalization:
42
- /.bundle/
43
- /vendor/bundle
44
- /lib/bundler/man/
45
-
46
- # for a library or gem, you might want to ignore these files since the code is
47
- # intended to run in multiple environments; otherwise, check them in:
48
- # Gemfile.lock
49
- # .ruby-version
50
- # .ruby-gemset
51
-
52
- # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
- .rvmrc
54
-
55
- # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
- # .rubocop-https?--*
57
- log
@@ -1,32 +0,0 @@
1
- ARG RUBY_BASE_IMAGE=ruby:3.4.1-alpine
2
- ARG GEM_CACHE_IMAGE=${RUBY_BASE_IMAGE}
3
-
4
- # base image
5
- FROM ${RUBY_BASE_IMAGE} AS base
6
- RUN apk add --update sqlite-dev openssl-dev tzdata bash curl zip git
7
- RUN apk add --update build-base
8
- RUN gem install bundler:2.6.9
9
-
10
- # gem cache
11
- FROM ${GEM_CACHE_IMAGE} AS gem-cache
12
- RUN mkdir -p /usr/local/bundle
13
-
14
- FROM base AS gems
15
- COPY --from=gem-cache /usr/local/bundle /usr/local/bundle
16
- COPY Gemfile Gemfile.lock ./
17
- RUN bundle install --jobs=4 --retry=5
18
-
19
- # Final backend image
20
- FROM base AS deploy
21
-
22
- RUN adduser -D app
23
- RUN chown app:app /home/app
24
- WORKDIR /home/app
25
- USER app
26
-
27
- RUN mkdir -p /tmp
28
- COPY --from=gems --chown=app:app /usr/local/bundle /usr/local/bundle
29
-
30
- EXPOSE 1234
31
-
32
- CMD ["bundle", "exec", "syntropy", "."]
@@ -1,3 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'syntropy', '0.3'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,51 +0,0 @@
1
- services:
2
- backend:
3
- build: .
4
- privileged: true
5
- restart: always
6
- ports:
7
- - 127.0.0.1:1234:1234
8
- # expose:
9
- # - 1234
10
- volumes:
11
- - .:/home/app
12
- deploy:
13
- # replicas: 1
14
- resources:
15
- limits:
16
- memory: 500M
17
- # restart: unless-stopped
18
- logging:
19
- driver: "json-file"
20
- options:
21
- max-size: "1M"
22
- max-file: "10"
23
-
24
- # healthcheck:
25
- # test: "curl 'http://localhost:1234/?q=ping'"
26
- # interval: "30s"
27
- # timeout: "3s"
28
- # start_period: "5s"
29
- # retries: 3
30
-
31
- proxy:
32
- depends_on:
33
- - backend
34
- build:
35
- context: ./proxy
36
- dockerfile: Dockerfile
37
- restart: always
38
- volumes:
39
- - ./proxy/etc/Caddyfile:/etc/caddy/Caddyfile
40
- ports:
41
- - "80:80"
42
- - "443:443"
43
- - "443:443/udp"
44
- # env_file:
45
- # - ./conf/caddy.env
46
- # - ./conf/caddy_sensitive.env
47
- logging:
48
- driver: "json-file"
49
- options:
50
- max-size: "1M"
51
- max-file: "10"
@@ -1,5 +0,0 @@
1
- FROM caddy:2.10.0-builder AS builder
2
- RUN xcaddy build
3
-
4
- FROM caddy:2.10.0
5
- COPY --from=builder /usr/bin/caddy /usr/bin/caddy
@@ -1,7 +0,0 @@
1
- localhost {
2
- reverse_proxy noteflakescom-backend-1:1234
3
- }
4
-
5
- my-awesome-domain.com {
6
- reverse_proxy noteflakescom-backend-1:1234
7
- }
@@ -1,2 +0,0 @@
1
- tls {$TLS_AUTO_EMAIL}
2
-
@@ -1,4 +0,0 @@
1
- tls {
2
- dns cloudflare {env.CLOUDFLARE_API_TOKEN}
3
- }
4
-
@@ -1 +0,0 @@
1
- tls {$TLS_CUSTOM_CERT} {$TLS_CUSTOM_KEY}
@@ -1 +0,0 @@
1
- tls internal
@@ -1,11 +0,0 @@
1
- export templ { |*a, **b|
2
- html {
3
- head {
4
- title 'My awesome Syntropy website'
5
- link rel: 'stylesheet', type: 'text/css', href: '/assets/css/style.css'
6
- }
7
- body {
8
- render_yield(*a, **b)
9
- }
10
- }
11
- }
@@ -1,6 +0,0 @@
1
- ---
2
- layout: default
3
- ---
4
- # About my site
5
-
6
- Lorem ipsum my awesome site.
@@ -1,29 +0,0 @@
1
- layout = import('_layout/default')
2
-
3
- poem = [
4
- " in ten\xA0", 'M', 'inutes',
5
- ' ', 'C', 'ome back: you will',
6
- 'have taught me chi', 'N', 'ese',
7
- ' (s', 'A', 'tie).',
8
- ' shall I ret', 'U', 'rn the favor?',
9
- ' ', 'G', 'ive you',
10
- ' ot', 'H', 'er lessons',
11
- ' (', 'T', 'ing!)?',
12
- ' ', 'O', 'r would you prefer',
13
- ' sile', 'N', 'ce?',
14
- ]
15
-
16
- export Papercraft.apply(layout) {
17
- article(class: 'mesostic') {
18
- h2 'For William McN. who studied with Ezra Pound'
19
-
20
- content {
21
- span(_for: poem) { text it }
22
- }
23
-
24
- author {
25
- span "-\xA0"
26
- a 'John cage', href: 'https://en.wikipedia.org/wiki/John_Cage'
27
- }
28
- }
29
- }
@@ -1,3 +0,0 @@
1
- export templ {
2
- h1 'Articles'
3
- }
@@ -1,40 +0,0 @@
1
- body {
2
- font-family: sans-serif;
3
- }
4
-
5
- article.mesostic {
6
- width: 600px;
7
- margin: 2em auto;
8
- font-size: 1.4em;
9
-
10
- * {
11
- font-family: monospace;
12
- }
13
-
14
- h2 {
15
- text-align: center;
16
- }
17
-
18
- content {
19
- display: grid;
20
- margin: 2em 0;
21
- grid-template-columns: 1fr auto 1fr;
22
-
23
- span {
24
- display: inline-block;
25
- }
26
- span:nth-child(3n + 1) {
27
- text-align: right;
28
- }
29
-
30
- span:nth-child(3n + 2) {
31
- text-align: center;
32
- font-weight: bold;
33
- }
34
- }
35
-
36
- author {
37
- display: block;
38
- text-align: right;
39
- }
40
- }
@@ -1,15 +0,0 @@
1
- layout = import('_layout/default')
2
-
3
- export Papercraft.apply(layout) {
4
- h1 'Hello from Syntropy'
5
- p {
6
- span "Here's an "
7
- a 'about', href: 'about'
8
- span ' page.'
9
- }
10
- p {
11
- span "Here's an "
12
- a 'article', href: 'articles/cage'
13
- span ' page.'
14
- }
15
- }
@@ -1,13 +0,0 @@
1
- export self
2
-
3
- def connection_pool
4
- @connection_pool ||= DB::ConnectionPool.new(@machine, @env[:config][:storage][:path], 4)
5
- end
6
-
7
- def schema
8
- DB::Schema.new(module_loader: @module_loader, schema_root: '_schema')
9
- end
10
-
11
- def migrate!
12
- schema.apply(connection_pool)
13
- end