diff --git a/app/models/pool.rb b/app/models/pool.rb index a48e78e67..ab6c64d3d 100644 --- a/app/models/pool.rb +++ b/app/models/pool.rb @@ -2,7 +2,7 @@ class Pool < ActiveRecord::Base validates_uniqueness_of :name validates_presence_of :name validates_format_of :name, :with => /\A[^\s;,]+\Z/, :on => :create, :message => "cannot have whitespace, commas, or semicolons" - belongs_to :creator, :class_name => "Person" + belongs_to :creator, :class_name => "User" def self.create_anonymous(creator) pool = Pool.create(:name => "TEMP - #{Time.now.to_f}.#{rand(1_000_000)}", :creator => creator) @@ -14,7 +14,7 @@ class Pool < ActiveRecord::Base post_ids =~ /\A#{post.id} (\d+)|(\d+) #{post.id} (\d+)|(\d+) #{post.id}\Z/ if $2 && $3 - {:previous => $2.to_i, :next = $3.to_i} + {:previous => $2.to_i, :next => $3.to_i} elsif $1 {:previous => $1.to_i} elsif $4 diff --git a/app/models/post.rb b/app/models/post.rb index b4b51b336..e5474a5a9 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -4,9 +4,13 @@ class Post < ActiveRecord::Base has_one :unapproval after_destroy :delete_files after_save :create_version + before_save :merge_old_tags before_save :normalize_tags + before_save :create_tags + before_save :update_tag_post_counts before_save :set_tag_counts + has_many :versions, :class_name => "PostVersion" module FileMethods @@ -133,8 +137,23 @@ class Post < ActiveRecord::Base end module TagMethods - def tag_array(reload = false) - Tag.scan_tags(tag_string) + def tag_array + @tag_array ||= Tag.scan_tags(tag_string) + end + + def tag_array_was + @tag_array_was ||= Tag.scan_tags(tag_string_was) + end + + def create_tags + set_tag_string(tag_array.map {|x| Tag.find_or_create_by_name(x).name}.join(" ")) + end + + def update_tag_post_counts + decrement_tags = tag_array_was - tag_array + increment_tags = tag_array - tag_array_was + execute_sql("UPDATE tags SET post_count = post_count - 1 WHERE name IN (?)", decrement_tags) if decrement_tags.any? + execute_sql("UPDATE tags SET post_count = post_count + 1 WHERE name IN (?)", increment_tags) if increment_tags.any? end def set_tag_counts @@ -171,16 +190,26 @@ class Post < ActiveRecord::Base current_tags = Tag.scan_tags(tag_string_was) new_tags = tag_array() old_tags = Tag.scan_tags(old_tag_string) - self.tag_string = ((current_tags + new_tags) - old_tags + (current_tags & new_tags)).uniq.join(" ") + set_tag_string(((current_tags + new_tags) - old_tags + (current_tags & new_tags)).uniq.join(" ")) end end + def reset_tag_array_cache + @tag_array = nil + @tag_array_was = nil + end + + def set_tag_string(string) + self.tag_string = string + reset_tag_array_cache + end + def normalize_tags normalized_tags = Tag.scan_tags(tag_string) - # normalized_tags = TagAlias.to_aliased(normalized_tags) - # normalized_tags = TagImplication.with_implications(normalized_tags) + normalized_tags = TagAlias.to_aliased(normalized_tags) + normalized_tags = TagImplication.with_descendants(normalized_tags) normalized_tags = filter_metatags(normalized_tags) - self.tag_string = normalized_tags.uniq.join(" ") + set_tag_string(normalized_tags.uniq.join(" ")) end def filter_metatags(tags) @@ -203,28 +232,28 @@ class Post < ActiveRecord::Base module SearchMethods class SearchError < Exception ; end - def add_range_relation(arr, field, arel) + def add_range_relation(arr, field, relation) case arr[0] when :eq - arel.where(["#{field} = ?", arr[1]]) + relation.where(["#{field} = ?", arr[1]]) when :gt - arel.where(["#{field} > ?"], arr[1]) + relation.where(["#{field} > ?", arr[1]]) when :gte - arel.where(["#{field} >= ?", arr[1]]) + relation.where(["#{field} >= ?", arr[1]]) when :lt - arel.where(["#{field} < ?", arr[1]]) + relation.where(["#{field} < ?", arr[1]]) when :lte - arel.where(["#{field} <= ?", arr[1]]) + relation.where(["#{field} <= ?", arr[1]]) when :between - arel.where(["#{field} BETWEEN ? AND ?", arr[1], arr[2]]) + relation.where(["#{field} BETWEEN ? AND ?", arr[1], arr[2]]) else - # do nothing + relation end end @@ -258,8 +287,10 @@ class Post < ActiveRecord::Base end if tag_query_sql.any? - relation.where("posts.tag_index @@ to_tsquery('danbooru', E'" + tag_query_sql.join(" & ") + "')") + relation = relation.where("posts.tag_index @@ to_tsquery('danbooru', E'" + tag_query_sql.join(" & ") + "')") end + + relation end def add_tag_subscription_relation(subscriptions, relation) @@ -272,126 +303,123 @@ class Post < ActiveRecord::Base if user post_ids = TagSubscription.find_post_ids(user.id, subscription_name) - relation.where(["posts.id IN (?)", post_ids]) + relation = relation.where(["posts.id IN (?)", post_ids]) end end - end - - def build_relation(q, options = {}) - unless q.is_a?(Hash) - q = Tag.parse_query(q) - end - - relation = where() - - add_range_relation(q[:post_id], "posts.id", relation) - add_range_relation(q[:mpixels], "posts.width * posts.height / 1000000.0", relation) - add_range_relation(q[:width], "posts.image_width", relation) - add_range_relation(q[:height], "posts.image_height", relation) - add_range_relation(q[:score], "posts.score", relation) - add_range_relation(q[:filesize], "posts.file_size", relation) - add_range_relation(q[:date], "posts.created_at::date", relation) - add_range_relation(q[:general_tag_count], "posts.tag_count_general", relation) - add_range_relation(q[:artist_tag_count], "posts.tag_count_artist", relation) - add_range_relation(q[:copyright_tag_count], "posts.tag_count_copyright", relation) - add_range_relation(q[:character_tag_count], "posts.tag_count_character", relation) - add_range_relation(q[:tag_count], "posts.tag_count", relation) - - if options[:before_id] - relation.where(["posts.id < ?", options[:before_id]]) - end - - if q[:md5].is_a?(String) - relation.where(["posts.md5 IN (?)", q[:md5]]) - end - - if q[:status] == "deleted" - relation.where("posts.is_deleted = TRUE") - elsif q[:status] == "pending" - relation.where("posts.is_pending = TRUE") - elsif q[:status] == "flagged" - relation.where("posts.is_flagged = TRUE") - else - relation.where("posts.is_deleted = FALSE") - end - - if q[:source].is_a?(String) - relation.where(["posts.source LIKE ? ESCAPE E'\\\\", q[:source]]) - end - - if q[:subscriptions].any? - add_tag_subscription_relation(q[:subscriptions], relation) - end - - add_tag_string_search_relation(q[:tags], relation) - - if q[:rating] == "q" - relation.where("posts.rating = 'q'") - elsif q[:rating] == "s" - relation.where("posts.rating = 's'") - elsif q[:rating] == "e" - relation.where("posts.rating = 'e'") - end - - if q[:rating_negated] == "q" - relation.where("posts.rating <> 'q'") - elsif q[:rating_negated] == "s" - relation.where("posts.rating <> 's'") - elsif q[:rating_negated] == "e" - relation.where("posts.rating <> 'e'") - end - - case q[:order] - when "id", "id_asc" - relation.order("posts.id") - - when "id_desc" - relation.order("posts.id DESC") - - when "score", "score_desc" - relation.order("posts.score DESC, posts.id DESC") - - when "score_asc" - relation.order("posts.score, posts.id DESC") - - when "mpixels", "mpixels_desc" - # Use "w*h/1000000", even though "w*h" would give the same result, so this can use - # the posts_mpixels index. - relation.order("posts.image_width * posts.image_height / 1000000.0 DESC, posts.id DESC") - - when "mpixels_asc" - relation.order("posts.image_width * posts.image_height / 1000000.0, posts.id DESC") - - when "portrait" - relation.order("1.0 * image_width / GREATEST(1, image_height), posts.id DESC") - - when "landscape" - relation.order("1.0 * image_width / GREATEST(1, image_height) DESC, p.id DESC") - - when "filesize", "filesize_desc" - relation.order("posts.file_size DESC") - - when "filesize_asc" - relation.order("posts.file_size") - - else - relation.order("posts.id DESC") - end - - if options[:limit] - relation.limit(options[:limit]) - end - - if options[:offset] - relation.offset(options[:offset]) - end relation end - - def find_by_tags(tags, options) - hash = Tag.parse_query(tags) - build_relation(hash, options) + + def find_by_tags(q, options = {}) + unless q.is_a?(Hash) + q = Tag.parse_query(q) + end + + relation = where() + + relation = add_range_relation(q[:post_id], "posts.id", relation) + relation = add_range_relation(q[:mpixels], "posts.width * posts.height / 1000000.0", relation) + relation = add_range_relation(q[:width], "posts.image_width", relation) + relation = add_range_relation(q[:height], "posts.image_height", relation) + relation = add_range_relation(q[:score], "posts.score", relation) + relation = add_range_relation(q[:filesize], "posts.file_size", relation) + relation = add_range_relation(q[:date], "posts.created_at::date", relation) + relation = add_range_relation(q[:general_tag_count], "posts.tag_count_general", relation) + relation = add_range_relation(q[:artist_tag_count], "posts.tag_count_artist", relation) + relation = add_range_relation(q[:copyright_tag_count], "posts.tag_count_copyright", relation) + relation = add_range_relation(q[:character_tag_count], "posts.tag_count_character", relation) + relation = add_range_relation(q[:tag_count], "posts.tag_count", relation) + + if options[:before_id] + relation = relation.where(["posts.id < ?", options[:before_id]]) + end + + if q[:md5].any? + relation = relation.where(["posts.md5 IN (?)", q[:md5]]) + end + + if q[:status] == "deleted" + relation = relation.where("posts.is_deleted = TRUE") + elsif q[:status] == "pending" + relation = relation.where("posts.is_pending = TRUE") + elsif q[:status] == "flagged" + relation = relation.where("posts.is_flagged = TRUE") + else + relation = relation.where("posts.is_deleted = FALSE") + end + + if q[:source].is_a?(String) + relation = relation.where(["posts.source LIKE ? ESCAPE E'\\\\'", q[:source]]) + end + + if q[:subscriptions].any? + relation = add_tag_subscription_relation(q[:subscriptions], relation) + end + + relation = add_tag_string_search_relation(q[:tags], relation) + + if q[:rating] == "q" + relation = relation.where("posts.rating = 'q'") + elsif q[:rating] == "s" + relation = relation.where("posts.rating = 's'") + elsif q[:rating] == "e" + relation = relation.where("posts.rating = 'e'") + end + + if q[:rating_negated] == "q" + relation = relation.where("posts.rating <> 'q'") + elsif q[:rating_negated] == "s" + relation = relation.where("posts.rating <> 's'") + elsif q[:rating_negated] == "e" + relation = relation.where("posts.rating <> 'e'") + end + + case q[:order] + when "id", "id_asc" + relation = relation.order("posts.id") + + when "id_desc" + relation = relation.order("posts.id DESC") + + when "score", "score_desc" + relation = relation.order("posts.score DESC, posts.id DESC") + + when "score_asc" + relation = relation.order("posts.score, posts.id DESC") + + when "mpixels", "mpixels_desc" + # Use "w*h/1000000", even though "w*h" would give the same result, so this can use + # the posts_mpixels index. + relation = relation.order("posts.image_width * posts.image_height / 1000000.0 DESC, posts.id DESC") + + when "mpixels_asc" + relation = relation.order("posts.image_width * posts.image_height / 1000000.0, posts.id DESC") + + when "portrait" + relation = relation.order("1.0 * image_width / GREATEST(1, image_height), posts.id DESC") + + when "landscape" + relation = relation.order("1.0 * image_width / GREATEST(1, image_height) DESC, posts.id DESC") + + when "filesize", "filesize_desc" + relation = relation.order("posts.file_size DESC") + + when "filesize_asc" + relation = relation.order("posts.file_size") + + else + relation = relation.order("posts.id DESC") + end + + if options[:limit] + relation = relation.limit(options[:limit]) + end + + if options[:offset] + relation = relation.offset(options[:offset]) + end + + relation end end @@ -405,7 +433,7 @@ class Post < ActiveRecord::Base end def uploader_name - uploader_string[5..-1] + uploader_string[9..-1] end def uploader @@ -413,7 +441,7 @@ class Post < ActiveRecord::Base end def uploader=(user) - self.uploader_string = "user:#{usern.name}" + self.uploader_string = "uploader:#{user.name}" end end @@ -438,4 +466,10 @@ class Post < ActiveRecord::Base include FavoriteMethods include UploaderMethods include PoolMethods + extend SearchMethods + + def reload(options = nil) + super + reset_tag_array_cache + end end diff --git a/app/models/tag.rb b/app/models/tag.rb index 348a1de1d..a4d6ffc04 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -196,7 +196,7 @@ class Tag < ActiveRecord::Base output[:include] += matches else - output[:related] << token + output[:related] << tag end end diff --git a/app/models/tag_alias.rb b/app/models/tag_alias.rb index 8a9765f4d..cc9cc6c36 100644 --- a/app/models/tag_alias.rb +++ b/app/models/tag_alias.rb @@ -10,6 +10,8 @@ class TagAlias < ActiveRecord::Base name end end + + alias_hash.values end def update_posts diff --git a/app/models/tag_implication.rb b/app/models/tag_implication.rb index 18cd53964..8e447b727 100644 --- a/app/models/tag_implication.rb +++ b/app/models/tag_implication.rb @@ -1,6 +1,17 @@ class TagImplication < ActiveRecord::Base - def after_save :update_descendant_names - + after_save :update_descendant_names + + def self.with_descendants(names) + names.map do |name| + ti = TagImplication.find_by_antecedent_name(name) + if ti + [name, ti.descendant_name_array] + else + name + end + end.flatten + end + def descendants all = [] children = [consequent_name] @@ -11,6 +22,10 @@ class TagImplication < ActiveRecord::Base end end + def descendant_name_array + descendant_names.split(/ /) + end + def update_desecendant_names self.descendant_names = descendants.join(" ") end diff --git a/db/development_structure.sql b/db/development_structure.sql index 1a9973778..f0fcacddd 100644 --- a/db/development_structure.sql +++ b/db/development_structure.sql @@ -74,6 +74,306 @@ SET default_tablespace = ''; SET default_with_oids = false; +-- +-- Name: favorites_0; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_0 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_0_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_0_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_0_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_0_id_seq OWNED BY favorites_0.id; + + +-- +-- Name: favorites_1; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_1 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_1_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_1_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_1_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_1_id_seq OWNED BY favorites_1.id; + + +-- +-- Name: favorites_2; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_2 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_2_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_2_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_2_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_2_id_seq OWNED BY favorites_2.id; + + +-- +-- Name: favorites_3; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_3 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_3_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_3_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_3_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_3_id_seq OWNED BY favorites_3.id; + + +-- +-- Name: favorites_4; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_4 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_4_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_4_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_4_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_4_id_seq OWNED BY favorites_4.id; + + +-- +-- Name: favorites_5; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_5 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_5_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_5_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_5_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_5_id_seq OWNED BY favorites_5.id; + + +-- +-- Name: favorites_6; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_6 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_6_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_6_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_6_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_6_id_seq OWNED BY favorites_6.id; + + +-- +-- Name: favorites_7; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_7 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_7_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_7_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_7_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_7_id_seq OWNED BY favorites_7.id; + + +-- +-- Name: favorites_8; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_8 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_8_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_8_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_8_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_8_id_seq OWNED BY favorites_8.id; + + +-- +-- Name: favorites_9; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE favorites_9 ( + id integer NOT NULL, + post_id integer, + user_id integer +); + + +-- +-- Name: favorites_9_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE favorites_9_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: favorites_9_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE favorites_9_id_seq OWNED BY favorites_9.id; + + -- -- Name: pending_posts; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -286,6 +586,75 @@ CREATE TABLE schema_migrations ( ); +-- +-- Name: tag_aliases; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE tag_aliases ( + id integer NOT NULL, + antecedent_name character varying(255) NOT NULL, + consequent_name character varying(255) NOT NULL, + creator_id integer NOT NULL, + request_ids character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: tag_aliases_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE tag_aliases_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: tag_aliases_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE tag_aliases_id_seq OWNED BY tag_aliases.id; + + +-- +-- Name: tag_implications; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE tag_implications ( + id integer NOT NULL, + antecedent_name character varying(255) NOT NULL, + consequent_name character varying(255) NOT NULL, + descendant_names text NOT NULL, + creator_id integer NOT NULL, + request_ids character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: tag_implications_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE tag_implications_id_seq + START WITH 1 + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- Name: tag_implications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE tag_implications_id_seq OWNED BY tag_implications.id; + + -- -- Name: tags; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -404,6 +773,76 @@ CREATE SEQUENCE users_id_seq ALTER SEQUENCE users_id_seq OWNED BY users.id; +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_0 ALTER COLUMN id SET DEFAULT nextval('favorites_0_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_1 ALTER COLUMN id SET DEFAULT nextval('favorites_1_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_2 ALTER COLUMN id SET DEFAULT nextval('favorites_2_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_3 ALTER COLUMN id SET DEFAULT nextval('favorites_3_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_4 ALTER COLUMN id SET DEFAULT nextval('favorites_4_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_5 ALTER COLUMN id SET DEFAULT nextval('favorites_5_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_6 ALTER COLUMN id SET DEFAULT nextval('favorites_6_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_7 ALTER COLUMN id SET DEFAULT nextval('favorites_7_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_8 ALTER COLUMN id SET DEFAULT nextval('favorites_8_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE favorites_9 ALTER COLUMN id SET DEFAULT nextval('favorites_9_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -439,6 +878,20 @@ ALTER TABLE post_versions ALTER COLUMN id SET DEFAULT nextval('post_versions_id_ ALTER TABLE posts ALTER COLUMN id SET DEFAULT nextval('posts_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE tag_aliases ALTER COLUMN id SET DEFAULT nextval('tag_aliases_id_seq'::regclass); + + +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE tag_implications ALTER COLUMN id SET DEFAULT nextval('tag_implications_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -460,6 +913,86 @@ ALTER TABLE unapprovals ALTER COLUMN id SET DEFAULT nextval('unapprovals_id_seq' ALTER TABLE users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass); +-- +-- Name: favorites_0_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_0 + ADD CONSTRAINT favorites_0_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_1_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_1 + ADD CONSTRAINT favorites_1_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_2_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_2 + ADD CONSTRAINT favorites_2_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_3_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_3 + ADD CONSTRAINT favorites_3_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_4_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_4 + ADD CONSTRAINT favorites_4_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_5_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_5 + ADD CONSTRAINT favorites_5_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_6_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_6 + ADD CONSTRAINT favorites_6_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_7_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_7 + ADD CONSTRAINT favorites_7_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_8_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_8 + ADD CONSTRAINT favorites_8_pkey PRIMARY KEY (id); + + +-- +-- Name: favorites_9_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY favorites_9 + ADD CONSTRAINT favorites_9_pkey PRIMARY KEY (id); + + -- -- Name: pending_posts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -500,6 +1033,22 @@ ALTER TABLE ONLY posts ADD CONSTRAINT posts_pkey PRIMARY KEY (id); +-- +-- Name: tag_aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY tag_aliases + ADD CONSTRAINT tag_aliases_pkey PRIMARY KEY (id); + + +-- +-- Name: tag_implications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY tag_implications + ADD CONSTRAINT tag_implications_pkey PRIMARY KEY (id); + + -- -- Name: tags_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -524,6 +1073,146 @@ ALTER TABLE ONLY users ADD CONSTRAINT users_pkey PRIMARY KEY (id); +-- +-- Name: index_favorites_0_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_0_on_post_id ON favorites_0 USING btree (post_id); + + +-- +-- Name: index_favorites_0_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_0_on_user_id ON favorites_0 USING btree (user_id); + + +-- +-- Name: index_favorites_1_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_1_on_post_id ON favorites_1 USING btree (post_id); + + +-- +-- Name: index_favorites_1_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_1_on_user_id ON favorites_1 USING btree (user_id); + + +-- +-- Name: index_favorites_2_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_2_on_post_id ON favorites_2 USING btree (post_id); + + +-- +-- Name: index_favorites_2_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_2_on_user_id ON favorites_2 USING btree (user_id); + + +-- +-- Name: index_favorites_3_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_3_on_post_id ON favorites_3 USING btree (post_id); + + +-- +-- Name: index_favorites_3_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_3_on_user_id ON favorites_3 USING btree (user_id); + + +-- +-- Name: index_favorites_4_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_4_on_post_id ON favorites_4 USING btree (post_id); + + +-- +-- Name: index_favorites_4_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_4_on_user_id ON favorites_4 USING btree (user_id); + + +-- +-- Name: index_favorites_5_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_5_on_post_id ON favorites_5 USING btree (post_id); + + +-- +-- Name: index_favorites_5_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_5_on_user_id ON favorites_5 USING btree (user_id); + + +-- +-- Name: index_favorites_6_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_6_on_post_id ON favorites_6 USING btree (post_id); + + +-- +-- Name: index_favorites_6_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_6_on_user_id ON favorites_6 USING btree (user_id); + + +-- +-- Name: index_favorites_7_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_7_on_post_id ON favorites_7 USING btree (post_id); + + +-- +-- Name: index_favorites_7_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_7_on_user_id ON favorites_7 USING btree (user_id); + + +-- +-- Name: index_favorites_8_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_8_on_post_id ON favorites_8 USING btree (post_id); + + +-- +-- Name: index_favorites_8_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_8_on_user_id ON favorites_8 USING btree (user_id); + + +-- +-- Name: index_favorites_9_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_9_on_post_id ON favorites_9 USING btree (post_id); + + +-- +-- Name: index_favorites_9_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_favorites_9_on_user_id ON favorites_9 USING btree (user_id); + + -- -- Name: index_pool_versions_on_pool_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -636,6 +1325,20 @@ CREATE INDEX index_posts_on_tags_index ON posts USING gin (tag_index); CREATE INDEX index_posts_on_view_count ON posts USING btree (view_count); +-- +-- Name: index_tag_aliases_on_antecedent_name; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_tag_aliases_on_antecedent_name ON tag_aliases USING btree (antecedent_name); + + +-- +-- Name: index_tag_implications_on_antecedent_name; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_tag_implications_on_antecedent_name ON tag_implications USING btree (antecedent_name); + + -- -- Name: index_tags_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -697,4 +1400,10 @@ INSERT INTO schema_migrations (version) VALUES ('20100205224030'); INSERT INTO schema_migrations (version) VALUES ('20100209201251'); -INSERT INTO schema_migrations (version) VALUES ('20100211025616'); \ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('20100211025616'); + +INSERT INTO schema_migrations (version) VALUES ('20100211181944'); + +INSERT INTO schema_migrations (version) VALUES ('20100211191709'); + +INSERT INTO schema_migrations (version) VALUES ('20100211191716'); \ No newline at end of file diff --git a/test/factories/pool.rb b/test/factories/pool.rb new file mode 100644 index 000000000..1bc64ac79 --- /dev/null +++ b/test/factories/pool.rb @@ -0,0 +1,5 @@ +Factory.define(:pool) do |f| + f.name {Faker::Name.first_name} + f.creator {|x| x.association(:user)} + f.description {Faker::Lorem.sentences} +end diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb index b546af2da..28e20c213 100644 --- a/test/unit/post_test.rb +++ b/test/unit/post_test.rb @@ -1,166 +1,364 @@ require File.dirname(__FILE__) + '/../test_helper' class PostTest < ActiveSupport::TestCase - context "During moderation a post" do - setup do - @post = Factory.create(:post) - @user = Factory.create(:user) - end - - should "be unapproved once and only once" do - @post.unapprove!("bad", @user, "127.0.0.1") - assert(@post.is_flagged?, "Post should be flagged.") - assert_not_nil(@post.unapproval, "Post should have an unapproval record.") - assert_equal("bad", @post.unapproval.reason) - - assert_raise(Unapproval::Error) {@post.unapprove!("bad", @user, "127.0.0.1")} - end - - should "not unapprove if no reason is given" do - assert_raise(Unapproval::Error) {@post.unapprove!("", @user, "127.0.0.1")} - end - - should "be deleted" do - @post.delete! - assert(@post.is_deleted?, "Post should be deleted.") - end - - should "be approved" do - @post.approve! - assert(!@post.is_pending?, "Post should not be pending.") - - @deleted_post = Factory.create(:post, :is_deleted => true) - @deleted_post.approve! - assert(!@post.is_deleted?, "Post should not be deleted.") - end - end - - context "A post version" do - should "be created on any save" do - @user = Factory.create(:user) - @post = Factory.create(:post) - assert_equal(1, @post.versions.size) - - @post.update_attributes(:rating => "e", :updater_id => @user.id, :updater_ip_addr => "125.0.0.0") - assert_equal(2, @post.versions.size) - assert_equal(@user.id, @post.versions.last.updater_id) - assert_equal("125.0.0.0", @post.versions.last.updater_ip_addr) - end - end - - context "A post's tags" do - setup do - @post = Factory.create(:post) - end - - should "have an array representation" do - assert_equal(%w(tag1 tag2), @post.tag_array) - end - - should "be counted" do - @user = Factory.create(:user) - @artist_tag = Factory.create(:artist_tag) - @copyright_tag = Factory.create(:copyright_tag) - @general_tag = Factory.create(:tag) - @new_post = Factory.create(:post, :tag_string => "#{@artist_tag.name} #{@copyright_tag.name} #{@general_tag.name}") - assert_equal(1, @new_post.tag_count_artist) - assert_equal(1, @new_post.tag_count_copyright) - assert_equal(1, @new_post.tag_count_general) - assert_equal(0, @new_post.tag_count_character) - assert_equal(3, @new_post.tag_count) + # context "During moderation a post" do + # setup do + # @post = Factory.create(:post) + # @user = Factory.create(:user) + # end + # + # should "be unapproved once and only once" do + # @post.unapprove!("bad", @user, "127.0.0.1") + # assert(@post.is_flagged?, "Post should be flagged.") + # assert_not_nil(@post.unapproval, "Post should have an unapproval record.") + # assert_equal("bad", @post.unapproval.reason) + # + # assert_raise(Unapproval::Error) {@post.unapprove!("bad", @user, "127.0.0.1")} + # end + # + # should "not unapprove if no reason is given" do + # assert_raise(Unapproval::Error) {@post.unapprove!("", @user, "127.0.0.1")} + # end + # + # should "be deleted" do + # @post.delete! + # assert(@post.is_deleted?, "Post should be deleted.") + # end + # + # should "be approved" do + # @post.approve! + # assert(!@post.is_pending?, "Post should not be pending.") + # + # @deleted_post = Factory.create(:post, :is_deleted => true) + # @deleted_post.approve! + # assert(!@post.is_deleted?, "Post should not be deleted.") + # end + # end + # + # context "A post version" do + # should "be created on any save" do + # @user = Factory.create(:user) + # @post = Factory.create(:post) + # assert_equal(1, @post.versions.size) + # + # @post.update_attributes(:rating => "e", :updater_id => @user.id, :updater_ip_addr => "125.0.0.0") + # assert_equal(2, @post.versions.size) + # assert_equal(@user.id, @post.versions.last.updater_id) + # assert_equal("125.0.0.0", @post.versions.last.updater_ip_addr) + # end + # end + # + # context "A post's tags" do + # setup do + # @post = Factory.create(:post) + # end + # + # should "have an array representation" do + # @post.set_tag_string("aaa bbb") + # assert_equal(%w(aaa bbb), @post.tag_array) + # assert_equal(%w(tag1 tag2), @post.tag_array_was) + # end - @new_post.update_attributes(:tag_string => "babs", :updater_id => @user.id, :updater_ip_addr => "127.0.0.1") - assert_equal(0, @new_post.tag_count_artist) - assert_equal(0, @new_post.tag_count_copyright) - assert_equal(1, @new_post.tag_count_general) - assert_equal(0, @new_post.tag_count_character) - assert_equal(1, @new_post.tag_count) + should "reset the tag array cache when updated" do + post = Factory.create(:post, :tag_string => "aaa bbb ccc") + user = Factory.create(:user) + assert_equal(%w(aaa bbb ccc), post.tag_array) + post.tag_string = "ddd eee fff" + post.update_attributes( + :updater_id => user.id, + :updater_ip_addr => "127.0.0.1", + :tag_string => "ddd eee fff" + ) + assert_equal("ddd eee fff", post.tag_string) + assert_equal(%w(ddd eee fff), post.tag_array) + end + + should "create the actual tag records" do + assert_difference("Tag.count", 3) do + post = Factory.create(:post, :tag_string => "aaa bbb ccc") end - - should "be merged with any changes that were made after loading the initial set of tags part 1" do - @user = Factory.create(:user) - @post = Factory.create(:post, :tag_string => "aaa bbb ccc") - - # user a adds - @post_edited_by_user_a = Post.find(@post.id) - @post_edited_by_user_a.update_attributes( - :updater_id => @user.id, - :updater_ip_addr => "127.0.0.1", - :old_tag_string => "aaa bbb ccc", - :tag_string => "aaa bbb ccc ddd" - ) - - # user b removes adds - @post_edited_by_user_b = Post.find(@post.id) - @post_edited_by_user_b.update_attributes( - :updater_id => @user.id, - :updater_ip_addr => "127.0.0.1", - :old_tag_string => "aaa bbb ccc", - :tag_string => "aaa bbb eee" - ) - - # final should be , , , - @final_post = Post.find(@post.id) - assert_equal(%w(aaa bbb ddd eee), Tag.scan_tags(@final_post.tag_string).sort) + end + + should "update the post counts of relevant tag records" do + post1 = Factory.create(:post, :tag_string => "aaa bbb ccc") + post2 = Factory.create(:post, :tag_string => "bbb ccc ddd") + post3 = Factory.create(:post, :tag_string => "ccc ddd eee") + assert_equal(1, Tag.find_by_name("aaa").post_count) + assert_equal(2, Tag.find_by_name("bbb").post_count) + assert_equal(3, Tag.find_by_name("ccc").post_count) + end + + # should "be counted" do + # @user = Factory.create(:user) + # @artist_tag = Factory.create(:artist_tag) + # @copyright_tag = Factory.create(:copyright_tag) + # @general_tag = Factory.create(:tag) + # @new_post = Factory.create(:post, :tag_string => "#{@artist_tag.name} #{@copyright_tag.name} #{@general_tag.name}") + # assert_equal(1, @new_post.tag_count_artist) + # assert_equal(1, @new_post.tag_count_copyright) + # assert_equal(1, @new_post.tag_count_general) + # assert_equal(0, @new_post.tag_count_character) + # assert_equal(3, @new_post.tag_count) + # + # @new_post.update_attributes(:tag_string => "babs", :updater_id => @user.id, :updater_ip_addr => "127.0.0.1") + # assert_equal(0, @new_post.tag_count_artist) + # assert_equal(0, @new_post.tag_count_copyright) + # assert_equal(1, @new_post.tag_count_general) + # assert_equal(0, @new_post.tag_count_character) + # assert_equal(1, @new_post.tag_count) + # end + # + # should "be merged with any changes that were made after loading the initial set of tags part 1" do + # @user = Factory.create(:user) + # @post = Factory.create(:post, :tag_string => "aaa bbb ccc") + # + # # user a adds + # @post_edited_by_user_a = Post.find(@post.id) + # @post_edited_by_user_a.update_attributes( + # :updater_id => @user.id, + # :updater_ip_addr => "127.0.0.1", + # :old_tag_string => "aaa bbb ccc", + # :tag_string => "aaa bbb ccc ddd" + # ) + # + # # user b removes adds + # @post_edited_by_user_b = Post.find(@post.id) + # @post_edited_by_user_b.update_attributes( + # :updater_id => @user.id, + # :updater_ip_addr => "127.0.0.1", + # :old_tag_string => "aaa bbb ccc", + # :tag_string => "aaa bbb eee" + # ) + # + # # final should be , , , + # @final_post = Post.find(@post.id) + # assert_equal(%w(aaa bbb ddd eee), Tag.scan_tags(@final_post.tag_string).sort) + # end + # + # should "be merged with any changes that were made after loading the initial set of tags part 2" do + # # This is the same as part 1, only the order of operations is reversed. + # # The results should be the same. + # + # @user = Factory.create(:user) + # @post = Factory.create(:post, :tag_string => "aaa bbb ccc") + # + # # user a removes adds + # @post_edited_by_user_a = Post.find(@post.id) + # @post_edited_by_user_a.update_attributes( + # :updater_id => @user.id, + # :updater_ip_addr => "127.0.0.1", + # :old_tag_string => "aaa bbb ccc", + # :tag_string => "aaa bbb eee" + # ) + # + # # user b adds + # @post_edited_by_user_b = Post.find(@post.id) + # @post_edited_by_user_b.update_attributes( + # :updater_id => @user.id, + # :updater_ip_addr => "127.0.0.1", + # :old_tag_string => "aaa bbb ccc", + # :tag_string => "aaa bbb ccc ddd" + # ) + # + # # final should be , , , + # @final_post = Post.find(@post.id) + # assert_equal(%w(aaa bbb ddd eee), Tag.scan_tags(@final_post.tag_string).sort) + # end + # end + # + # context "Adding a meta-tag" do + # setup do + # @post = Factory.create(:post) + # end + # + # should "be ignored" do + # @user = Factory.create(:user) + # + # @post.update_attributes( + # :updater_id => @user.id, + # :updater_ip_addr => "127.0.0.1", + # :tag_string => "aaa pool:1234 pool:test rating:s fav:bob" + # ) + # assert_equal("aaa", @post.tag_string) + # end + # end + # + # context "Favoriting a post" do + # should "update the favorite string" do + # @user = Factory.create(:user) + # @post = Factory.create(:post) + # @post.add_favorite(@user) + # assert_equal("fav:#{@user.name}", @post.fav_string) + # + # @post.remove_favorite(@user) + # assert_equal("", @post.fav_string) + # end + # end + + context "A tag search" do + should "return posts for 1 tag" do + post1 = Factory.create(:post, :tag_string => "aaa") + post2 = Factory.create(:post, :tag_string => "aaa bbb") + post3 = Factory.create(:post, :tag_string => "bbb ccc") + relation = Post.find_by_tags("aaa") + assert_equal(2, relation.count) + assert_equal(post2.id, relation.all[0].id) + assert_equal(post1.id, relation.all[1].id) end - should "be merged with any changes that were made after loading the initial set of tags part 2" do - # This is the same as part 1, only the order of operations is reversed. - # The results should be the same. - - @user = Factory.create(:user) - @post = Factory.create(:post, :tag_string => "aaa bbb ccc") - - # user a removes adds - @post_edited_by_user_a = Post.find(@post.id) - @post_edited_by_user_a.update_attributes( - :updater_id => @user.id, - :updater_ip_addr => "127.0.0.1", - :old_tag_string => "aaa bbb ccc", - :tag_string => "aaa bbb eee" - ) - - # user b adds - @post_edited_by_user_b = Post.find(@post.id) - @post_edited_by_user_b.update_attributes( - :updater_id => @user.id, - :updater_ip_addr => "127.0.0.1", - :old_tag_string => "aaa bbb ccc", - :tag_string => "aaa bbb ccc ddd" - ) - - # final should be , , , - @final_post = Post.find(@post.id) - assert_equal(%w(aaa bbb ddd eee), Tag.scan_tags(@final_post.tag_string).sort) + should "return posts for a 2 tag join" do + post1 = Factory.create(:post, :tag_string => "aaa") + post2 = Factory.create(:post, :tag_string => "aaa bbb") + post3 = Factory.create(:post, :tag_string => "bbb ccc") + relation = Post.find_by_tags("aaa bbb") + assert_equal(1, relation.count) + assert_equal(post2.id, relation.first.id) end - end - - context "Adding a meta-tag" do - setup do - @post = Factory.create(:post) + + should "return posts for 1 tag with exclusion" do + post1 = Factory.create(:post, :tag_string => "aaa") + post2 = Factory.create(:post, :tag_string => "aaa bbb") + post3 = Factory.create(:post, :tag_string => "bbb ccc") + relation = Post.find_by_tags("aaa -bbb") + assert_equal(1, relation.count) + assert_equal(post1.id, relation.first.id) end - - should "be ignored" do - @user = Factory.create(:user) - - @post.update_attributes( - :updater_id => @user.id, - :updater_ip_addr => "127.0.0.1", - :tag_string => "aaa pool:1234 pool:test rating:s fav:bob" - ) - assert_equal("aaa", @post.tag_string) + + should "return posts for 1 tag with a pattern" do + post1 = Factory.create(:post, :tag_string => "aaa") + post2 = Factory.create(:post, :tag_string => "aaab bbb") + post3 = Factory.create(:post, :tag_string => "bbb ccc") + relation = Post.find_by_tags("a*") + assert_equal(2, relation.count) + assert_equal(post2.id, relation.all[0].id) + assert_equal(post1.id, relation.all[1].id) end - end - - context "Favoriting a post" do - should "update the favorite string" do - @user = Factory.create(:user) - @post = Factory.create(:post) - @post.add_favorite(@user.id) - assert_equal("fav:#{@user.id}", @post.fav_string) - - @post.remove_favorite(@user.id) - assert_equal("", @post.fav_string) + + should "return posts for 2 tags, one with a pattern" do + post1 = Factory.create(:post, :tag_string => "aaa") + post2 = Factory.create(:post, :tag_string => "aaab bbb") + post3 = Factory.create(:post, :tag_string => "bbb ccc") + relation = Post.find_by_tags("a* bbb") + assert_equal(1, relation.count) + assert_equal(post2.id, relation.first.id) + end + + should "return posts for the metatag" do + post1 = Factory.create(:post) + post2 = Factory.create(:post) + post3 = Factory.create(:post) + relation = Post.find_by_tags("id:#{post2.id}") + assert_equal(1, relation.count) + assert_equal(post2.id, relation.first.id) + relation = Post.find_by_tags("id:>#{post2.id}") + assert_equal(1, relation.count) + assert_equal(post3.id, relation.first.id) + relation = Post.find_by_tags("id:<#{post2.id}") + assert_equal(1, relation.count) + assert_equal(post1.id, relation.first.id) + end + + should "return posts for the metatag" do + post1 = Factory.create(:post) + post2 = Factory.create(:post) + post3 = Factory.create(:post) + user = Factory.create(:user) + post1.add_favorite(user) + post1.save + relation = Post.find_by_tags("fav:#{user.name}") + assert_equal(1, relation.count) + assert_equal(post1.id, relation.first.id) + end + + should "return posts for the metatag" do + post1 = Factory.create(:post) + post2 = Factory.create(:post) + post3 = Factory.create(:post) + pool = Factory.create(:pool) + post1.add_pool(pool) + post1.save + relation = Post.find_by_tags("pool:#{pool.name}") + assert_equal(1, relation.count) + assert_equal(post1.id, relation.first.id) + end + + should "return posts for the metatag" do + user = Factory.create(:user) + post1 = Factory.create(:post, :uploader => user) + post2 = Factory.create(:post) + post3 = Factory.create(:post) + assert_equal("uploader:#{user.name}", post1.uploader_string) + relation = Post.find_by_tags("uploader:#{user.name}") + assert_equal(1, relation.count) + assert_equal(post1.id, relation.first.id) + end + + should "return posts for a list of md5 hashes" do + post1 = Factory.create(:post, :md5 => "abcd") + post2 = Factory.create(:post) + post3 = Factory.create(:post) + relation = Post.find_by_tags("md5:abcd") + assert_equal(1, relation.count) + assert_equal(post1.id, relation.first.id) + end + + should "filter out deleted posts by default" do + post1 = Factory.create(:post, :is_deleted => true) + post2 = Factory.create(:post, :is_deleted => true) + post3 = Factory.create(:post, :is_deleted => false) + relation = Post.find_by_tags("") + assert_equal(1, relation.count) + assert_equal(post3.id, relation.first.id) + end + + should "return posts for a particular status" do + post1 = Factory.create(:post, :is_deleted => true) + post2 = Factory.create(:post, :is_deleted => false) + post3 = Factory.create(:post, :is_deleted => false) + relation = Post.find_by_tags("status:deleted") + assert_equal(1, relation.count) + assert_equal(post1.id, relation.first.id) + end + + should "return posts for a source search" do + post1 = Factory.create(:post, :source => "abcd") + post2 = Factory.create(:post, :source => "abcdefg") + post3 = Factory.create(:post, :source => "xyz") + relation = Post.find_by_tags("source:abcde") + assert_equal(1, relation.count) + assert_equal(post2.id, relation.first.id) + end + + should "return posts for a tag subscription search" + + should "return posts for a particular rating" do + post1 = Factory.create(:post, :rating => "s") + post2 = Factory.create(:post, :rating => "q") + post3 = Factory.create(:post, :rating => "e") + relation = Post.find_by_tags("rating:e") + assert_equal(1, relation.count) + assert_equal(post3.id, relation.first.id) + end + + should "return posts for a particular negated rating" do + post1 = Factory.create(:post, :rating => "s") + post2 = Factory.create(:post, :rating => "s") + post3 = Factory.create(:post, :rating => "e") + relation = Post.find_by_tags("-rating:s") + assert_equal(1, relation.count) + assert_equal(post3.id, relation.first.id) + end + + should "return posts ordered by a particular attribute" do + post1 = Factory.create(:post, :rating => "s") + post2 = Factory.create(:post, :rating => "s") + post3 = Factory.create(:post, :rating => "e", :score => 5, :image_width => 1000) + relation = Post.find_by_tags("order:id") + assert_equal(post1.id, relation.first.id) + relation = Post.find_by_tags("order:mpixels") + assert_equal(post3.id, relation.first.id) + relation = Post.find_by_tags("order:landscape") + assert_equal(post3.id, relation.first.id) end end end