cache bundle install at devcontainer build step
This commit is contained in:
@@ -21,6 +21,10 @@ RSpec.describe HasAuxTable do
|
||||
end
|
||||
|
||||
describe "column reporting" do
|
||||
it "reports columns of the base class" do
|
||||
expect(Vehicle.inspect).to include("name")
|
||||
end
|
||||
|
||||
it "reports the correct columns on the string repr of the class" do
|
||||
expect(Car.inspect).to include("fuel_type")
|
||||
end
|
||||
@@ -106,7 +110,7 @@ RSpec.describe HasAuxTable do
|
||||
end
|
||||
|
||||
it "can set association on aux record" do
|
||||
driver = Driver.create!(name: "John Doe")
|
||||
driver = Driver.create!(name: "John Doe", license_number: 12_345)
|
||||
car = Car.create!(name: "Honda Civic")
|
||||
driver.car = car
|
||||
expect(driver.car).to eq(car)
|
||||
@@ -142,6 +146,20 @@ RSpec.describe HasAuxTable do
|
||||
expect(plane.engine_type).to eq("turboprop")
|
||||
end
|
||||
|
||||
describe "validations" do
|
||||
it "validates the main record" do
|
||||
driver = Driver.create!(name: "John Doe", license_number: 12_345)
|
||||
expect(driver.valid?).to be_truthy
|
||||
driver.name = nil
|
||||
expect(driver.valid?).to be_falsey
|
||||
end
|
||||
|
||||
it "validates through an association" do
|
||||
car = Car.create!(name: "Honda Civic")
|
||||
car.drivers.create!(name: "John Doe", license_number: 12_345)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#changed?" do
|
||||
it "returns true if the main record changes" do
|
||||
car = Car.create!(name: "Honda Civic")
|
||||
@@ -361,10 +379,7 @@ RSpec.describe HasAuxTable do
|
||||
end
|
||||
|
||||
it "works with chained where clauses" do
|
||||
# Chain where clauses with auxiliary columns
|
||||
|
||||
efficient_cars = Car.where(fuel_type: "hybrid").where(engine_size: 1.8)
|
||||
|
||||
expect(efficient_cars.length).to eq(1)
|
||||
expect(efficient_cars.first.name).to eq("Toyota Prius")
|
||||
end
|
||||
@@ -377,6 +392,12 @@ RSpec.describe HasAuxTable do
|
||||
car_names = cars.map(&:name).sort
|
||||
expect(car_names).to eq(["Tesla Model 3", "Toyota Prius"])
|
||||
end
|
||||
|
||||
it "works when sql is passed to where" do
|
||||
cars = Car.where("fuel_type = 'hybrid'")
|
||||
expect(cars.length).to eq(1)
|
||||
expect(cars.first.name).to eq("Toyota Prius")
|
||||
end
|
||||
end
|
||||
|
||||
describe "query performance and optimization" do
|
||||
@@ -689,7 +710,7 @@ RSpec.describe HasAuxTable do
|
||||
|
||||
describe "nested associations" do
|
||||
it "can create a driver through the association" do
|
||||
driver = @car.drivers.create!(name: "John Doe")
|
||||
driver = @car.drivers.create!(name: "John Doe", license_number: 123_456)
|
||||
expect(driver.car).to eq(@car)
|
||||
expect(driver.car_id).to eq(@car.id)
|
||||
expect(driver.car.fuel_type).to eq("hybrid")
|
||||
@@ -708,7 +729,8 @@ RSpec.describe HasAuxTable do
|
||||
end
|
||||
|
||||
it "can create a driver directly" do
|
||||
driver = Driver.create!(car: @car, name: "John Doe")
|
||||
driver =
|
||||
Driver.create!(car: @car, name: "John Doe", license_number: 123_456)
|
||||
expect(driver.car).to eq(@car)
|
||||
expect(driver.car_id).to eq(@car.id)
|
||||
expect(driver.car.fuel_type).to eq("hybrid")
|
||||
@@ -716,12 +738,12 @@ RSpec.describe HasAuxTable do
|
||||
end
|
||||
|
||||
it "can be accessed through the association" do
|
||||
driver = @car.drivers.create!(name: "John Doe")
|
||||
driver = @car.drivers.create!(name: "John Doe", license_number: 123_456)
|
||||
expect(@car.drivers).to eq([driver])
|
||||
end
|
||||
|
||||
it "can be destroyed through the association" do
|
||||
driver = @car.drivers.create!(name: "John Doe")
|
||||
driver = @car.drivers.create!(name: "John Doe", license_number: 123_456)
|
||||
expect { driver.destroy }.to change { @car.reload.drivers.count }.by(-1)
|
||||
end
|
||||
|
||||
@@ -736,6 +758,15 @@ RSpec.describe HasAuxTable do
|
||||
d = drivers.find_by(license_number: 123_456)
|
||||
expect(d.id).to eq(driver.id)
|
||||
end
|
||||
|
||||
# it "can create STI models through associations" do
|
||||
# user =
|
||||
# TwitterUser.create!(last_login_at: Time.now, twitter_handle: "a_user")
|
||||
# post = user.posts.create!(title: "twitter post")
|
||||
# expect(post.user).to eq(user)
|
||||
# expect(post.user_id).to eq(user.id)
|
||||
# expect(post.user.twitter_handle).to eq("a_user")
|
||||
# end
|
||||
end
|
||||
|
||||
describe "#reload" do
|
||||
@@ -768,7 +799,7 @@ RSpec.describe HasAuxTable do
|
||||
it "reloads associations" do
|
||||
expect(@car.drivers.length).to eq(0)
|
||||
|
||||
Driver.create!(car: @car, name: "Billy Kid")
|
||||
Driver.create!(car: @car, name: "Billy Kid", license_number: 123_456)
|
||||
expect(@car.drivers.length).to eq(0)
|
||||
expect(@car.drivers.count).to eq(1)
|
||||
|
||||
@@ -869,4 +900,15 @@ RSpec.describe HasAuxTable do
|
||||
expect(@book.read_book_joins.count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe "joins model with aux tables" do
|
||||
it "can create a join record" do
|
||||
doctor = Person.create!(name: "Dr. John Doe")
|
||||
patient = Person.create!(name: "Jane Doe")
|
||||
assoc = doctor.patients
|
||||
assoc << patient
|
||||
expect(doctor.patients.count).to eq(1)
|
||||
expect(patient.doctors.count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
# typed: strict
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "simplecov"
|
||||
require "simplecov-lcov"
|
||||
|
||||
SimpleCov::Formatter::LcovFormatter.config do |c|
|
||||
c.report_with_single_file = true
|
||||
c.lcov_file_name = "lcov.info"
|
||||
end
|
||||
|
||||
SimpleCov.start do
|
||||
enable_coverage :branch
|
||||
add_filter "spec"
|
||||
formatter(
|
||||
SimpleCov::Formatter::MultiFormatter.new(
|
||||
[
|
||||
SimpleCov::Formatter::LcovFormatter, # Add Lcov as an output when generating code coverage report
|
||||
SimpleCov::Formatter::HTMLFormatter # Add other outputs for the code coverage report
|
||||
]
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
require "pry"
|
||||
require "active_record"
|
||||
require "active_record/errors"
|
||||
require "has_aux_table"
|
||||
require "pry"
|
||||
|
||||
# Configure ActiveRecord to use in-memory SQLite database
|
||||
ActiveRecord::Base.establish_connection(
|
||||
@@ -21,7 +42,7 @@ RSpec.configure do |config|
|
||||
# Disable RSpec exposing methods globally on `Module` and `main`
|
||||
config.disable_monkey_patching!
|
||||
|
||||
# config.backtrace_inclusion_patterns = [/\bactiverecord\b/]
|
||||
config.backtrace_inclusion_patterns = [/\bactiverecord\b/]
|
||||
|
||||
config.expect_with :rspec do |c|
|
||||
c.syntax = :expect
|
||||
|
||||
@@ -18,7 +18,9 @@ ActiveRecord::Schema.define do
|
||||
t.string :fuel_type
|
||||
t.decimal :engine_size, precision: 3, scale: 1
|
||||
end
|
||||
end
|
||||
|
||||
change_base_table :vehicles do |t|
|
||||
t.create_aux :boat do |t|
|
||||
t.boolean :only_freshwater
|
||||
end
|
||||
@@ -35,7 +37,7 @@ ActiveRecord::Schema.define do
|
||||
t.timestamps
|
||||
|
||||
t.create_aux :driver do |t|
|
||||
t.integer :license_number
|
||||
t.integer :license_number, index: true, null: false
|
||||
t.references :car,
|
||||
foreign_key: {
|
||||
to_table: :vehicles_car_aux,
|
||||
@@ -62,6 +64,20 @@ ActiveRecord::Schema.define do
|
||||
end
|
||||
end
|
||||
|
||||
create_base_table :relationship_joins do |t|
|
||||
t.create_aux :doctor_patient do |t|
|
||||
t.integer :num_exams
|
||||
t.references :doctor, foreign_key: { to_table: :people }
|
||||
t.references :patient, foreign_key: { to_table: :people }
|
||||
end
|
||||
|
||||
t.create_aux :employer_employee do |t|
|
||||
t.boolean :signed_nda
|
||||
t.references :employer, foreign_key: { to_table: :people }
|
||||
t.references :employee, foreign_key: { to_table: :people }
|
||||
end
|
||||
end
|
||||
|
||||
create_base_table :utensils do |t|
|
||||
t.string :name
|
||||
t.string :material
|
||||
@@ -127,12 +143,82 @@ class Plane < Vehicle
|
||||
end
|
||||
|
||||
class Person < ActiveRecord::Base
|
||||
extend T::Sig
|
||||
include HasAuxTable
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
|
||||
sig do
|
||||
params(
|
||||
associations: [Symbol, Symbol],
|
||||
table_name: Symbol,
|
||||
model_class_name: T.any(Symbol, String, T.class_of(ActiveRecord::Base)),
|
||||
join_class_name: T.any(Symbol, String, T.class_of(ActiveRecord::Base))
|
||||
).void
|
||||
end
|
||||
def self.has_and_belongs_to_many_through(
|
||||
associations,
|
||||
table_name:,
|
||||
model_class_name:,
|
||||
join_class_name:
|
||||
)
|
||||
from_assoc_plural, to_assoc_plural = associations
|
||||
from_assoc_class_name, to_assoc_class_name =
|
||||
model_class_name,
|
||||
model_class_name
|
||||
from_assoc_singular = from_assoc_plural.to_s.singularize
|
||||
from_join_assoc_name = :"#{from_assoc_singular}_#{table_name}"
|
||||
to_assoc_singular = to_assoc_plural.to_s.singularize
|
||||
to_join_assoc_name = :"#{to_assoc_singular}_#{table_name}"
|
||||
|
||||
has_many(
|
||||
from_join_assoc_name,
|
||||
primary_key: primary_key,
|
||||
foreign_key: "#{from_assoc_singular}_id",
|
||||
inverse_of: from_assoc_singular,
|
||||
class_name: join_class_name
|
||||
)
|
||||
has_many(
|
||||
to_assoc_plural,
|
||||
through: from_join_assoc_name,
|
||||
source: to_assoc_singular,
|
||||
class_name: to_assoc_class_name
|
||||
)
|
||||
|
||||
has_many(
|
||||
to_join_assoc_name,
|
||||
primary_key: primary_key,
|
||||
foreign_key: "#{to_assoc_singular}_id",
|
||||
inverse_of: to_assoc_singular,
|
||||
class_name: join_class_name
|
||||
)
|
||||
has_many(
|
||||
from_assoc_plural,
|
||||
through: to_join_assoc_name,
|
||||
source: from_assoc_singular,
|
||||
class_name: from_assoc_class_name
|
||||
)
|
||||
end
|
||||
|
||||
has_and_belongs_to_many_through(
|
||||
%i[doctors patients],
|
||||
model_class_name: "Person",
|
||||
join_class_name: "DoctorPatientJoin",
|
||||
table_name: :doctor_patient_joins
|
||||
)
|
||||
|
||||
has_and_belongs_to_many_through(
|
||||
%i[employers employees],
|
||||
model_class_name: "Person",
|
||||
join_class_name: "EmployerEmployeeJoin",
|
||||
table_name: :employer_employee_joins
|
||||
)
|
||||
end
|
||||
|
||||
class Driver < Person
|
||||
aux_table :driver
|
||||
belongs_to :car, optional: true
|
||||
validates :license_number, presence: true, uniqueness: true
|
||||
end
|
||||
|
||||
class Captain < Person
|
||||
@@ -177,3 +263,52 @@ class ReadBookJoin < ActiveRecord::Base
|
||||
belongs_to :book, counter_cache: true
|
||||
belongs_to :reader, counter_cache: true
|
||||
end
|
||||
|
||||
# Join table that has aux records
|
||||
class RelationshipJoin < ActiveRecord::Base
|
||||
include HasAuxTable
|
||||
end
|
||||
|
||||
class DoctorPatientJoin < RelationshipJoin
|
||||
aux_table :doctor_patient
|
||||
belongs_to :doctor, class_name: "Person"
|
||||
belongs_to :patient, class_name: "Person"
|
||||
end
|
||||
|
||||
class EmployerEmployeeJoin < RelationshipJoin
|
||||
aux_table :employer_employee
|
||||
belongs_to :employer, class_name: "Person"
|
||||
belongs_to :employee, class_name: "Person"
|
||||
end
|
||||
|
||||
class User < ActiveRecord::Base
|
||||
include HasAuxTable
|
||||
has_many :posts, inverse_of: :user, class_name: "Post"
|
||||
end
|
||||
|
||||
# class TwitterUser < User
|
||||
# aux_table :twitter
|
||||
# validates :twitter_handle, presence: true
|
||||
# has_many :posts, inverse_of: :user, class_name: "TwitterPost"
|
||||
# end
|
||||
|
||||
# class RedditUser < User
|
||||
# aux_table :reddit
|
||||
# validates :reddit_handle, presence: true
|
||||
# has_many :posts, inverse_of: :user, class_name: "RedditPost"
|
||||
# end
|
||||
|
||||
# class Post < ActiveRecord::Base
|
||||
# include HasAuxTable
|
||||
# belongs_to :user, inverse_of: :posts
|
||||
# end
|
||||
|
||||
# class TwitterPost < Post
|
||||
# aux_table :twitter
|
||||
# belongs_to :user, inverse_of: :posts, class_name: "TwitterUser"
|
||||
# end
|
||||
|
||||
# class RedditPost < Post
|
||||
# aux_table :reddit
|
||||
# belongs_to :user, inverse_of: :posts, class_name: "RedditUser"
|
||||
# end
|
||||
|
||||
Reference in New Issue
Block a user