rpfm_extensions/search/schema.rs
1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11/*!
12Module with all the code related to the `SchemaMatches`.
13
14This module contains the code needed to get schema matches from a `GlobalSearch`.
15!*/
16
17use getset::{Getters, MutGetters};
18use serde_derive::{Deserialize, Serialize};
19
20use rpfm_lib::schema::Schema;
21
22use super::{MatchingMode, Searchable};
23
24//-------------------------------------------------------------------------------//
25// Enums & Structs
26//-------------------------------------------------------------------------------//
27
28/// This struct represents all the matches of the global search within a Schema.
29#[derive(Debug, Default, Clone, Getters, MutGetters, Serialize, Deserialize)]
30#[getset(get = "pub", get_mut = "pub")]
31pub struct SchemaMatches {
32
33 /// The list of matches within the versioned file.
34 matches: Vec<SchemaMatch>,
35}
36
37/// This struct represents a match on a column name within a Schema.
38#[derive(Debug, Clone, Getters, MutGetters, Serialize, Deserialize)]
39#[getset(get = "pub", get_mut = "pub")]
40pub struct SchemaMatch {
41
42 // The type of versioned file we have.
43 table_name: String,
44
45 // Version of the definition with a match.
46 version: i32,
47
48 // Column of the match.
49 column: u32,
50
51 // Full name of the matched column.
52 column_name: String,
53}
54
55//-------------------------------------------------------------------------------//
56// Implementations
57//-------------------------------------------------------------------------------//
58
59impl Searchable for Schema {
60 type SearchMatches = SchemaMatches;
61
62 /// This function performs a search over the provided Text PackedFile.
63 fn search(&self, _file_path: &str, pattern_to_search: &str, case_sensitive: bool, matching_mode: &MatchingMode) -> SchemaMatches {
64 let mut matches = SchemaMatches::default();
65
66 for (table_name, definitions) in self.definitions() {
67 match matching_mode {
68 MatchingMode::Regex(regex) => {
69 for definition in definitions {
70 for (index, field) in definition.fields_processed().iter().enumerate() {
71 if regex.is_match(field.name()) {
72 matches.matches.push(SchemaMatch::new(
73 table_name,
74 *definition.version(),
75 index as u32,
76 field.name()
77 ));
78 }
79 }
80 }
81 }
82
83 // If we're searching a pattern, we just check every text PackedFile, line by line.
84 MatchingMode::Pattern(regex) => {
85 let pattern = if case_sensitive || regex.is_some() {
86 pattern_to_search.to_owned()
87 } else {
88 pattern_to_search.to_lowercase()
89 };
90
91 for definition in definitions {
92 for (index, field) in definition.fields_processed().iter().enumerate() {
93 if case_sensitive {
94 if field.name().contains(&pattern) {
95 matches.matches.push(SchemaMatch::new(
96 table_name,
97 *definition.version(),
98 index as u32,
99 field.name()
100 ));
101 }
102 }
103 else if let Some(regex) = regex {
104 if regex.is_match(field.name()) {
105 matches.matches.push(SchemaMatch::new(
106 table_name,
107 *definition.version(),
108 index as u32,
109 field.name()
110 ));
111 }
112 }
113
114 // Fallback, just in case the regex is invalid.
115 else {
116 let name = field.name().to_lowercase();
117 if name.contains(&pattern) {
118 matches.matches.push(SchemaMatch::new(
119 table_name,
120 *definition.version(),
121 index as u32,
122 field.name()
123 ));
124 }
125 }
126 }
127 }
128 }
129 }
130 }
131
132 matches
133 }
134}
135
136impl SchemaMatch {
137
138 /// This function creates a new `SchemaMatch` with the provided data.
139 pub fn new(table_name: &str, version: i32, column: u32, column_name: &str) -> Self {
140 Self {
141 table_name: table_name.to_owned(),
142 version,
143 column,
144 column_name: column_name.to_owned(),
145 }
146 }
147}