1use crate::db::schema::app_global::book_search_api::BookSearchApi;
2use crate::db::schema::binder_helper::{placeholder_helper, placeholder_in_clause, Binder};
3use crate::db::schema::MAX_BIND_COUNT;
4use crate::db::schema::{
5 BackgroundInfo, BackgroundReference, Bibliography, BibliographyAuthor, Draft, Headline, Item,
6 ItemReference, Paragraph, ParagraphLink, ParagraphSummary, Publisher, RelBackgroundAndItem,
7 RelBibliographyAuthor, RelTagAndItem, ReturningId, Setting, Tag, Task, TaskCategory,
8 TaskTemplate,
9};
10use sqlx::{Acquire, Error, SqliteConnection, SqliteExecutor, SqliteTransaction};
11
12fn first_or_row_not_found<T>(values: &Vec<T>) -> Result<T, Error>
13where
14 T: Clone,
15{
16 if values.is_empty() {
17 Err(Error::RowNotFound)
18 } else {
19 Ok(values[0].clone())
20 }
21}
22
23macro_rules! allow_r {
24 ($(($x: ty, $view_name:expr)),*) => {
25 $(impl $x {
26 #[doc=concat!(stringify!($view_name), "からすべてのレコードを取得します。")]
27 #[doc="# SQL"]
28 #[doc="以下のクエリが実行されます。"]
29 #[doc="```sql"]
30 #[doc=concat!("SELECT * FROM ", $view_name)]
31 #[doc="```"]
32 pub async fn select_all(conn: &mut SqliteConnection) -> Result<Vec<Self>, Error> {
33 sqlx::query_as(concat!("SELECT * FROM ", $view_name))
34 .fetch_all(conn).await
35 }
36
37 #[doc=concat!(stringify!($view_name), "から対応するidのレコードを取得します。")]
38 #[doc="# SQL"]
39 #[doc="以下のクエリが実行されます。"]
40 #[doc="```sql"]
41 #[doc=concat!("SELECT * FROM ", $view_name)]
42 #[doc="WHERE id=?"]
43 #[doc="```"]
44 pub async fn from_id(conn: &mut SqliteConnection, id: i64) -> Result<Option<Self>, Error> {
45 sqlx::query_as(concat!("SELECT * FROM ", $view_name, " WHERE id = ?"))
46 .bind(id)
47 .fetch_optional(conn)
48 .await
49 }
50 })*
51 };
52}
53
54macro_rules! allow_c {
55 ($(($x: ty, $table_name:expr, $view_name:expr, $register_columns:expr, $place_holder_count:expr)),*) => {
56 $(impl $x {
57 pub async fn register_optional(val: Option<Self>, conn: &mut SqliteConnection, is_on_conflict_do_nothing: bool) -> Result<Option<Self>, Error> {
59 Ok(match val {
60 Some(v) => Some(v.register(conn, is_on_conflict_do_nothing).await?),
61 None => None
62 })
63 }
64
65 pub async fn register(&self, conn: &mut SqliteConnection, is_on_conflict_do_nothing: bool) -> Result<Self, Error> {
67 first_or_row_not_found(&Self::register_many(&vec![self.clone()], conn, is_on_conflict_do_nothing).await?)
68 }
69
70 #[doc="複数レコードを一括で登録します。"]
71 #[doc=concat!("1クエリあたり、[`", stringify!(MAX_BIND_COUNT), "`]件の値が登録されます。")] #[doc="# SQL"]
73 #[doc="以下のクエリが実行されます。"]
74 #[doc="- ..はプレースホルダの省略です。"]
75 #[doc="- ON CONFLICT DO NOTHING はフラグが `true` の場合に有効化されます。"]
76 #[doc="```sql"]
77 #[doc=concat!("INSERT INTO ", $table_name, " (")]
78 #[doc=$register_columns]
79 #[doc=")"]
80 #[doc="VALUES (..) [ON CONFLICT DO NOTHING] RETURNING id"]
81 #[doc="```"]
82 pub async fn register_many(values: &[Self], conn: &mut SqliteConnection, is_on_conflict_do_nothing: bool) -> Result<Vec<Self>, Error> {
83 if values.is_empty() {
84 return Ok(vec![]);
85 }
86 let mut v = Vec::new();
87 for i in values.chunks(MAX_BIND_COUNT / $place_holder_count) {
88 let sql = format!(
89 concat!(
90 "INSERT INTO ",
91 $table_name,
92 "(",
93 $register_columns,
94 ") VALUES {} {} RETURNING id"
95 ),
96 placeholder_helper(format!("({})", placeholder_helper("?", $place_holder_count)), i.len()),
97 if is_on_conflict_do_nothing { "ON CONFLICT DO NOTHING" } else { "" }
98 );
99 let mut query = sqlx::query_as(sql.as_str());
100 for i in i {
101 query = Binder::register_bind_values(i.clone(), query)
102 }
103 let id_list: Vec<ReturningId> = query.fetch_all(&mut *conn).await?;
104 let sql = format!(
105 concat!("SELECT * FROM ", $view_name, " WHERE id IN ({})"),
106 placeholder_in_clause(id_list.as_ref())
107 );
108 let mut query = sqlx::query_as(sql.as_str());
109 for i in id_list {
110 query = query.bind(i.id);
111 }
112 v.extend(query.fetch_all(&mut *conn).await?);
113 }
114 Ok(v)
115 }
116 })*
117 };
118}
119macro_rules! allow_u {
120 ($(($x: ty, $table_name:expr, $update_set_clause:expr)),*) => {
121 $(impl $x {
122 #[doc=concat!("[`Self::id`]に対応するレコードの値を更新します。")]
123 #[doc="# Panics"]
124 #[doc=concat!("[`Self::id`]が`0`の場合、パニックを発生させます。")]
125 #[doc="# SQL"]
126 #[doc="以下のクエリが実行されます。"]
127 #[doc="```sql"]
128 #[doc=concat!("UPDATE ", $table_name)]
129 #[doc=concat!("SET ", $update_set_clause)]
130 #[doc="WHERE id=?"]
131 #[doc="```"]
132 #[tracing::instrument]
133 pub async fn update(&self, conn: &mut SqliteConnection) -> Result<(), Error> {
134 if self.id == 0 {
135 tracing::error!("Unexpected data is included!! Self: {:#?}", self);
136 panic!()
137 }
138 let mut query = sqlx::query(concat!(
139 "UPDATE ",
140 $table_name,
141 " SET ",
142 $update_set_clause,
143 " WHERE id=?"
144 ));
145 self
146 .clone()
147 .update_bind_values(query)
148 .bind(self.id)
149 .execute(conn)
150 .await?;
151 Ok(())
152 }
153 })*
154 };
155}
156macro_rules! allow_d {
157 ($(($x:ty, $table_name:expr)),*) => {
158 $(
159 impl $x {
160 #[doc=concat!("[`Self::id`]に対応するレコードを削除します。")]
161 #[doc="# Panics"]
162 #[doc=concat!("[`Self::id`]が`0`の場合、パニックを発生させます。")]
163 #[doc="# SQL"]
164 #[doc="以下のクエリが実行されます。"]
165 #[doc="```sql"]
166 #[doc=concat!("DELETE FROM ", $table_name)]
167 #[doc="WHERE id=?"]
168 #[doc="```"]
169 #[tracing::instrument]
170 pub async fn delete(self, conn: &mut SqliteConnection) -> Result<(), Error> {
171 if self.id == 0 {
172 tracing::error!("Unexpected data is included!! Self: {:#?}", self);
173 panic!()
174 }
175 sqlx::query(concat!("DELETE FROM ", $table_name, " WHERE id=?"))
176 .bind(self.id)
177 .execute(conn)
178 .await?;
179 Ok(())
180 }
181 }
182 )*
183 };
184}
185macro_rules! allow_crud {
186 ($(($x: ty, $table_name:expr, $view_name:expr, $register_columns:expr, $place_holder:expr, $update_set_clause:expr)),*) => {
187 $(
188 allow_c!(($x, $table_name, $view_name, $register_columns, $place_holder));
189 allow_r!(($x, $view_name));
190 allow_u!(($x, $table_name, $update_set_clause));
191 allow_d!(($x, $table_name));
192 )*
193 };
194}
195macro_rules! allow_cru {
196 ($(($x: ty, $table_name:expr, $view_name:expr, $register_columns:expr, $place_holder:expr, $update_set_clause:expr)),*) => {
197 $(
198 allow_c!(($x, $table_name, $view_name, $register_columns, $place_holder));
199 allow_r!(($x, $view_name));
200 allow_u!(($x, $table_name, $update_set_clause));
201 )*
202 };
203}
204macro_rules! allow_crd {
205 ($(($x: ty, $table_name:expr, $view_name:expr, $register_columns:expr, $place_holder:expr)),*) => {
206 $(
207 allow_c!(($x, $table_name, $view_name, $register_columns, $place_holder));
208 allow_r!(($x, $view_name));
209 allow_d!(($x, $table_name));
210 )*
211 };
212}
213
214allow_cru!(
215 (
216 Paragraph,
217 "paragraph",
218 "view_deserializable_paragraph",
219 "item_id,headline_id,paragraph_pos,accepted_draft_id",
220 4,
221 "headline_id=?,paragraph_pos=?,accepted_draft_id=?"
222 ),
223 (
224 Headline,
225 "headlines",
226 "headlines",
227 "item_id,parent_id,headline_pos",
228 3,
229 "parent_id=?,headline_pos=?"
230 )
231);
232
233allow_crud!(
234 (
235 BackgroundInfo,
236 "background_info",
237 "background_info",
238 "body",
239 1,
240 "body=?"
241 ),
242 (Tag, "tags", "tags", "name,memo", 2, "name=?,memo=?"),
243 (
244 Publisher,
245 "publishers",
246 "publishers",
247 "name,memo",
248 2,
249 "name=?,memo=?"
250 ),
251 (
252 Bibliography,
253 "bibliographies",
254 "view_deserializable_bibliographies",
255 "isbn,url,title,detail,publisher_id,publication_date,tmp_registration_id",
256 7,
257 "isbn=?,url=?,title=?,detail=?,publisher_id=?,publication_date=?"
258 ),
259 (
260 BibliographyAuthor,
261 "bibliography_authors",
262 "bibliography_authors",
263 "name,memo",
264 2,
265 "name=?,memo=?"
266 ),
267 (
268 Item,
269 "items",
270 "view_deserializable_item",
271 "item_type,title",
272 2,
273 "title=?"
274 ),
275 (
276 Draft,
277 "draft",
278 "draft",
279 "paragraph_id,draft_pos,title,body",
280 4,
281 "paragraph_id=?,draft_pos=?,title=?,body=?"
282 ),
283 (
284 ParagraphSummary,
285 "paragraph_summaries",
286 "paragraph_summaries",
287 "paragraph_id,title,detail",
288 3,
289 "paragraph_id=?,title=?,detail=?"
290 ),
291 (
292 BackgroundReference,
293 "background_references",
294 "view_deserializable_background_reference",
295 "background_info_id,bibliography_id,location",
296 3,
297 "background_info_id=?,bibliography_id=?,location=?"
298 ),
299 (
300 ItemReference,
301 "item_references",
302 "view_deserializable_item_reference",
303 "item_id,bibliography_id,location",
304 3,
305 "item_id=?,bibliography_id=?,location=?"
306 ),
307 (
308 TaskCategory,
309 "task_categories",
310 "task_categories",
311 "name,autocomplete_paragraph_link",
312 2,
313 "name=?,autocomplete_paragraph_link=?"
314 ),
315 (
316 TaskTemplate,
317 "task_templates",
318 "view_deserializable_task_template",
319 "task_category_id,title,detail",
320 3,
321 "task_category_id=?,title=?,detail=?"
322 ),
323 (
324 Task,
325 "tasks",
326 "view_deserializable_task",
327 "item_id,task_category_id,title,detail,is_finished",
328 5,
329 "item_id=?,task_category_id=?,title=?,detail=?,is_finished=?"
330 ),
331 (
332 ParagraphLink,
333 "paragraph_link",
334 "view_deserializable_paragraph_link",
335 "from_paragraph_id,to_paragraph_id,task_id,comment",
336 4,
337 "from_paragraph_id=?,to_paragraph_id=?,task_id=?,comment=?"
338 ),
339 (
340 Setting,
341 "settings",
342 "settings",
343 "setting_key,setting_value",
344 2,
345 "setting_value=?"
346 ),
347 (
348 RelBibliographyAuthor,
349 "rel_bibliography_authors",
350 "rel_bibliography_authors",
351 "bibliography_id,bibliography_author_id",
352 2,
353 "bibliography_id=?,bibliography_author_id=?"
354 ),
355 (
356 RelTagAndItem,
357 "rel_tag_and_item",
358 "rel_tag_and_item",
359 "item_id,tag_id",
360 2,
361 "item_id=?,tag_id=?"
362 ),
363 (
364 RelBackgroundAndItem,
365 "rel_background_and_item",
366 "rel_background_and_item",
367 "item_id,background_info_id",
368 2,
369 "item_id=?,background_info_id=?"
370 )
371);
372
373allow_crud!((
374 BookSearchApi,
375 "book_search_api",
376 "book_search_api",
377 "name,detail,isbn_url,text_url,mapping_script",
378 5,
379 "name=?,detail=?,isbn_url=?,text_url=?,mapping_script=?"
380));