Replace ActiveRecord with Sequel
This commit is contained in:
parent
689b650a75
commit
4cbd4d6f39
16 changed files with 96 additions and 88 deletions
|
@ -18,7 +18,7 @@ within your local network. It is both easy to use, and easy to install.
|
|||
* The server is powered by [rack](https://github.com/rack/rack) and [puma](https://github.com/puma/puma):
|
||||
- Accepts GraphQL requests at `/graphql`.
|
||||
- Serves client (HTML, JS, CSS).
|
||||
- Dependencies: ActiveRecord, SQLite3, ruby-graphql.
|
||||
- Dependencies: Sequel, SQLite3, ruby-graphql.
|
||||
* The client is a statically compiled [nanoc](https://github.com/nanoc/nanoc) website:
|
||||
- Dependencies: webpack, typescript, react.
|
||||
* The CLI controls the web server:
|
||||
|
|
|
@ -4,6 +4,8 @@ module Twenty::Command::SQLiteMixin
|
|||
def run_command(options)
|
||||
path = options.database || Twenty.default_database
|
||||
Twenty.establish_connection(path:)
|
||||
require "twenty-server/migration"
|
||||
require "twenty-server/model"
|
||||
super(options)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,13 +2,8 @@
|
|||
|
||||
module Twenty
|
||||
require "fileutils"
|
||||
require "active_record"
|
||||
require "sequel"
|
||||
require_relative "twenty-server/path"
|
||||
require_relative "twenty-server/graphql"
|
||||
require_relative "twenty-server/rack"
|
||||
require_relative "twenty-server/migration"
|
||||
require_relative "twenty-server/model"
|
||||
extend FileUtils
|
||||
extend Path
|
||||
|
||||
##
|
||||
|
@ -26,24 +21,24 @@ module Twenty
|
|||
#
|
||||
# @return [void]
|
||||
def self.establish_connection(path:)
|
||||
ActiveRecord::Base.establish_connection(
|
||||
adapter: "sqlite3",
|
||||
database: path,
|
||||
pool: 16
|
||||
@connection = Sequel.connect(
|
||||
adapter: "sqlite",
|
||||
database: path
|
||||
)
|
||||
end
|
||||
|
||||
##
|
||||
# Prepares the parent directory of the database.
|
||||
# @return [void]
|
||||
# @api private
|
||||
def self.prepare_dir
|
||||
mkdir_p(datadir)
|
||||
mkdir_p(tmpdir)
|
||||
touch(default_database)
|
||||
def self.connection
|
||||
establish_connection unless @connection
|
||||
@connection
|
||||
end
|
||||
|
||||
begin
|
||||
FileUtils.mkdir_p(datadir)
|
||||
FileUtils.mkdir_p(tmpdir)
|
||||
FileUtils.touch(default_database)
|
||||
rescue => ex
|
||||
warn "prepare_dir error: #{ex.message} (#{ex.class})"
|
||||
end
|
||||
private_class_method :prepare_dir
|
||||
prepare_dir
|
||||
require_relative "twenty-server/graphql"
|
||||
require_relative "twenty-server/rack"
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ module Twenty::GraphQL::Mutation
|
|||
argument :input, Twenty::GraphQL::Input::TaskInput
|
||||
|
||||
def resolve(input:)
|
||||
Twenty::Task.new(input.to_h).save!
|
||||
Twenty::Task.create(input.to_h)
|
||||
{"errors" => []}
|
||||
rescue => ex
|
||||
{"errors" => [ex.message]}
|
||||
|
|
|
@ -7,8 +7,9 @@ module Twenty::GraphQL::Mutation
|
|||
argument :input, Twenty::GraphQL::Input::TaskInput
|
||||
|
||||
def resolve(task_id:, input:)
|
||||
task = Twenty::Task.find_by(id: task_id)
|
||||
task.update!(input.to_h)
|
||||
Twenty::Task
|
||||
.with_pk!(task_id)
|
||||
.update!(input.to_h)
|
||||
{"errors" => []}
|
||||
rescue => ex
|
||||
{"errors" => [ex.message]}
|
||||
|
|
|
@ -11,15 +11,16 @@ module Twenty::GraphQL::Type
|
|||
end
|
||||
field :projects, [Project], null: false
|
||||
|
||||
|
||||
def find_task(task_id:)
|
||||
Twenty::Task.find_by(id: task_id)
|
||||
Twenty::Task.with_pk!(task_id)
|
||||
end
|
||||
|
||||
def tasks(status:, project_id: nil)
|
||||
tasks = Twenty::Task
|
||||
.where(status:)
|
||||
.order(updated_at: :desc)
|
||||
project_id ? tasks.where(project_id:) : tasks
|
||||
.by_status(status)
|
||||
.order("updated_at DESC")
|
||||
(project_id ? tasks.where(project_id:) : tasks).all
|
||||
end
|
||||
|
||||
def projects
|
||||
|
|
|
@ -1,34 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Twenty::Migration
|
||||
require "sequel/extensions/migration"
|
||||
##
|
||||
# @return [String]
|
||||
# Returns the path to twenty's migrations.
|
||||
def self.migrations_path
|
||||
[File.join(__dir__, "migration")]
|
||||
File.join(__dir__, "migration")
|
||||
end
|
||||
|
||||
##
|
||||
# Runs migrations (if neccessary).
|
||||
# @return [void]
|
||||
def self.run!
|
||||
context.migrate
|
||||
Sequel::Migrator.run(Twenty.connection, migrations_path)
|
||||
end
|
||||
ActiveRecord.timestamped_migrations = false
|
||||
|
||||
##
|
||||
# @return [Boolean]
|
||||
# Returns true when there are pending migrations.
|
||||
def self.pending_migrations?
|
||||
context.open.pending_migrations.any?
|
||||
Sequel::Migrator.is_current?(Twenty.connection, migrations_path)
|
||||
end
|
||||
|
||||
##
|
||||
# @return [ActiveRecord::MigrationContext]
|
||||
# Returns an instance of
|
||||
# {ActiveRecord::MigrationContext ActiveRecord::MigrationContext}.
|
||||
def self.context
|
||||
@context ||= ActiveRecord::MigrationContext.new(migrations_path)
|
||||
end
|
||||
private_class_method :context
|
||||
end
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateProjects < ActiveRecord::Migration[7.1]
|
||||
def up
|
||||
create_table(:projects) do |t|
|
||||
t.string :name, null: false
|
||||
t.string :path, null: false
|
||||
t.timestamps
|
||||
Sequel.migration do
|
||||
up do
|
||||
create_table(:projects) do
|
||||
primary_key :id
|
||||
String :name, null: false
|
||||
String :path, null: false
|
||||
DateTime :created_at
|
||||
DateTime :updated_at
|
||||
end
|
||||
add_index :projects, [:name, :path], unique: true
|
||||
end
|
||||
|
||||
def down
|
||||
down do
|
||||
drop_table(:projects)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateTasks < ActiveRecord::Migration[7.1]
|
||||
def up
|
||||
Sequel.migration do
|
||||
up do
|
||||
create_table(:tasks) do |t|
|
||||
t.string :title, null: false
|
||||
t.text :content, null: false
|
||||
t.integer :status, null: false, default: 0
|
||||
t.belongs_to :project, null: false
|
||||
t.timestamps
|
||||
primary_key :id
|
||||
String :title, null: false
|
||||
Text :content, null: false
|
||||
Integer :status, null: false, default: 0
|
||||
DateTime :created_at
|
||||
DateTime :updated_at
|
||||
foreign_key :project_id, :projects, null: false
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
down do
|
||||
drop_table(:tasks)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddColorToProjects < ActiveRecord::Migration[7.1]
|
||||
def up
|
||||
Sequel.migration do
|
||||
up do
|
||||
default = Twenty::ColorableMixin.random_color
|
||||
add_column :projects, :color, :string, null: false, default:
|
||||
end
|
||||
|
||||
def down
|
||||
down do
|
||||
drop_column :projects, :color
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Twenty::Model < ActiveRecord::Base
|
||||
module Twenty::Model
|
||||
def self.included(model)
|
||||
model.plugin(:validation_class_methods)
|
||||
model.plugin(:timestamps, update_on_create: true)
|
||||
end
|
||||
|
||||
require_relative "model/mixin/colorable_mixin"
|
||||
require_relative "model/project"
|
||||
require_relative "model/task"
|
||||
|
|
|
@ -14,8 +14,9 @@ module Twenty::ColorableMixin
|
|||
"#993366", "#2200AA", "#557788", "#998877", "#BB4400"
|
||||
]
|
||||
|
||||
def self.included(klass)
|
||||
klass.before_validation :set_random_color, on: :create
|
||||
def before_validation
|
||||
super if defined?(super)
|
||||
set_random_color
|
||||
end
|
||||
|
||||
def random_color
|
||||
|
@ -25,6 +26,7 @@ module Twenty::ColorableMixin
|
|||
private
|
||||
|
||||
def set_random_color
|
||||
return if id
|
||||
self.color = random_color
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Twenty::Project < Twenty::Model
|
||||
class Twenty::Project < Sequel::Model
|
||||
include Twenty::Model
|
||||
include Twenty::ColorableMixin
|
||||
self.table_name = "projects"
|
||||
|
||||
##
|
||||
# Validations
|
||||
validates :name, presence: true
|
||||
validates :path, presence: true
|
||||
|
||||
##
|
||||
# Associations
|
||||
has_many :tasks, class_name: "Twenty::Task"
|
||||
validates_presence_of :name
|
||||
validates_presence_of :path
|
||||
one_to_many :tasks, class_name: "Twenty::Task"
|
||||
|
||||
##
|
||||
# @return [String]
|
||||
|
|
|
@ -1,18 +1,32 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Twenty::Task < Twenty::Model
|
||||
self.table_name = "tasks"
|
||||
class Twenty::Task < Sequel::Model
|
||||
include Twenty::Model
|
||||
|
||||
STATUS = {backlog: 0, ready: 1, in_progress: 2, complete: 3}
|
||||
enum :status, STATUS, default: :backlog
|
||||
plugin(:enum)
|
||||
STATUS_MAP = {backlog: 0, ready: 1, in_progress: 2, complete: 3}
|
||||
STATUS_KEYS = STATUS_MAP.keys
|
||||
enum :status, STATUS_MAP
|
||||
|
||||
##
|
||||
# Validations
|
||||
validates :title, presence: true
|
||||
validates :content, presence: true
|
||||
validates :project, presence: true
|
||||
def self.by_status(status)
|
||||
if STATUS_KEYS.any? { _1.to_s == status.to_s }
|
||||
public_send(status)
|
||||
else
|
||||
where(id: nil)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Associations
|
||||
belongs_to :project, class_name: "Twenty::Project"
|
||||
validates_presence_of :title
|
||||
validates_presence_of :content
|
||||
validates_presence_of :project
|
||||
validates_inclusion_of :status, in: [STATUS_KEYS, *STATUS_KEYS.map(&:to_s)]
|
||||
many_to_one :project, class_name: "Twenty::Project"
|
||||
|
||||
def status=(v)
|
||||
super(v.to_sym)
|
||||
end
|
||||
|
||||
def status
|
||||
super.to_s
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|||
gem.require_paths = ["lib"]
|
||||
gem.summary = "twenty: server-side component"
|
||||
gem.description = gem.summary
|
||||
gem.add_runtime_dependency "activerecord", "~> 7.1"
|
||||
gem.add_runtime_dependency "sequel", "~> 5.78"
|
||||
gem.add_runtime_dependency "sqlite3", "~> 1.6"
|
||||
gem.add_runtime_dependency "graphql", "~> 2.2"
|
||||
gem.add_runtime_dependency "server.rb", "~> 0.1"
|
||||
|
|
|
@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|||
gem.require_paths = ["lib"]
|
||||
gem.summary = "twenty: server-side component"
|
||||
gem.description = gem.summary
|
||||
gem.add_runtime_dependency "activerecord", "~> 7.1"
|
||||
gem.add_runtime_dependency "sequel", "~> 5.78"
|
||||
gem.add_runtime_dependency "sqlite3", "~> 1.6"
|
||||
gem.add_runtime_dependency "graphql", "~> 2.2"
|
||||
gem.add_runtime_dependency "server.rb", "~> 0.1"
|
||||
|
|
Loading…
Reference in a new issue