fix typing

This commit is contained in:
Dylan Knutson
2025-01-27 04:54:33 +00:00
parent 69fc3652a2
commit ade1d478a5
9 changed files with 214 additions and 39 deletions

View File

@@ -31,7 +31,7 @@ class DbSampler
sig { void.params(file: T.untyped) }
def initialize(file)
@file = T.let(file, StringIO)
@file = T.let(file, T.any(StringIO, IO))
@handled = T.let(Set.new, T::Set[ReduxApplicationRecord])
end
@@ -148,7 +148,9 @@ class DbSampler
sig { params(model: ReduxApplicationRecord, level: Integer).void }
def dump(model, level)
@file.puts(Base64.strict_encode64(Zstd.compress(Marshal.dump(model), 1)))
@file.puts(
Base64.strict_encode64(Zstd.compress(Marshal.dump(model), level: 1)),
)
id = model.id
id = HexUtil.bin2hex(id) if model.class.primary_key == "sha256"
$stderr.puts ("-" * level) + " dumped #{model.class.name}/#{id}"

24
app/lib/graph.rb Normal file
View File

@@ -0,0 +1,24 @@
# typed: strict
module Graph
class Base < ActiveRecord::Base
end
class Node < Base
end
class Edge < Base
end
end
require_relative "graph/node/belongs_to_many_nodes_assoc"
require_relative "graph/node/belongs_to_node_assoc"
require_relative "graph/node/has_one_node_assoc"
require_relative "graph/node/has_many_nodes_assoc"
require_relative "graph/node_mixin"
require_relative "graph/edge_mixin"
require_relative "graph/column_type"
require_relative "graph/active_record_query_extensions"
require_relative "graph/base"
require_relative "graph/node"
require_relative "graph/edge"

View File

@@ -1,7 +1,7 @@
# typed: strict
require_relative("./active_record_query_extensions")
class Graph::Base < ReduxApplicationRecord
class Graph::Base < ActiveRecord::Base
extend T::Sig
extend T::Helpers
abstract!

View File

