1use crate::types::{DbMode, Mode, Params, TableOptions};
2use crate::Connection;
3use crate::{pools};
4use json::{array, object, JsonValue};
5use lazy_static::lazy_static;
6use log::{error, info};
7use sqlite::{Connection as Connect, ConnectionThreadSafe, OpenFlags, State, Statement, Type};
8use std::collections::HashMap;
9use std::sync::{Arc, Mutex};
10use std::thread;
11use chrono::Local;
12
13lazy_static! {
14 static ref DBS: Mutex<HashMap<String, Arc<ConnectionThreadSafe>>> = Mutex::new(HashMap::new());
15 static ref TR: Mutex<HashMap<String, Arc<ConnectionThreadSafe>>> = Mutex::new(HashMap::new());
16 static ref TR_COUNT: Mutex<HashMap<String, u32>> = Mutex::new(HashMap::new());
17 static ref SQL_LIST: Mutex<Vec<String>> = Mutex::new(Vec::new());
18 static ref FIELDS: Mutex<HashMap<String,JsonValue>> = Mutex::new(HashMap::new());
19}
20
21#[derive(Clone, Debug)]
22pub struct Sqlite {
23 pub connection: Connection,
25 pub default: String,
27
28 pub params: Params,
29}
30
31impl Sqlite {
32 pub fn connect(connection: Connection, default: String) -> Result<Self, String> {
33 let flags = OpenFlags::new().with_create().with_read_write();
34 match Connect::open_thread_safe_with_flags(connection.clone().get_dsn().as_str(), flags) {
35 Ok(e) => {
36 DBS.lock().unwrap().insert(default.clone(), Arc::new(e));
37 Ok(Self {
38 connection: connection.clone(),
39 default: default.clone(),
40 params: Params::default("sqlite"),
41 })
42 }
43 Err(e) => {
44 error!(
45 "sqlite 启动失败: {} {}",
46 e,
47 connection.clone().get_dsn().as_str()
48 );
49 Err(e.to_string())
50 }
51 }
52 }
53 fn query_handle(&mut self, mut statement: Statement, sql: String) -> (bool, JsonValue) {
54 let thread_id = format!("{:?}", thread::current().id());
55
56 let mut data = array![];
57 while let State::Row = match statement.next() {
58 Ok(e) => e,
59 Err(e) => {
60 let transaction = *TR_COUNT.lock().unwrap().get(&*thread_id.clone()).unwrap_or(&0);
61 if transaction > 0 {
62 error!("{} 查询事务: {} {}", thread_id, e, sql.clone());
63 } else {
64 error!("{} 非事务查询: {} {}", thread_id, e, sql.clone());
65 }
66 return (false, data);
67 }
68 } {
69 let mut list = object! {};
70 let mut index = 0;
71 for field in statement.column_names().iter() {
72 if !list[field.as_str()].is_null() {
73 index += 1;
74 continue;
75 }
76 match statement.column_type(field.as_str()) {
77 Ok(types) => match types {
78 Type::String => {
79 let data = statement.read::<String, _>(index).unwrap();
80 match data.as_str() {
81 "false" => {
82 list[field.as_str()] = JsonValue::from(false);
83 }
84 "true" => {
85 list[field.as_str()] = JsonValue::from(true);
86 }
87 _ => {
88 list[field.as_str()] = JsonValue::from(data.clone());
89 }
90 }
91 }
92 Type::Integer => {
93 if FIELDS.lock().unwrap().get(&self.params.table).is_none() {
94 let data = statement.read::<i64, _>(index).unwrap();
95 list[field.as_str()] = JsonValue::from(data);
96 } else {
97 let fields = FIELDS.lock().unwrap().get(&self.params.table).unwrap().clone();
98 if fields[field.clone()].is_empty() {
99 let data = statement.read::<i64, _>(index).unwrap();
100 list[field.as_str()] = data.into();
101 continue;
102 }
103 match fields[field.clone()]["type"].as_str().unwrap() {
104 "INTEGER" => {
105 let data = statement.read::<i64, _>(index).unwrap();
106 list[field.as_str()] = JsonValue::from(data == 1);
107 }
108 x if x.contains("int(") => {
109 let data = statement.read::<i64, _>(index).unwrap();
110 list[field.as_str()] = data.into();
111 }
112 x if x.contains("decimal(") && x.ends_with(",0)") => {
113 let data = statement.read::<f64, _>(index).unwrap();
114 list[field.as_str()] = data.into();
115 }
116 _ => {
117 let data = statement.read::<i64, _>(index).unwrap();
118 list[field.as_str()] = data.into();
119 }
120 }
121 }
122 }
123 Type::Float => {
124 let data = statement.read::<f64, _>(index).unwrap();
125 list[field.as_str()] = JsonValue::from(data);
126 }
127 Type::Binary => {
128 let data = statement.read::<String, _>(index).unwrap();
129 list[field.as_str()] = JsonValue::from(data.clone());
130 }
131 Type::Null => match statement.read::<String, _>(index) {
132 Ok(data) => {
133 list[field.as_str()] = JsonValue::from(data.clone());
134 }
135 Err(_) => match statement.read::<f64, _>(index) {
136 Ok(data) => {
137 if data == 0.0 {
138 list[field.as_str()] = JsonValue::from("");
139 } else {
140 list[field.as_str()] = JsonValue::from(data);
141 }
142 }
143 Err(_) => match statement.read::<i64, _>(index) {
144 Ok(data) => {
145 if data == 0 {
146 list[field.as_str()] = JsonValue::from("");
147 } else {
148 list[field.as_str()] = JsonValue::from(data);
149 }
150 }
151 Err(e) => {
152 error!("Type:{} {:?}", field.as_str(), e);
153 }
154 },
155 },
156 },
157 },
158 Err(e) => {
159 error!("query Err: {e:?}");
160 }
161 }
162 index += 1;
163 }
164 data.push(list).unwrap();
165 }
166 (true, data)
167 }
168 pub fn query(&mut self, sql: String) -> (bool, JsonValue) {
169 let thread_id = format!("{:?}", thread::current().id());
170
171 let transaction = *TR_COUNT.lock().unwrap().get(&*thread_id.clone()).unwrap_or(&0);
172 if transaction > 0 {
173 if self.connection.debug {
174 info!("{} 查询事务: sql: {:?}", thread_id, sql.clone());
175 }
176
177 let dbs = match TR.lock() {
178 Ok(dbs) => dbs,
179 Err(e) => {
180 error!("{thread_id} 获取数据库锁失败: {e}\r\nSQL: {sql}");
181 return (false, JsonValue::from("数据库锁定失败"));
182 }
183 };
184 let db = dbs.get(&*thread_id.clone()).unwrap().clone();
185 let x = match db.prepare(sql.clone()) {
186 Ok(statement) => self.query_handle(statement, sql.clone()),
187 Err(e) => {
188 error!("{} 查询事务: Err: {} {}", thread_id, e, sql.clone());
189 (false, e.to_string().into())
190 }
191 };
192 x
193 } else {
194 if self.connection.debug {
195 info!("{} 非事务查询: sql: {:?}", thread_id, sql.clone());
196 }
197 let dbs = match DBS.lock() {
198 Ok(dbs) => dbs,
199 Err(e) => {
200 error!("{thread_id} 获取数据库锁失败: {e}\r\nSQL: {sql}");
201 return (false, JsonValue::from("数据库锁定失败"));
202 }
203 };
204 let db = dbs.get(&*self.default).unwrap().clone();
205 let x = match db.prepare(sql.clone()) {
206 Ok(statement) => self.query_handle(statement, sql.clone()),
207 Err(e) => {
208 error!("{thread_id} 查询非事务: Err: {e}");
209 (false, e.to_string().into())
210 }
211 };
212 x
213 }
214 }
215
216 pub fn execute(&mut self, sql: String) -> (bool, JsonValue) {
217 let thread_id = format!("{:?}", thread::current().id());
218
219 let transaction = *TR_COUNT.lock().unwrap().get(&*thread_id.clone()).unwrap_or(&0);
220 if transaction > 0 {
221 if self.connection.debug {
222 info!("{} 执行事务: sql: {}", thread_id, sql.clone());
223 }
224
225 let dbs = match TR.lock() {
226 Ok(dbs) => dbs,
227 Err(e) => {
228 error!("{thread_id} 获取数据库锁失败: {e}\r\nSQL: {sql}");
229 return (false, JsonValue::from("数据库锁定失败"));
230 }
231 };
232 let db = match dbs.get(&*thread_id) {
233 Some(db) => db.clone(),
234 None => {
235 error!(
236 "{} 未找到默认数据库配置: {}\r\nSQL: {}",
237 thread_id, self.default, sql
238 );
239 return (false, JsonValue::from("未找到默认数据库配置"));
240 }
241 };
242 match db.execute(sql.clone()) {
243 Ok(_) => {
244 let count = db.change_count();
245 if self.connection.debug {
246 info!(
247 "{} count:{} total_count:{}",
248 thread_id,
249 count,
250 db.total_change_count()
251 );
252 }
253 (true, JsonValue::from(count))
254 }
255 Err(e) => {
256 error!("{} 执行事务: \r\nErr: {}\r\n{}", thread_id, e, sql.clone());
257 (false, JsonValue::from(e.to_string()))
258 }
259 }
260 } else {
261 if self.connection.debug {
262 info!("{} 执行非事务: \r\nsql: {}", thread_id, sql.clone());
263 }
264 let dbs = match DBS.lock() {
265 Ok(dbs) => dbs,
266 Err(e) => {
267 error!("{thread_id} 获取数据库锁失败: {e}\r\nSQL: {sql}");
268 return (false, JsonValue::from("数据库锁定失败"));
269 }
270 };
271
272 let db = match dbs.get(&*self.default) {
273 Some(db) => db.clone(),
274 None => {
275 error!(
276 "{} 未找到默认数据库配置: {}\r\nSQL: {}",
277 thread_id, self.default, sql
278 );
279 return (false, JsonValue::from("未找到默认数据库配置"));
280 }
281 };
282 match db.execute(sql.clone()) {
283 Ok(_) => {
284 let count = db.change_count();
285 if self.connection.debug {
286 info!(
287 "{} count: {} total_count: {}",
288 thread_id,
289 count,
290 db.total_change_count()
291 );
292 }
293 (true, JsonValue::from(count))
294 }
295 Err(e) => {
296 error!(
297 "{} 执行非事务: Err: {}\r\nSQL: {}",
298 thread_id,
299 e,
300 sql.clone()
301 );
302 (false, JsonValue::from(e.to_string()))
303 }
304 }
305 }
306 }
307}
308
309impl DbMode for Sqlite {
310 fn database_tables(&mut self) -> JsonValue {
311 let sql = "select name from sqlite_master where type='table' order by name;".to_string();
312 match self.sql(sql.as_str()) {
313 Ok(e) => {
314 let mut list = vec![];
315 for item in e.members() {
316 list.push(item["name"].clone());
317 }
318 list.into()
319 }
320 Err(_) => {
321 array![]
322 }
323 }
324 }
325 fn database_create(&mut self, _name: &str) -> bool {
326 todo!()
327 }
328}
329
330impl Mode for Sqlite {
331 fn table_create(&mut self, options: TableOptions) -> JsonValue {
332 let mut sql = String::new();
333 let mut unique_fields = String::new();
335 let mut unique_name = String::new();
336 let mut unique = String::new();
337 for item in options.table_unique.iter() {
338 if unique_fields.is_empty() {
339 unique_fields = format!("`{item}`");
340 unique_name = format!("unique_{item}");
341 } else {
342 unique_fields = format!("{unique_fields},`{item}`");
343 unique_name = format!("{unique_name}_{item}");
344 }
345 unique = format!(
346 "CREATE UNIQUE INDEX {} on {} ({});\r\n",
347 unique_name, options.table_name, unique_fields
348 );
349 }
350
351 let mut index = vec![];
353 for row in options.table_index.iter() {
354 let mut index_fields = String::new();
355 let mut index_name = String::new();
356 for item in row.iter() {
357 if index_fields.is_empty() {
358 index_fields = format!("`{item}`");
359 index_name = format!("index_{item}");
360 } else {
361 index_fields = format!("{index_fields},`{item}`");
362 index_name = format!("{index_name}_{item}");
363 }
364 }
365 index.push(format!(
366 "CREATE INDEX {} on {} ({});\r\n",
367 index_name, options.table_name, index_fields
368 ));
369 }
370
371 for (name, field) in options.table_fields.entries() {
372 let row = br_fields::field("sqlite", name, field.clone());
373 sql = format!("{sql} {row},\r\n");
374 }
375
376 sql = sql.trim_end_matches(",\r\n").to_string();
377
378 let sql = format!(
379 "CREATE TABLE IF NOT EXISTS `{}` (\r\n{}\r\n);\r\n",
380 options.table_name, sql
381 );
382 if self.params.sql {
383 let mut list = vec![sql];
384 if !unique.is_empty() {
385 list.push(unique)
386 }
387 if !index.is_empty() {
388 list.extend(index)
389 }
390
391 return JsonValue::from(list.join(""));
392 }
393
394 let thread_id = format!("{:?}", thread::current().id());
395
396 let (state, _) = self.execute(sql.clone());
397 if state {
398 if !unique.is_empty() {
399 let (state, _) = self.execute(unique.clone());
400 info!(
401 "{} {} 唯一索引创建:{}",
402 thread_id, options.table_name, state
403 );
404 }
405 for sql in index.iter() {
406 let (state, _) = self.execute(sql.clone());
407 info!("{} {} 索引创建:{}", thread_id, options.table_name, state);
408 }
409 JsonValue::from(true)
410 } else {
411 JsonValue::from(false)
412 }
413 }
414 fn table_update(&mut self, options: TableOptions) -> JsonValue {
415 let thread_id = format!("{:?}", thread::current().id());
416
417 let mut sql = String::new();
418 let mut add = vec![];
419 let mut del = vec![];
420 let mut put = vec![];
421
422 let (_, mut fields_list) = self.query(format!("pragma table_info ('{}')", options.table_name));
423 let mut field_old = object! {};
424 for item in fields_list.members_mut() {
425 item["dflt_value"] = item["dflt_value"].to_string().trim_start_matches("'").trim_end_matches("'").into();
426 let name = item["name"].as_str().unwrap();
427 field_old[name] = item.clone();
428 if options.table_fields[name].is_empty() {
429 del.push(name);
430 }
431 }
432
433 let mut fields_list = vec![];
434 let mut fields_list_new = vec![];
435
436 for (name, field) in options.table_fields.entries() {
437 if field_old[name].is_empty() {
438 add.push(name);
439 } else {
440 fields_list.push(name);
441 fields_list_new.push(name);
442 let old_value = match field["mode"].as_str().unwrap() {
443 "select" => {
444 if field_old[name]["dflt_value"].clone().is_empty() {
445 "".to_string()
446 } else {
447 field_old[name]["dflt_value"].clone().to_string()
448 }
449 }
450 "switch" => {
451 (field_old[name]["dflt_value"].to_string().parse::<i32>().unwrap() == 1).to_string()
452 }
453 _ => {
454 field_old[name]["dflt_value"].clone().to_string()
455 }
456 };
457 let new_value = match field["mode"].as_str().unwrap() {
458 "select" => {
459 field["def"].members().map(|x| x.to_string()).collect::<Vec<String>>().join(",")
460 }
461 _ => field["def"].clone().to_string()
462 };
463 if old_value != new_value {
464 info!("{} 差异化当前: {} old_value: {} new_value: {} {}",
465 options.table_name,
466 name,
467 old_value,
468 new_value,
469 old_value != new_value
470 );
471 info!("差异化更新: {} {:#} {:#}", name, field_old[name], field);
472 put.push(name);
473 } else if field_old[name]["pk"].as_i64().unwrap() == 1 && name != options.table_key
474 {
475 info!("{} 主键替换: {}", options.table_name, name);
476 put.push(name);
477 }
478 }
479 }
480
481 let mut unique_fields = String::new();
482 let mut unique_name = String::new();
483 let mut unique = String::new();
484
485 for item in options.table_unique.iter() {
487 if unique_fields.is_empty() {
488 unique_fields = format!("`{item}`");
489 unique_name = format!("unique_{item}");
490 } else {
491 unique_fields = format!("{unique_fields},`{item}`");
492 unique_name = format!("{unique_name}_{item}");
493 }
494 unique = format!(
495 "CREATE UNIQUE INDEX {}_{} on {} ({});\r\n",
496 options.table_name, unique_name, options.table_name, unique_fields
497 )
498 }
499
500 let mut index = vec![];
502 for row in options.table_index.iter() {
503 let mut index_fields = String::new();
504 let mut index_name = String::new();
505 for item in row.iter() {
506 if index_fields.is_empty() {
507 index_fields = item.to_string();
508 index_name = format!("index_{item}");
509 } else {
510 index_fields = format!("{index_fields},{item}");
511 index_name = format!("{index_name}_{item}");
512 }
513 }
514 index.push(format!(
515 "create index {}_{} on {} ({});\r\n",
516 options.table_name, index_name, options.table_name, index_fields
517 ));
518 }
519 for (name, field) in options.table_fields.entries() {
520 let row = br_fields::field("sqlite", name, field.clone());
521 sql = format!("{sql} {row},\r\n");
522 }
523
524 if !unique.is_empty() || !index.is_empty() {
525 let unique_text = unique.clone();
526 let (_, unique_old) = self.query(format!("PRAGMA index_list({});\r\n", options.table_name));
527 let mut index_old_list = vec![];
528 let mut index_new_list = vec![];
529 for item in unique_old.members() {
530 let origin = item["origin"].as_str().unwrap();
531 let unique_1 = item["unique"].as_usize().unwrap();
532 let name = item["name"].as_str().unwrap();
533
534 if origin == "c" && unique_1 == 1 {
535 if unique.contains(format!(" {name} ").as_str()) {
536 unique = "".to_string();
537 }
538 continue;
539 }
540 if origin == "c" && unique_1 == 0 {
541 index_old_list.push(item);
542 for item in index.iter() {
543 if item.contains(format!(" {name} ").as_str()) {
544 index_new_list.push(item.clone());
545 }
546 }
547 continue;
548 }
549 }
550 if unique.is_empty() {
551 if index_old_list.len() == index.len() && index_old_list.len() == index_new_list.len()
552 {
553 index = vec![];
554 } else {
555 unique = unique_text;
556 }
557 }
558 }
559
560 sql = sql.trim_end_matches(",\r\n").to_string();
561 sql = format!(
562 "CREATE TABLE {}_tmp (\r\n{}\r\n);\r\n",
563 options.table_name, sql
564 );
565
566 let sqls = format!(
567 "replace INTO {}_tmp (`{}`) select `{}` from {00};\r\n",
568 options.table_name,
569 fields_list_new.join("`,`"),
570 fields_list.join("`,`")
571 );
572 let drop_sql = format!("drop table {};\r\n", options.table_name);
573 let alter_sql = format!("alter table {}_tmp rename to {00};\r\n", options.table_name);
574 let drop_sql_temp = format!("drop table {}_tmp;\r\n", options.table_name);
575
576 if self.params.sql {
577 let mut list = vec![sql, sqls, drop_sql, alter_sql, drop_sql_temp];
578 if !unique.is_empty() {
579 list.push(unique)
580 }
581 if !index.is_empty() {
582 list.extend(index)
583 }
584 return JsonValue::from(list.join(""));
585 }
586
587 if add.is_empty() && del.is_empty() && unique.is_empty() && index.is_empty() && put.is_empty()
588 {
589 return JsonValue::from(-1);
590 }
591
592 let (state, _) = self.execute(sql.clone());
593 let data = match state {
594 true => {
595 let (state, _) = self.execute(sqls.clone());
596 match state {
597 true => {
598 let (state, _) = self.execute(drop_sql);
599 match state {
600 true => {
601 let (state, _) = self.execute(alter_sql);
602 match state {
603 true => {
604 if !unique.is_empty() {
605 let (state, _) = self.execute(unique.clone());
606 info!(
607 "{} {} 唯一索引创建:{}",
608 thread_id, options.table_name, state
609 );
610 }
611 for index_sql in index.iter() {
612 let (state, _) = self.execute(index_sql.clone());
613 match state {
614 true => {}
615 false => {
616 error!(
617 "{} 索引创建失败: {} {}",
618 options.table_name, state, index_sql
619 );
620 return JsonValue::from(0);
621 }
622 };
623 }
624
625 return JsonValue::from(1);
626 }
627 false => {
628 error!("{} 修改表名失败", options.table_name);
629 return JsonValue::from(0);
630 }
631 }
632 }
633 false => {
634 error!("{} 删除本表失败", options.table_name);
635 return JsonValue::from(0);
636 }
637 }
638 }
639 false => {
640 error!(
641 "{} 添加tmp表记录失败 {:#} {:#}",
642 options.table_name, sql, sqls
643 );
644 let sql = format!("drop table {}_tmp", options.table_name);
645 let (_, _) = self.execute(sql);
646 0
647 }
648 }
649 }
650 false => {
651 error!("{} 创建TMP表失败 {:#}", options.table_name, sql);
652 let (_, _) = self.execute(drop_sql_temp);
653 0
654 }
655 };
656 JsonValue::from(data)
657 }
658
659 fn table_info(&mut self, table: &str) -> JsonValue {
660 if FIELDS.lock().unwrap().get(table).is_some() {
661 return FIELDS.lock().unwrap().get(table).unwrap().clone();
662 }
663 let sql = format!("PRAGMA table_info({table})");
664 let (state, data) = self.query(sql);
665
666 match state {
667 true => {
668 let mut fields = object! {};
669 for item in data.members() {
670 fields[item["name"].as_str().unwrap()] = item.clone();
671 }
672 FIELDS.lock().unwrap().insert(table.to_string(), fields.clone());
673 data
674 }
675 false => object! {}
676 }
677 }
678
679 fn table_is_exist(&mut self, name: &str) -> bool {
680 let sql = format!(
681 "SELECT count(*) as count FROM sqlite_master WHERE type='table' AND name='{name}'"
682 );
683 let (state, data) = self.query(sql);
684 if state {
685 if data[0]["count"].as_i64().unwrap() > 0 {
686 return true;
687 }
688 false
689 } else {
690 false
691 }
692 }
693
694 fn table(&mut self, name: &str) -> &mut Sqlite {
695 self.params = Params::default(self.connection.mode.str().as_str());
696 self.params.table = format!("{}{}", self.connection.prefix, name);
697 self.params.join_table = self.params.table.clone();
698 self
699 }
700 fn change_table(&mut self, name: &str) -> &mut Self {
701 self.params.join_table = name.to_string();
702 self
703 }
704 fn autoinc(&mut self) -> &mut Self {
705 self.params.autoinc = true;
706 self
707 }
708
709 fn fetch_sql(&mut self) -> &mut Self {
710 self.params.sql = true;
711 self
712 }
713
714 fn order(&mut self, field: &str, by: bool) -> &mut Self {
715 self.params.order[field] = {
716 if by {
717 "DESC"
718 } else {
719 "ASC"
720 }
721 }.into();
722 self
723 }
724
725 fn group(&mut self, field: &str) -> &mut Self {
726 let fields: Vec<&str> = field.split(",").collect();
727 for field in fields.iter() {
728 let fields = field.to_string();
729 self.params.group[fields.as_str()] = fields.clone().into();
730 self.params.fields[fields.as_str()] = fields.clone().into();
731 }
732 self
733 }
734
735 fn distinct(&mut self) -> &mut Self {
736 self.params.distinct = true;
737 self
738 }
739 fn json(&mut self, field: &str) -> &mut Self {
740 let list: Vec<&str> = field.split(",").collect();
741 for item in list.iter() {
742 self.params.json[item.to_string().as_str()] = item.to_string().into();
743 }
744 self
745 }
746
747 fn location(&mut self, field: &str) -> &mut Self {
748 let list: Vec<&str> = field.split(",").collect();
749 for item in list.iter() {
750 self.params.location[item.to_string().as_str()] = item.to_string().into();
751 }
752 self
753 }
754
755 fn field(&mut self, field: &str) -> &mut Self {
756 let list: Vec<&str> = field.split(",").collect();
757 let join_table = if self.params.join_table.is_empty() {
758 self.params.table.clone()
759 } else {
760 self.params.join_table.clone()
761 };
762 for item in list.iter() {
763 let item = item.to_string();
764 if item.contains(" as ") {
765 let text = item.split(" as ").collect::<Vec<&str>>().clone();
766 self.params.fields[item] = format!("{}.`{}` as `{}`", join_table, text[0], text[1]).into();
767 } else {
768 self.params.fields[item] = format!("{join_table}.`{item}`").into();
769 }
770 }
771 self
772 }
773 fn hidden(&mut self, name: &str) -> &mut Self {
774 let hidden: Vec<&str> = name.split(",").collect();
775 let sql = format!("PRAGMA table_info({})", self.params.table);
776 let (_, data) = self.query(sql);
777 for item in data.members() {
778 let name = item["name"].as_str().unwrap();
779 if !hidden.contains(&name) {
780 self.params.fields[name] = name.into();
781 }
782 }
783 self
784 }
785
786 fn where_and(&mut self, field: &str, compare: &str, mut value: JsonValue) -> &mut Self {
787 let join_table = if self.params.join_table.is_empty() {
788 self.params.table.clone()
789 } else {
790 self.params.join_table.clone()
791 };
792
793 if value.is_boolean() {
794 if value.as_bool().unwrap() {
795 value = 1.into();
796 } else {
797 value = 0.into();
798 }
799 }
800
801 match compare {
802 "between" => {
803 self.params.where_and.push(format!(
804 "{}.`{}` between '{}' AND '{}'",
805 join_table, field, value[0], value[1]
806 ));
807 }
808 "set" => {
809 let list: Vec<&str> = value.as_str().unwrap().split(",").collect();
810 let mut wheredata = vec![];
811 for item in list.iter() {
812 wheredata.push(format!("{join_table}.`{field}` like '%{item}%'"));
813 }
814 self.params.where_and.push(format!("({})", wheredata.join(" or ")));
815 }
816 "notin" => {
817 let mut text = String::new();
818 for item in value.members() {
819 text = format!("{text},'{item}'");
820 }
821 text = text.trim_start_matches(",").into();
822 self.params.where_and.push(format!("{join_table}.`{field}` not in ({text})"));
823 }
824 "in" => {
825 let mut text = String::new();
826 if value.is_array() {
827 for item in value.members() {
828 text = format!("{text},'{item}'");
829 }
830 } else {
831 let value = value.to_string();
832 let value: Vec<&str> = value.split(",").collect();
833 for item in value.iter() {
834 text = format!("{text},'{item}'");
835 }
836 }
837 text = text.trim_start_matches(",").into();
838
839 self.params.where_and.push(format!("{join_table}.`{field}` {compare} ({text})"));
840 }
841 "=" => {
842 if value.is_null() {
843 self.params.where_and.push(format!("{}.`{}` {} {}", join_table, field, "IS", value));
844 } else {
845 self.params.where_and.push(format!(
846 "{join_table}.`{field}` {compare} '{value}'"
847 ));
848 }
849 }
850 _ => {
851 if value.is_null() {
852 self.params.where_and.push(format!("{join_table}.`{field}` {compare} {value}"));
853 } else {
854 self.params.where_and.push(format!(
855 "{join_table}.`{field}` {compare} '{value}'"
856 ));
857 }
858 }
859 }
860 self
861 }
862 fn where_or(&mut self, field: &str, compare: &str, mut value: JsonValue) -> &mut Self {
863 let join_table = if self.params.join_table.is_empty() {
864 self.params.table.clone()
865 } else {
866 self.params.join_table.clone()
867 };
868
869 if value.is_boolean() {
870 if value.as_bool().unwrap() {
871 value = 1.into();
872 } else {
873 value = 0.into();
874 }
875 }
876 match compare {
877 "between" => {
878 self.params.where_or.push(format!(
879 "{}.`{}` between '{}' AND '{}'",
880 join_table, field, value[0], value[1]
881 ));
882 }
883 "set" => {
884 let tt = value.to_string().replace(",", "%");
885 self.params.where_or.push(format!("{join_table}.`{field}` like '%{tt}%'"));
886 }
887 "notin" => {
888 let mut text = String::new();
889 for item in value.members() {
890 text = format!("{text},'{item}'");
891 }
892 text = text.trim_start_matches(",").into();
893 self.params.where_or.push(format!("{join_table}.`{field}` not in ({text})"));
894 }
895 "in" => {
896 let mut text = String::new();
897 if value.is_array() {
898 for item in value.members() {
899 text = format!("{text},'{item}'");
900 }
901 } else {
902 let value = value.as_str().unwrap();
903 let value: Vec<&str> = value.split(",").collect();
904 for item in value.iter() {
905 text = format!("{text},'{item}'");
906 }
907 }
908 text = text.trim_start_matches(",").into();
909 self.params.where_or.push(format!("{join_table}.`{field}` {compare} ({text})"));
910 }
911 _ => {
912 self.params.where_or.push(format!(
913 "{join_table}.`{field}` {compare} '{value}'"
914 ));
915 }
916 }
917 self
918 }
919 fn where_column(&mut self, field_a: &str, compare: &str, field_b: &str) -> &mut Self {
920 self.params.where_column = format!(
921 "{}.`{}` {} {}.`{}`",
922 self.params.table, field_a, compare, self.params.table, field_b
923 );
924 self
925 }
926
927 fn page(&mut self, page: i32, limit: i32) -> &mut Self {
928 self.params.page = page;
929 self.params.limit = limit;
930 self
931 }
932
933 fn column(&mut self, field: &str) -> JsonValue {
934 self.field(field);
935 self.group(field);
936 let sql = self.params.select_sql();
937 if self.params.sql {
938 return JsonValue::from(sql.clone());
939 }
940 self.table_info(self.params.table.clone().as_str());
941 let (state, data) = self.query(sql);
942 if state {
943 let mut list = array![];
944 for item in data.members() {
945 if self.params.json[field].is_empty() {
946 list.push(item[field].clone()).unwrap();
947 } else {
948 let data = json::parse(item[field].as_str().unwrap()).unwrap_or(array![]);
949 list.push(data).unwrap();
950 }
951 }
952 list
953 } else {
954 array![]
955 }
956 }
957
958 fn count(&mut self) -> JsonValue {
959 self.params.fields["count"] = "count(*) as count".to_string().into();
960 let sql = self.params.select_sql();
961 if self.params.sql {
962 return JsonValue::from(sql.clone());
963 }
964 let (state, data) = self.query(sql);
965 match state {
966 true => data[0]["count"].clone(),
967 false => JsonValue::from(0),
968 }
969 }
970
971 fn max(&mut self, field: &str) -> JsonValue {
972 self.params.fields[field] = format!("max({field}) as {field}").into();
973 let sql = self.params.select_sql();
974 if self.params.sql {
975 return JsonValue::from(sql.clone());
976 }
977 let (state, data) = self.query(sql);
978 if state {
979 if data.len() > 1 {
980 return data;
981 }
982 data[0][field].clone()
983 } else {
984 JsonValue::from(0.0)
985 }
986 }
987
988 fn min(&mut self, field: &str) -> JsonValue {
989 self.params.fields[field] = format!("min({field}) as {field}").into();
990 let sql = self.params.select_sql();
991 let (state, data) = self.query(sql);
992 if state {
993 if data.len() > 1 {
994 return data;
995 }
996 data[0][field].clone()
997 } else {
998 JsonValue::from(0.0)
999 }
1000 }
1001
1002 fn sum(&mut self, field: &str) -> JsonValue {
1003 self.params.fields[field] = format!("sum({field}) as {field}").into();
1004 let sql = self.params.select_sql();
1005 if self.params.sql {
1006 return JsonValue::from(sql.clone());
1007 }
1008 let (state, data) = self.query(sql);
1009 match state {
1010 true => {
1011 if data.len() > 1 {
1012 return data;
1013 }
1014 if self.params.fields.len() > 1 {
1015 return data[0].clone();
1016 }
1017 data[0][field].clone()
1018 }
1019 false => JsonValue::from(0),
1020 }
1021 }
1022 fn avg(&mut self, field: &str) -> JsonValue {
1023 self.params.fields[field] = format!("avg({field}) as {field}").into();
1024 let sql = self.params.select_sql();
1025 if self.params.sql {
1026 return JsonValue::from(sql.clone());
1027 }
1028 let (state, data) = self.query(sql);
1029 if state {
1030 if data.len() > 1 {
1031 return data;
1032 }
1033 data[0][field].clone()
1034 } else {
1035 JsonValue::from(0)
1036 }
1037 }
1038 fn select(&mut self) -> JsonValue {
1039 let sql = self.params.select_sql();
1040 if self.params.sql {
1041 return JsonValue::from(sql.clone());
1042 }
1043 self.table_info(self.params.table.clone().as_str());
1044 let (state, mut data) = self.query(sql.clone());
1045 match state {
1046 true => {
1047 for (field, _) in self.params.json.entries() {
1048 for item in data.members_mut() {
1049 if !item[field].is_empty() {
1050 let json = item[field].to_string();
1051 item[field] = match json::parse(&json) {
1052 Ok(e) => e,
1053 Err(_) => JsonValue::from(json),
1054 };
1055 }
1056 }
1057 }
1058 data.clone()
1059 }
1060 false => {
1061 error!("{data:?}");
1062 array![]
1063 }
1064 }
1065 }
1066 fn find(&mut self) -> JsonValue {
1067 self.params.page = 1;
1068 self.params.limit = 1;
1069 let sql = self.params.select_sql();
1070 if self.params.sql {
1071 return JsonValue::from(sql.clone());
1072 }
1073
1074 self.table_info(self.params.table.clone().as_str());
1075 let (state, mut data) = self.query(sql.clone());
1076 match state {
1077 true => {
1078 if data.is_empty() {
1079 return object! {};
1080 }
1081 for (field, _) in self.params.json.entries() {
1082 if !data[0][field].is_empty() {
1083 let json = data[0][field].to_string();
1084 let json = json::parse(&json).unwrap_or(array![]);
1085 data[0][field] = json;
1086 } else {
1087 data[0][field] = array![];
1088 }
1089 }
1090 data[0].clone()
1091 }
1092 false => {
1093 error!("{data:?}");
1094 object! {}
1095 }
1096 }
1097 }
1098
1099 fn value(&mut self, field: &str) -> JsonValue {
1100 self.params.fields = object! {};
1101 self.params.fields[field] = format!("{}.`{}`", self.params.table, field).into();
1102 self.params.page = 1;
1103 self.params.limit = 1;
1104 let sql = self.params.select_sql();
1105 if self.params.sql {
1106 return JsonValue::from(sql.clone());
1107 }
1108 self.table_info(self.params.table.clone().as_str());
1109 let (state, mut data) = self.query(sql.clone());
1110 match state {
1111 true => {
1112 for (field, _) in self.params.json.entries() {
1113 if !data[0][field].is_empty() {
1114 let json = data[0][field].to_string();
1115 let json = json::parse(&json).unwrap_or(array![]);
1116 data[0][field] = json;
1117 } else {
1118 data[0][field] = array![];
1119 }
1120 }
1121 data[0][field].clone()
1122 }
1123 false => {
1124 if self.connection.debug {
1125 info!("{data:?}");
1126 }
1127 JsonValue::Null
1128 }
1129 }
1130 }
1131
1132 fn insert(&mut self, mut data: JsonValue) -> JsonValue {
1133 let mut fields = vec![];
1134 let mut values = vec![];
1135
1136 if !self.params.autoinc && data["id"].is_empty() {
1137 data["id"] = format!("{:X}", Local::now().timestamp_nanos_opt().unwrap()).into();
1138 }
1139 for (field, value) in data.entries() {
1140 fields.push(format!("`{field}`"));
1141
1142 if value.is_string() {
1143 if value.to_string().contains("'") {
1144 values.push(format!("\"{}\"", value.to_string().replace("'", "''")));
1145 continue;
1146 } else if value.to_string().contains('"') {
1147 values.push(format!("'{value}'"));
1148 continue;
1149 } else {
1150 values.push(format!("\"{value}\""));
1151 continue;
1152 }
1153 } else if value.is_array() || value.is_object() {
1154 if self.params.json[field].is_empty() {
1155 values.push(format!("'{value}'"));
1156 } else {
1157 let json = value.to_string();
1158 let json = json.replace("'", "''");
1159 values.push(format!("'{json}'"));
1160 }
1161 continue;
1162 } else if value.is_number() || value.is_boolean() || value.is_null() {
1163 values.push(format!("{value}"));
1164 continue;
1165 } else {
1166 values.push(format!("'{value}'"));
1167 continue;
1168 }
1169 }
1170 let fields = fields.join(",");
1171 let values = values.join(",");
1172
1173 let sql = format!(
1174 "INSERT INTO `{}` ({}) VALUES ({});",
1175 self.params.table, fields, values
1176 );
1177 if self.params.sql {
1178 return JsonValue::from(sql.clone());
1179 }
1180 let (state, ids) = self.execute(sql);
1181 match state {
1182 true => {
1183 if self.params.autoinc {
1184 let (state, ids) = self.query(format!("select max(id) as id from {}", self.params.table));
1185 return match state {
1186 true => ids[0]["id"].clone(),
1187 false => {
1188 error!("{ids}");
1189 JsonValue::from("")
1190 }
1191 };
1192 }
1193 data["id"].clone()
1194 }
1195 false => {
1196 error!("{ids}");
1197 JsonValue::from("")
1198 }
1199 }
1200 }
1201 fn insert_all(&mut self, mut data: JsonValue) -> JsonValue {
1202 let mut fields = String::new();
1203
1204 if !self.params.autoinc && data[0]["id"].is_empty() {
1205 data[0]["id"] = "".into();
1206 }
1207 for (field, _) in data[0].entries() {
1208 fields = format!("{fields},`{field}`");
1209 }
1210 fields = fields.trim_start_matches(",").parse().unwrap();
1211
1212 let core_count = num_cpus::get();
1213 let mut p = pools::Pool::new(core_count * 4);
1214 let autoinc = self.params.autoinc;
1215 for list in data.members() {
1216 let mut item = list.clone();
1217 p.execute(move |pcindex| {
1218 if !autoinc && item["id"].is_empty() {
1219 let id = format!(
1220 "{:X}{:X}",
1221 Local::now().timestamp_nanos_opt().unwrap(),
1222 pcindex
1223 );
1224 item["id"] = id.into();
1225 }
1226 let mut values = "".to_string();
1227 for (_, value) in item.entries() {
1228 if value.is_string() {
1229 values = format!("{},'{}'", values, value.to_string().replace("'", "''"));
1230 } else if value.is_number() || value.is_boolean() {
1231 values = format!("{values},{value}");
1232 } else {
1233 values = format!("{},'{}'", values, value.to_string().replace("'", "''"));
1234 }
1235 }
1236 values = format!("({})", values.trim_start_matches(","));
1237 array![item["id"].clone(), values]
1238 });
1239 }
1240 let (ids_list, mut values) = p.insert_all();
1241
1242 values = values.trim_start_matches(",").parse().unwrap();
1243
1244 let sql = format!(
1245 "INSERT INTO {} ({}) VALUES {};",
1246 self.params.table, fields, values
1247 );
1248 if self.params.sql {
1249 return JsonValue::from(sql.clone());
1250 }
1251 let (state, data) = self.execute(sql.clone());
1252 match state {
1253 true => {
1254 if self.params.autoinc {
1255 let (state, ids) = self.query(format!(
1256 "SELECT id FROM {} GROUP BY id ORDER BY id DESC LIMIT {} OFFSET 0",
1257 self.params.table,
1258 ids_list.len()
1259 ));
1260 return match state {
1261 true => {
1262 let mut idlist = array![];
1263 for item in ids.members() {
1264 idlist.push(item["id"].clone()).unwrap();
1265 }
1266 idlist
1267 }
1268 false => {
1269 error!("批量添加失败: {ids:?} {sql}");
1270 array![]
1271 }
1272 };
1273 }
1274 JsonValue::from(ids_list)
1275 }
1276 false => {
1277 error!("批量添加失败: {data:?} {sql}");
1278 array![]
1279 }
1280 }
1281 }
1282
1283 fn update(&mut self, data: JsonValue) -> JsonValue {
1284 let mut values = vec![];
1285
1286 for (field, value) in data.entries() {
1287 if value.is_string() {
1288 values.push(format!(
1289 "`{}` = '{}'",
1290 field,
1291 value.to_string().replace("'", "''")
1292 ));
1293 } else if value.is_array() || value.is_object() {
1294 if self.params.json[field].is_empty() {
1295 values.push(format!("`{field}` = '{value}'"));
1296 } else {
1297 let json = value.to_string();
1298 let json = json.replace("'", "''");
1299 values.push(format!("`{field}` = '{json}'"));
1300 }
1301 continue;
1302 } else if value.is_number() || value.is_boolean() || value.is_null() {
1303 values.push(format!("`{field}` = {value} "));
1304 } else {
1305 values.push(format!("`{field}` = '{value}' "));
1306 }
1307 }
1308
1309 for (field, value) in self.params.inc_dec.entries() {
1310 values.push(format!("{} = {}", field, value.to_string().clone()));
1311 }
1312
1313 let values = values.join(",");
1314 let sql = format!(
1315 "UPDATE `{}` SET {} {} {};",
1316 self.params.table.clone(),
1317 values,
1318 self.params.where_sql(),
1319 self.params.page_limit_sql()
1320 );
1321 if self.params.sql {
1322 return JsonValue::from(sql.clone());
1323 }
1324 let (state, data) = self.execute(sql);
1325 if state {
1326 data
1327 } else {
1328 error!("{data}");
1329 JsonValue::from(0)
1330 }
1331 }
1332
1333 fn update_all(&mut self, data: JsonValue) -> JsonValue {
1334 let mut values = vec![];
1335 let mut ids = vec![];
1336 for (field, _) in data[0].entries() {
1337 if field == "id" {
1338 continue;
1339 }
1340 let mut fields = vec![];
1341 for row in data.members() {
1342 let value = row[field].clone();
1343 let id = row["id"].clone();
1344 ids.push(id.clone());
1345 if value.is_string() {
1346 fields.push(format!(
1347 "WHEN '{}' THEN '{}'",
1348 id,
1349 value.to_string().replace("'", "''")
1350 ));
1351 } else if value.is_array() || value.is_object() {
1352 if self.params.json[field].is_empty() {
1353 fields.push(format!("WHEN '{id}' THEN '{value}'"));
1354 } else {
1355 let json = value.to_string();
1356 let json = json.replace("'", "''");
1357 fields.push(format!("WHEN '{id}' THEN '{json}'"));
1358 }
1359 continue;
1360 } else if value.is_number() || value.is_boolean() || value.is_null() {
1361 fields.push(format!("WHEN '{id}' THEN {value}"));
1362 } else {
1363 fields.push(format!("WHEN '{id}' THEN '{value}'"));
1364 }
1365 }
1366 values.push(format!("`{}` = CASE id {} END", field, fields.join(" ")))
1367 }
1368
1369 self.where_and("id", "in", ids.into());
1370 for (field, value) in self.params.inc_dec.entries() {
1371 values.push(format!("{} = {}", field, value.to_string().clone()));
1372 }
1373
1374 let values = values.join(",");
1375 let sql = format!(
1376 "UPDATE {} SET {} {} {};",
1377 self.params.table.clone(),
1378 values,
1379 self.params.where_sql(),
1380 self.params.page_limit_sql()
1381 );
1382 if self.params.sql {
1383 return JsonValue::from(sql.clone());
1384 }
1385 let (state, data) = self.execute(sql);
1386 if state {
1387 data
1388 } else {
1389 error!("{data:?}");
1390 JsonValue::from(0)
1391 }
1392 }
1393 fn delete(&mut self) -> JsonValue {
1394 let sql = format!(
1395 "delete FROM `{}` {};",
1396 self.params.table.clone(),
1397 self.params.where_sql()
1398 );
1399 if self.params.sql {
1400 return JsonValue::from(sql.clone());
1401 }
1402 let (state, data) = self.execute(sql);
1403 match state {
1404 true => data,
1405 false => {
1406 error!("delete 失败>>>{data:?}");
1407 JsonValue::from(0)
1408 }
1409 }
1410 }
1411
1412 fn transaction(&mut self) -> bool {
1413 let thread_id = format!("{:?}", thread::current().id());
1414 let mut transaction = *TR_COUNT.lock().unwrap().get(&*thread_id.clone()).unwrap_or(&0);
1415 if transaction > 0 {
1416 transaction += 1;
1417 TR_COUNT.lock().unwrap().insert(thread_id.clone(), transaction);
1418 return true;
1419 }
1420
1421 loop {
1422 let mut t = TR_COUNT.lock().unwrap();
1423 if t.is_empty() {
1424 t.insert(thread_id.clone(), 1);
1425 break;
1426 }
1427 drop(t);
1428 thread::yield_now();
1429 }
1430
1431 let flags = OpenFlags::new().with_read_write().with_no_mutex();
1432 let db = match Connect::open_thread_safe_with_flags(
1433 self.connection.clone().get_dsn().as_str(),
1434 flags,
1435 ) {
1436 Ok(e) => Arc::new(e),
1437 Err(_) => {
1438 return false;
1439 }
1440 };
1441 TR.lock().unwrap().insert(thread_id.clone(), db);
1442 let (state, data) = self.query("BEGIN".to_string());
1443 if state {
1444 true
1445 } else {
1446 error!("{thread_id} 启动事务失败: {data}");
1447 TR.lock().unwrap().remove(&thread_id.clone());
1448 TR_COUNT.lock().unwrap().remove(&thread_id.clone());
1449 false
1450 }
1451 }
1452
1453 fn commit(&mut self) -> bool {
1454 let thread_id = format!("{:?}", thread::current().id());
1455
1456 let mut transaction = *TR_COUNT.lock().unwrap().get(&*thread_id.clone()).unwrap_or(&0);
1457 if transaction > 1 {
1458 transaction -= 1;
1459 TR_COUNT.lock().unwrap().insert(thread_id.clone(), transaction);
1460 return true;
1461 }
1462 let sql = "COMMIT";
1463 let (state, _) = self.query(sql.to_string());
1464 TR_COUNT.lock().unwrap().remove(&*thread_id.clone());
1465 TR.lock().unwrap().remove(&*thread_id.clone());
1466
1467 if state {
1468 true
1469 } else {
1470 error!("{thread_id} 提交事务失败");
1471 false
1472 }
1473 }
1474
1475 fn rollback(&mut self) -> bool {
1476 let thread_id = format!("{:?}", thread::current().id());
1477 let sql = "ROLLBACK";
1478
1479 let mut t = *TR_COUNT.lock().unwrap().get(&thread_id).unwrap();
1480 if t > 1 {
1481 t -= 1;
1482 TR_COUNT.lock().unwrap().insert(thread_id.clone(), t);
1483 return true;
1484 }
1485 let (state, _) = self.query(sql.to_string());
1486 TR_COUNT.lock().unwrap().remove(&*thread_id.clone());
1487 TR.lock().unwrap().remove(&*thread_id.clone());
1488
1489 if state {
1490 true
1491 } else {
1492 error!("回滚失败: {thread_id}");
1493 false
1494 }
1495 }
1496
1497 fn sql(&mut self, sql: &str) -> Result<JsonValue, String> {
1498 let (state, data) = self.query(sql.to_string());
1499 match state {
1500 true => Ok(data),
1501 false => Err(data.to_string()),
1502 }
1503 }
1504
1505 fn sql_execute(&mut self, sql: &str) -> Result<JsonValue, String> {
1506 let (state, data) = self.execute(sql.to_string());
1507 match state {
1508 true => Ok(data),
1509 false => Err(data.to_string()),
1510 }
1511 }
1512
1513 fn inc(&mut self, field: &str, num: f64) -> &mut Self {
1514 self.params.inc_dec[field] = format!("`{field}` + {num}").into();
1515 self
1516 }
1517
1518 fn dec(&mut self, field: &str, num: f64) -> &mut Self {
1519 self.params.inc_dec[field] = format!("`{field}` - {num}").into();
1520 self
1521 }
1522
1523 fn buildsql(&mut self) -> String {
1524 self.fetch_sql();
1525 let sql = self.select().to_string();
1526 format!("( {} ) `{}`", sql, self.params.table)
1527 }
1528
1529 fn join(&mut self, table: &str, main_fields: &str, right_fields: &str) -> &mut Self {
1530 let main_fields = if main_fields.is_empty() {
1531 "id"
1532 } else {
1533 main_fields
1534 };
1535 let right_fields = if right_fields.is_empty() {
1536 self.params.table.clone()
1537 } else {
1538 right_fields.to_string().clone()
1539 };
1540 self.params.join_table = table.to_string();
1541 self.params.join.push(format!(
1542 " LEFT JOIN {} ON {}.{} = {}.{}",
1543 table, self.params.table, main_fields, table, right_fields
1544 ));
1545 self
1546 }
1547
1548 fn join_inner(&mut self, table: &str, main_fields: &str, second_fields: &str) -> &mut Self {
1549 let main_fields = if main_fields.is_empty() {
1550 "id"
1551 } else {
1552 main_fields
1553 };
1554 let second_fields = if second_fields.is_empty() {
1555 self.params.table.clone()
1556 } else {
1557 second_fields.to_string().clone()
1558 };
1559 let sec_table_name = format!("{}{}", table, "_2");
1560 let second_table = format!("{} {}", table, sec_table_name.clone());
1561 self.params.join_table = sec_table_name.clone();
1562 self.params.join.push(format!(
1563 " INNER JOIN {} ON {}.{} = {}.{}",
1564 second_table, self.params.table, main_fields, sec_table_name, second_fields
1565 ));
1566 self
1567 }
1568}