1use crate::Config;
2use crate::colored::Colorize;
3use sqlx::{AnyPool, Row, Column, TypeInfo};
4use serde_json::Value;
5use serde::de::DeserializeOwned;
6
7pub async fn connect(cfg: &Config) -> AnyPool {
8 let db_url = if cfg.db_connection == "mysql" {
9 format!(
10 "mysql://{}:{}@{}:{}/{}",
11 cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port, cfg.db_database
12 )
13 } else {
14 format!("sqlite:database/{}.sqlite?mode=rwc", cfg.db_database)
15 };
16
17 sqlx::any::install_default_drivers();
18
19 let db_url_ref: &str = &db_url;
20 match AnyPool::connect(db_url_ref).await {
21 Ok(pool) => pool,
22 Err(e) => {
23 let err_msg = e.to_string();
24 if (err_msg.contains("1049") || err_msg.contains("Unknown database")) && cfg.db_connection == "mysql" {
25 println!("{}", "⚠️ Database tidak ditemukan. Mencoba membuat database baru...".yellow());
26
27 let root_url = format!(
28 "mysql://{}:{}@{}:{}",
29 cfg.db_username, cfg.db_password, cfg.db_host, cfg.db_port
30 );
31
32 if let Ok(pool) = sqlx::MySqlPool::connect(&root_url).await {
33 let create_query = format!("CREATE DATABASE IF NOT EXISTS `{}`", cfg.db_database);
34 if sqlx::query(&create_query).execute(&pool).await.is_ok() {
35 println!("✅ Database '{}' berhasil dibuat.", cfg.db_database.green());
36 return AnyPool::connect(&db_url).await.expect("Gagal terhubung setelah membuat database");
37 }
38 }
39 }
40 panic!("Gagal terhubung ke database: {:?}", e);
41 }
42 }
43}
44
45#[derive(Clone)]
50pub enum WhereClause {
51 Simple { column: String, operator: String, value: Value },
52 Raw { sql: String, binds: Vec<Value> },
53}
54
55#[derive(Clone)]
56pub struct OrderClause {
57 column: String,
58 direction: String,
59}
60
61#[derive(Clone)]
62pub struct QueryBuilder<'a> {
63 pool: &'a AnyPool,
64 table: String,
65 wheres: Vec<WhereClause>,
66 orders: Vec<OrderClause>,
67 limit: Option<usize>,
68}
69
70pub struct DB;
71
72impl DB {
73 pub fn table<'a>(pool: &'a AnyPool, name: &str) -> QueryBuilder<'a> {
74 QueryBuilder::new(pool, name)
75 }
76}
77
78impl<'a> QueryBuilder<'a> {
79 pub fn new(pool: &'a AnyPool, table: &str) -> Self {
80 Self {
81 pool,
82 table: table.to_string(),
83 wheres: Vec::new(),
84 orders: Vec::new(),
85 limit: None,
86 }
87 }
88
89 pub fn where_(mut self, column: &str, value: impl serde::Serialize) -> Self {
90 let val = serde_json::to_value(value).unwrap_or(Value::Null);
91 self.wheres.push(WhereClause::Simple {
92 column: column.to_string(),
93 operator: "=".to_string(),
94 value: val,
95 });
96 self
97 }
98
99 pub fn where_op(mut self, column: &str, operator: &str, value: impl serde::Serialize) -> Self {
100 let val = serde_json::to_value(value).unwrap_or(Value::Null);
101 self.wheres.push(WhereClause::Simple {
102 column: column.to_string(),
103 operator: operator.to_string(),
104 value: val,
105 });
106 self
107 }
108
109 pub fn where_raw(mut self, sql: &str, binds: Vec<Value>) -> Self {
110 self.wheres.push(WhereClause::Raw {
111 sql: sql.to_string(),
112 binds,
113 });
114 self
115 }
116
117 pub fn where_in(self, column: &str, values: Vec<impl serde::Serialize>) -> Self {
118 if values.is_empty() {
119 return self.where_raw("1 = 0", vec![]);
120 }
121 let placeholders: Vec<&str> = (0..values.len()).map(|_| "?").collect();
122 let sql = format!("`{}` IN ({})", column, placeholders.join(", "));
123 let binds: Vec<Value> = values.iter()
124 .map(|v| serde_json::to_value(v).unwrap_or(Value::Null))
125 .collect();
126 self.where_raw(&sql, binds)
127 }
128
129 pub fn pool(&self) -> &'a AnyPool {
130 self.pool
131 }
132
133
134 pub fn order_by(mut self, column: &str, direction: &str) -> Self {
135 self.orders.push(OrderClause {
136 column: column.to_string(),
137 direction: direction.to_string(),
138 });
139 self
140 }
141
142 pub fn limit(mut self, limit: usize) -> Self {
143 self.limit = Some(limit);
144 self
145 }
146
147 fn to_select_sql(&self) -> (String, Vec<Value>) {
148 let mut sql = format!("SELECT * FROM `{}`", self.table);
149 let mut binds = Vec::new();
150
151 if !self.wheres.is_empty() {
152 sql.push_str(" WHERE ");
153 let mut parts = Vec::new();
154 for w in &self.wheres {
155 match w {
156 WhereClause::Simple { column, operator, value } => {
157 parts.push(format!("`{}` {} ?", column, operator));
158 binds.push(value.clone());
159 }
160 WhereClause::Raw { sql: raw_sql, binds: raw_binds } => {
161 parts.push(raw_sql.clone());
162 binds.extend(raw_binds.clone());
163 }
164 }
165 }
166 sql.push_str(&parts.join(" AND "));
167 }
168
169 if !self.orders.is_empty() {
170 sql.push_str(" ORDER BY ");
171 let parts: Vec<String> = self.orders.iter()
172 .map(|o| format!("`{}` {}", o.column, o.direction))
173 .collect();
174 sql.push_str(&parts.join(", "));
175 }
176
177 if let Some(limit) = self.limit {
178 sql.push_str(&format!(" LIMIT {}", limit));
179 }
180
181 (sql, binds)
182 }
183
184 pub async fn first<T: DeserializeOwned>(&self) -> Result<Option<T>, sqlx::Error> {
185 let mut builder = self.clone();
186 builder.limit = Some(1);
187 let (sql, binds) = builder.to_select_sql();
188
189 let mut query = sqlx::query(&sql);
190 for b in &binds {
191 query = bind_query_json(query, b);
192 }
193
194 let row_opt = query.fetch_optional(self.pool).await?;
195 if let Some(row) = row_opt {
196 let val = row_to_json_value(&row);
197 let parsed = serde_json::from_value::<T>(val)
198 .map_err(|e| sqlx::Error::Protocol(format!("Deserialization error: {}", e)))?;
199 Ok(Some(parsed))
200 } else {
201 Ok(None)
202 }
203 }
204
205 pub async fn get<T: DeserializeOwned>(&self) -> Result<Vec<T>, sqlx::Error> {
206 let (sql, binds) = self.to_select_sql();
207
208 let mut query = sqlx::query(&sql);
209 for b in &binds {
210 query = bind_query_json(query, b);
211 }
212
213 let rows = query.fetch_all(self.pool).await?;
214 let mut result = Vec::new();
215 for row in rows {
216 let val = row_to_json_value(&row);
217 let parsed = serde_json::from_value::<T>(val)
218 .map_err(|e| sqlx::Error::Protocol(format!("Deserialization error: {}", e)))?;
219 result.push(parsed);
220 }
221 Ok(result)
222 }
223
224 pub async fn count(&self) -> Result<i64, sqlx::Error> {
225 let mut sql = format!("SELECT COUNT(*) FROM `{}`", self.table);
226 let mut binds = Vec::new();
227
228 if !self.wheres.is_empty() {
229 sql.push_str(" WHERE ");
230 let mut parts = Vec::new();
231 for w in &self.wheres {
232 match w {
233 WhereClause::Simple { column, operator, value } => {
234 parts.push(format!("`{}` {} ?", column, operator));
235 binds.push(value.clone());
236 }
237 WhereClause::Raw { sql: raw_sql, binds: raw_binds } => {
238 parts.push(raw_sql.clone());
239 binds.extend(raw_binds.clone());
240 }
241 }
242 }
243 sql.push_str(&parts.join(" AND "));
244 }
245
246 let mut query = sqlx::query(&sql);
247 for b in &binds {
248 query = bind_query_json(query, b);
249 }
250
251 let row = query.fetch_one(self.pool).await?;
252 let count_val: i64 = row.try_get(0).unwrap_or(0);
253 Ok(count_val)
254 }
255
256 pub async fn insert(&self, data: Value) -> Result<(), sqlx::Error> {
257 let obj = data.as_object().ok_or_else(|| {
258 sqlx::Error::Protocol("Data insert harus berupa JSON object".into())
259 })?;
260
261 let mut columns = Vec::new();
262 let mut placeholders = Vec::new();
263 let mut binds = Vec::new();
264
265 for (col, val) in obj {
266 columns.push(format!("`{}`", col));
267 placeholders.push("?");
268 binds.push(val.clone());
269 }
270
271 let sql = format!(
272 "INSERT INTO `{}` ({}) VALUES ({})",
273 self.table,
274 columns.join(", "),
275 placeholders.join(", ")
276 );
277
278 let mut query = sqlx::query(&sql);
279 for b in &binds {
280 query = bind_query_json(query, b);
281 }
282
283 query.execute(self.pool).await?;
284 Ok(())
285 }
286
287 pub async fn insert_get_id(&self, data: Value) -> Result<i64, sqlx::Error> {
288 let obj = data.as_object().ok_or_else(|| {
289 sqlx::Error::Protocol("Data insert harus berupa JSON object".into())
290 })?;
291
292 let mut columns = Vec::new();
293 let mut placeholders = Vec::new();
294 let mut binds = Vec::new();
295
296 for (col, val) in obj {
297 columns.push(format!("`{}`", col));
298 placeholders.push("?");
299 binds.push(val.clone());
300 }
301
302 let sql = format!(
303 "INSERT INTO `{}` ({}) VALUES ({})",
304 self.table,
305 columns.join(", "),
306 placeholders.join(", ")
307 );
308
309 let mut conn = self.pool.acquire().await?;
310
311 let mut query = sqlx::query(&sql);
312 for b in &binds {
313 query = bind_query_json(query, b);
314 }
315
316 let result = query.execute(&mut *conn).await?;
317 if let Some(id) = result.last_insert_id() {
318 if id != 0 {
319 return Ok(id);
320 }
321 }
322
323 if let Ok(row) = sqlx::query("SELECT last_insert_rowid()").fetch_one(&mut *conn).await {
325 let id: i64 = row.try_get(0).unwrap_or(0);
326 if id != 0 {
327 return Ok(id);
328 }
329 }
330
331 if let Ok(row) = sqlx::query("SELECT LAST_INSERT_ID()").fetch_one(&mut *conn).await {
333 let id: i64 = row.try_get(0).unwrap_or(0);
334 if id != 0 {
335 return Ok(id);
336 }
337 }
338
339 Ok(0)
340 }
341
342 pub async fn update(&self, data: Value) -> Result<u64, sqlx::Error> {
343 let obj = data.as_object().ok_or_else(|| {
344 sqlx::Error::Protocol("Data update harus berupa JSON object".into())
345 })?;
346
347 let mut sets = Vec::new();
348 let mut binds = Vec::new();
349
350 for (col, val) in obj {
351 sets.push(format!("`{}` = ?", col));
352 binds.push(val.clone());
353 }
354
355 let mut sql = format!("UPDATE `{}` SET {}", self.table, sets.join(", "));
356
357 if !self.wheres.is_empty() {
358 sql.push_str(" WHERE ");
359 let mut parts = Vec::new();
360 for w in &self.wheres {
361 match w {
362 WhereClause::Simple { column, operator, value } => {
363 parts.push(format!("`{}` {} ?", column, operator));
364 binds.push(value.clone());
365 }
366 WhereClause::Raw { sql: raw_sql, binds: raw_binds } => {
367 parts.push(raw_sql.clone());
368 binds.extend(raw_binds.clone());
369 }
370 }
371 }
372 sql.push_str(&parts.join(" AND "));
373 }
374
375 let mut query = sqlx::query(&sql);
376 for b in &binds {
377 query = bind_query_json(query, b);
378 }
379
380 let result = query.execute(self.pool).await?;
381 Ok(result.rows_affected())
382 }
383
384 pub async fn delete(&self) -> Result<u64, sqlx::Error> {
385 let mut sql = format!("DELETE FROM `{}`", self.table);
386 let mut binds = Vec::new();
387
388 if !self.wheres.is_empty() {
389 sql.push_str(" WHERE ");
390 let mut parts = Vec::new();
391 for w in &self.wheres {
392 match w {
393 WhereClause::Simple { column, operator, value } => {
394 parts.push(format!("`{}` {} ?", column, operator));
395 binds.push(value.clone());
396 }
397 WhereClause::Raw { sql: raw_sql, binds: raw_binds } => {
398 parts.push(raw_sql.clone());
399 binds.extend(raw_binds.clone());
400 }
401 }
402 }
403 sql.push_str(&parts.join(" AND "));
404 }
405
406 let mut query = sqlx::query(&sql);
407 for b in &binds {
408 query = bind_query_json(query, b);
409 }
410
411 let result = query.execute(self.pool).await?;
412 Ok(result.rows_affected())
413 }
414}
415
416fn bind_query_json<'q>(
421 query: sqlx::query::Query<'q, sqlx::Any, sqlx::any::AnyArguments<'q>>,
422 val: &Value,
423) -> sqlx::query::Query<'q, sqlx::Any, sqlx::any::AnyArguments<'q>> {
424 match val {
425 Value::Null => query.bind(None::<String>),
426 Value::Bool(b) => query.bind(*b),
427 Value::Number(n) => {
428 if let Some(i) = n.as_i64() {
429 query.bind(i)
430 } else if let Some(f) = n.as_f64() {
431 query.bind(f)
432 } else {
433 query.bind(0.0f64)
434 }
435 }
436 Value::String(s) => query.bind(s.clone()),
437 _ => query.bind(val.to_string()),
438 }
439}
440
441pub fn row_to_json_value(row: &sqlx::any::AnyRow) -> Value {
442 let mut map = serde_json::Map::new();
443 for i in 0..row.len() {
444 let col = row.column(i);
445 let name = col.name();
446 let val = get_json_value(row, i);
447 map.insert(name.to_string(), val);
448 }
449 Value::Object(map)
450}
451
452fn get_json_value(row: &sqlx::any::AnyRow, index: usize) -> Value {
453 let type_name = row.column(index).type_info().name();
454 if type_name == "NULL" {
455 return Value::Null;
456 }
457
458
459 if let Ok(Some(b)) = row.try_get::<Option<bool>, _>(index) {
460 return Value::Bool(b);
461 }
462
463 if let Ok(Some(i)) = row.try_get::<Option<i64>, _>(index) {
464 return Value::Number(serde_json::Number::from(i));
465 }
466
467 if let Ok(Some(f)) = row.try_get::<Option<f64>, _>(index) {
468 if let Some(num) = serde_json::Number::from_f64(f) {
469 return Value::Number(num);
470 }
471 }
472
473 if let Ok(Some(s)) = row.try_get::<Option<String>, _>(index) {
474 return Value::String(s);
475 }
476
477 Value::Null
478}