@@ -1,4 +1,4 @@
# typed: false
# typed: strict
class Domain::Fa::User < ReduxApplicationRecord
self.table_name = "domain_fa_users"
include Pundit::Authorization
@@ -65,6 +65,9 @@ class Domain::Fa::User < ReduxApplicationRecord
# `url_name` can be longer.
validates_presence_of(:name, :url_name)
validate do
T.bind(self, Domain::Fa::User)
name = self.name
url_name = self.url_name
if name && url_name
expected = self.class.name_to_url_name(name)
@@ -100,50 +103,68 @@ class Domain::Fa::User < ReduxApplicationRecord
before_destroy { throw :abort if posts.any? }
SCAN_TYPES = {
page: 1.month,
gallery: 1.year,
follows: 1.month,
favs: 1.month,
incremental: 1.month,
}
SCAN_TYPES =
T.let(
{
page: 1.month,
gallery: 1.year,
follows: 1.month,
favs: 1.month,
incremental: 1.month,
},
T::Hash[Symbol, ActiveSupport::Duration],
)
SCAN_FIELD_TYPES = {
page: :column,
gallery: :column,
follows: :column,
favs: :column,
incremental: :state_detail,
}
SCAN_FIELD_TYPES =
T.let(
{
page: :column,
gallery: :column,
follows: :column,
favs: :column,
incremental: :state_detail,
},
T::Hash[Symbol, Symbol],
)
SCAN_TYPES.keys.each do |scan_type|
define_method(:"due_for_#{scan_type}_scan?") { scan_due?(scan_type) }
define_method(:"due_for_#{scan_type}_scan?") do
T.bind(self, Domain::Fa::User)
scan_due?(scan_type)
end
define_method(:"time_ago_for_#{scan_type}_scan") do
T.bind(self, Domain::Fa::User)
scanned_ago_in_words(scan_type)
end
next unless SCAN_FIELD_TYPES[scan_type] == :state_detail
define_method(:"scanned_#{scan_type}_at") do
T.bind(self, Domain::Fa::User)
get_scanned_at_value(scan_type)
end
define_method(:"scanned_#{scan_type}_at=") do |value|
T.bind(self, Domain::Fa::User)
set_scanned_at_value(scan_type, value)
end
end
DATE_HELPER = Class.new.extend(ActionView::Helpers::DateHelper)
class DateHelper
extend ActionView::Helpers::DateHelper
end
sig { params(scan_type: Symbol).returns(String) }
def scanned_ago_in_words(scan_type)
if (timestamp = get_scanned_at_value(scan_type))
DATE_HELPER.time_ago_in_words(timestamp) + " ago"
DateHelper.time_ago_in_words(timestamp) + " ago"
else
"never"
end
end
sig { params(scan_type: Symbol).returns(T::Boolean) }
def scan_due?(scan_type)
duration =
SCAN_TYPES[scan_type] || raise("invalid scan type '#{scan_type}'")
@@ -151,6 +172,7 @@ class Domain::Fa::User < ReduxApplicationRecord
timestamp.nil? || timestamp <= duration.ago
end
sig { params(other_user: Domain::Fa::User).void }
def take_posts_from(other_user)
return if other_user == self
@@ -165,21 +187,24 @@ class Domain::Fa::User < ReduxApplicationRecord
self.class.transaction { avatar || create_avatar! }
end
sig do
params(
submission_parser:
T.any(
Domain::Fa::Parser::SubmissionParserHelper,
Domain::Fa::Parser::ListedSubmissionParserHelper,
),
).returns(Domain::Fa::User)
end
def self.find_or_build_from_submission_parser(submission_parser)
unless submission_parser.is_a?(
Domain::Fa::Parser::ListedSubmissionParserHelper,
) ||
submission_parser.is_a?(Domain::Fa::Parser::SubmissionParserHelper)
raise ArgumentError
end
find_or_initialize_by(url_name: submission_parser.artist_url_name) do |user|
user.name = submission_parser.artist
end
end
URL_NAME_EXCEPTIONS = { "Kammiu" => "rammiu" }
URL_NAME_EXCEPTIONS = T.let({ "Kammiu" => "rammiu" }, T::Hash[String, String])
sig { params(name: String).returns(String) }
def self.name_to_url_name(name)
name = name.strip
URL_NAME_EXCEPTIONS[name] || name.delete("_").gsub(/\s/, "").downcase
@@ -197,15 +222,26 @@ class Domain::Fa::User < ReduxApplicationRecord
# exclude self.follows.pluck(:followed_id)
# find users similar to 'self' based on who 'self' follows
sig do
params(exclude_followed_by: T.nilable(Domain::Fa::User)).returns(
PrivateRelation,
)
end
def similar_users_by_follower(exclude_followed_by: nil)
similar_users_by(:for_follower, exclude_followed_by)
end
# find users similar to 'self one based on who follows 'self'
sig do
params(exclude_followed_by: T.nilable(Domain::Fa::User)).returns(
PrivateRelation,
)
end
def similar_users_by_followed(exclude_followed_by: nil)
similar_users_by(:for_followed, exclude_followed_by)
end
sig { returns(T.nilable(HttpLogEntry)) }
def guess_user_page_log_entry
for_path =
proc do |uri_path|
@@ -234,14 +270,25 @@ class Domain::Fa::User < ReduxApplicationRecord
# TODO: - maybe can look for posts as well, those might list an avatar
end
sig { returns(T.nilable(String)) }
def to_param
url_name
end
private
sig do
params(
factor_col: Symbol,
exclude_followed_by: T.nilable(Domain::Fa::User),
).returns(PrivateRelation)
end
def similar_users_by(factor_col, exclude_followed_by)
query = disco.nearest_neighbors(factor_col, distance: "euclidean")
query =
T.cast(
T.must(disco).nearest_neighbors(factor_col, distance: "euclidean"),
Domain::Fa::User::PrivateRelation,
)
query =
query.where.not(
@@ -251,6 +298,7 @@ class Domain::Fa::User < ReduxApplicationRecord
users_from_disco_query(query)
end
sig { params(disco_query: PrivateRelation).returns(PrivateRelation) }
def users_from_disco_query(disco_query)
Domain::Fa::User
.select("domain_fa_users.*", disco_query.select_values.last)
@@ -258,6 +306,7 @@ class Domain::Fa::User < ReduxApplicationRecord
.merge(disco_query.reselect(:user_id))
end
sig { params(scan_type: Symbol).returns(T.nilable(Time)) }
def get_scanned_at_value(scan_type)
case SCAN_FIELD_TYPES[scan_type]
when :column
@@ -270,12 +319,13 @@ class Domain::Fa::User < ReduxApplicationRecord
end
end
sig { params(scan_type: Symbol, value: T.nilable(Time)).void }
def set_scanned_at_value(scan_type, value)
case SCAN_FIELD_TYPES[scan_type]
when :column
send(:"scanned_#{scan_type}_at=", value)
when :state_detail
state_detail["scanned_#{scan_type}_at"] = value.iso8601
state_detail["scanned_#{scan_type}_at"] = value&.iso8601
else
raise("invalid scan type '#{scan_type}'")
end

View File

@@ -1,5 +1,6 @@
# typed: strict
class Domain::Fa::UserFactor < ReduxApplicationRecord
include Neighbor::Model
self.table_name = "domain_fa_user_factors"
belongs_to :user, class_name: "::Domain::Fa::User"
@@ -7,4 +8,8 @@ class Domain::Fa::UserFactor < ReduxApplicationRecord
FACTORS_WIDTHS = 16
has_neighbors :for_follower
has_neighbors :for_followed
sig { void }
def foo
end
end

View File

@@ -1,4 +1,4 @@
# typed: strict
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for types exported from the `neighbor` gem.

View File

@@ -0,0 +1,11 @@
# typed: strict
module Neighbor::Model
sig do
params(attribute_name: Symbol, distance: String).returns(
ActiveRecord::Relation,
)
end
def nearest_neighbors(attribute_name, distance:)
end
end

View File

@@ -0,0 +1,89 @@
# typed: strict
class Domain::Fa::User
# define for:
# :page
# :gallery
# :follows
# :favs
# :incremental
sig { returns(T::Boolean) }
def due_for_page_scan?
end
sig { returns(T::Boolean) }
def due_for_gallery_scan?
end
sig { returns(T::Boolean) }
def due_for_follows_scan?
end
sig { returns(T::Boolean) }
def due_for_favs_scan?
end
sig { returns(T::Boolean) }
def due_for_incremental_scan?
end
sig { returns(String) }
def time_ago_for_page_scan
end
sig { returns(String) }
def time_ago_for_gallery_scan
end
sig { returns(String) }
def time_ago_for_follows_scan
end
sig { returns(String) }
def time_ago_for_favs_scan
end
sig { returns(String) }
def time_ago_for_incremental_scan
end
sig { returns(T.nilable(Time)) }
def scanned_page_at
end
sig { returns(T.nilable(Time)) }
def scanned_gallery_at
end
sig { returns(T.nilable(Time)) }
def scanned_follows_at
end
sig { returns(T.nilable(Time)) }
def scanned_favs_at
end
sig { returns(T.nilable(Time)) }
def scanned_incremental_at
end
sig { params(time: T.nilable(Time)).void }
def scanned_page_at=(time)
end
sig { params(time: T.nilable(Time)).void }
def scanned_gallery_at=(time)
end
sig { params(time: T.nilable(Time)).void }
def scanned_follows_at=(time)
end
sig { params(time: T.nilable(Time)).void }
def scanned_favs_at=(time)
end
sig { params(time: T.nilable(Time)).void }
def scanned_incremental_at=(time)
end
end

View File

@@ -1,14 +1,8 @@
# typed: true
# frozen_string_literal: true
require "./app/models/graph/node/belongs_to_node_assoc"
require "./app/models/graph/node/has_one_node_assoc"
require "./app/models/graph/node/has_many_nodes_assoc"
require "./spec/lib/graph/nodes_for_tests"
require "./app/lib/graph"
require "./app/lib/has_color_logger"
require "./app/lib/graph/base"
require "./app/lib/graph/edge"
require "./app/lib/graph/node"
require "./spec/helpers/debug_helpers"
require "./spec/helpers/http_client_mock_helpers"
require "./spec/helpers/perform_job_helpers"