Skip to content

Commit 0ed3e47

Browse files
committed
Style
1 parent c7957b7 commit 0ed3e47

File tree

8 files changed

+261
-134
lines changed

8 files changed

+261
-134
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# SQLx PHP Extension
22

3+
[![CI](https://github.com/kakserpom/php-sqlx-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/kakserpom/php-sqlx-rs/actions/workflows/ci.yml)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5+
[![PHP 8.2+](https://img.shields.io/badge/PHP-8.2%2B-8892BF.svg)](https://php.net)
6+
[![Rust](https://img.shields.io/badge/Rust-stable-orange.svg)](https://rust-lang.org)
7+
38
The extension is powered by Rust 🦀 and [SQLx](https://github.com/launchbadge/sqlx), built
49
using [ext-php-rs](https://github.com/davidcole1340/ext-php-rs). It enables safe, fast, and expressive
510
database access with additional SQL syntax. It comes with a powerful [query builder](QUERY-BUILDER.md).

docker-compose.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
version: '3.8'
2+
3+
services:
4+
postgres:
5+
image: postgres:16-alpine
6+
environment:
7+
POSTGRES_USER: postgres
8+
POSTGRES_PASSWORD: postgres
9+
POSTGRES_DB: test_db
10+
ports:
11+
- "15432:5432"
12+
healthcheck:
13+
test: ["CMD-SHELL", "pg_isready -U postgres"]
14+
interval: 5s
15+
timeout: 5s
16+
retries: 5
17+
18+
mysql:
19+
image: mysql:8.0
20+
environment:
21+
MYSQL_ROOT_PASSWORD: root
22+
MYSQL_DATABASE: test_db
23+
ports:
24+
- "3306:3306"
25+
healthcheck:
26+
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
27+
interval: 5s
28+
timeout: 5s
29+
retries: 5
30+
31+
mssql:
32+
image: mcr.microsoft.com/azure-sql-edge:latest
33+
platform: linux/arm64
34+
environment:
35+
ACCEPT_EULA: Y
36+
MSSQL_SA_PASSWORD: TestPassword123!
37+
ports:
38+
- "1433:1433"
39+
healthcheck:
40+
test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'TestPassword123!' -Q 'SELECT 1' || exit 1"]
41+
interval: 10s
42+
timeout: 5s
43+
retries: 10

src/ast/mod.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,10 +1103,7 @@ impl Ast {
11031103
}
11041104
// Wrap Array/Object in Json when ?j placeholder is used
11051105
if *expected_type == Some(PlaceholderType::Json)
1106-
&& matches!(
1107-
val,
1108-
ParameterValue::Array(_) | ParameterValue::Object(_)
1109-
)
1106+
&& matches!(val, ParameterValue::Array(_) | ParameterValue::Object(_))
11101107
{
11111108
ParameterValue::Json(Box::new(val.clone()))
11121109
.write_sql_to(sql, out_vals, settings)?;

src/inner_driver.rs

Lines changed: 129 additions & 97 deletions
Large diffs are not rendered by default.

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ pub mod utils;
6262

6363
use dbms::{mssql, mysql, postgres};
6464
use ext_php_rs::prelude::*;
65-
use std::time::Duration;
65+
pub use inner_driver::RetryPolicy;
6666
#[cfg(feature = "lazy-row")]
6767
pub use lazy_row::{LazyRow, LazyRowJson};
68-
pub use inner_driver::RetryPolicy;
6968
use std::num::NonZeroU32;
7069
use std::sync::LazyLock;
70+
use std::time::Duration;
7171
use tokio::runtime::Runtime;
7272

7373
/// Global Tokio runtime for executing async `SQLx` queries from synchronous PHP context.

src/options.rs

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ impl ReplicaConfig {
6767
/// Creates a new replica config with the given URL and weight.
6868
#[must_use]
6969
pub fn with_weight(url: String, weight: u32) -> Self {
70-
Self { url, weight: weight.max(1) }
70+
Self {
71+
url,
72+
weight: weight.max(1),
73+
}
7174
}
7275
}
7376

@@ -421,7 +424,9 @@ impl DriverOptionsArg {
421424
_ => {
422425
return Err(SqlxError::config(
423426
"read_replicas",
424-
format!("element at index {i}: 'weight' must be an integer"),
427+
format!(
428+
"element at index {i}: 'weight' must be an integer"
429+
),
425430
));
426431
}
427432
};
@@ -430,7 +435,9 @@ impl DriverOptionsArg {
430435
_ => {
431436
return Err(SqlxError::config(
432437
"read_replicas",
433-
format!("element at index {i} must be a string or ['url' => ..., 'weight' => ...]"),
438+
format!(
439+
"element at index {i} must be a string or ['url' => ..., 'weight' => ...]"
440+
),
434441
));
435442
}
436443
}
@@ -461,9 +468,7 @@ impl DriverOptionsArg {
461468
None | Some(ParameterValue::Null) => DEFAULT_RETRY_INITIAL_BACKOFF,
462469
Some(ParameterValue::String(value)) => parse_duration::parse(value)
463470
.map_err(|e| SqlxError::config("retry_initial_backoff", e.to_string()))?,
464-
Some(ParameterValue::Int(value)) => {
465-
Duration::from_secs(u64::try_from(*value)?)
466-
}
471+
Some(ParameterValue::Int(value)) => Duration::from_secs(u64::try_from(*value)?),
467472
_ => {
468473
return Err(SqlxError::config(
469474
"retry_initial_backoff",
@@ -475,9 +480,7 @@ impl DriverOptionsArg {
475480
None | Some(ParameterValue::Null) => DEFAULT_RETRY_MAX_BACKOFF,
476481
Some(ParameterValue::String(value)) => parse_duration::parse(value)
477482
.map_err(|e| SqlxError::config("retry_max_backoff", e.to_string()))?,
478-
Some(ParameterValue::Int(value)) => {
479-
Duration::from_secs(u64::try_from(*value)?)
480-
}
483+
Some(ParameterValue::Int(value)) => Duration::from_secs(u64::try_from(*value)?),
481484
_ => {
482485
return Err(SqlxError::config(
483486
"retry_max_backoff",
@@ -491,10 +494,7 @@ impl DriverOptionsArg {
491494
ParameterValue::Float(f) => Ok(*f),
492495
#[allow(clippy::cast_precision_loss)]
493496
ParameterValue::Int(n) => Ok(*n as f64),
494-
_ => Err(SqlxError::config(
495-
"retry_multiplier",
496-
"must be a number",
497-
)),
497+
_ => Err(SqlxError::config("retry_multiplier", "must be a number")),
498498
},
499499
)?,
500500
},
@@ -547,7 +547,10 @@ mod tests {
547547
#[test]
548548
fn test_read_replicas_simple_strings() {
549549
let driver_options = DriverOptionsArg::Options(BTreeMap::from_iter([
550-
(DriverOptions::OPT_URL.into(), "postgres://primary/db".into()),
550+
(
551+
DriverOptions::OPT_URL.into(),
552+
"postgres://primary/db".into(),
553+
),
551554
(
552555
DriverOptions::OPT_READ_REPLICAS.into(),
553556
ParameterValue::Array(vec![
@@ -560,16 +563,25 @@ mod tests {
560563
.unwrap();
561564

562565
assert_eq!(driver_options.read_replicas.len(), 2);
563-
assert_eq!(driver_options.read_replicas[0].url, "postgres://replica1/db");
566+
assert_eq!(
567+
driver_options.read_replicas[0].url,
568+
"postgres://replica1/db"
569+
);
564570
assert_eq!(driver_options.read_replicas[0].weight, 1);
565-
assert_eq!(driver_options.read_replicas[1].url, "postgres://replica2/db");
571+
assert_eq!(
572+
driver_options.read_replicas[1].url,
573+
"postgres://replica2/db"
574+
);
566575
assert_eq!(driver_options.read_replicas[1].weight, 1);
567576
}
568577

569578
#[test]
570579
fn test_read_replicas_with_weights() {
571580
let driver_options = DriverOptionsArg::Options(BTreeMap::from_iter([
572-
(DriverOptions::OPT_URL.into(), "postgres://primary/db".into()),
581+
(
582+
DriverOptions::OPT_URL.into(),
583+
"postgres://primary/db".into(),
584+
),
573585
(
574586
DriverOptions::OPT_READ_REPLICAS.into(),
575587
ParameterValue::Array(vec![
@@ -588,16 +600,25 @@ mod tests {
588600
.unwrap();
589601

590602
assert_eq!(driver_options.read_replicas.len(), 2);
591-
assert_eq!(driver_options.read_replicas[0].url, "postgres://replica1/db");
603+
assert_eq!(
604+
driver_options.read_replicas[0].url,
605+
"postgres://replica1/db"
606+
);
592607
assert_eq!(driver_options.read_replicas[0].weight, 3);
593-
assert_eq!(driver_options.read_replicas[1].url, "postgres://replica2/db");
608+
assert_eq!(
609+
driver_options.read_replicas[1].url,
610+
"postgres://replica2/db"
611+
);
594612
assert_eq!(driver_options.read_replicas[1].weight, 1);
595613
}
596614

597615
#[test]
598616
fn test_read_replicas_mixed_format() {
599617
let driver_options = DriverOptionsArg::Options(BTreeMap::from_iter([
600-
(DriverOptions::OPT_URL.into(), "postgres://primary/db".into()),
618+
(
619+
DriverOptions::OPT_URL.into(),
620+
"postgres://primary/db".into(),
621+
),
601622
(
602623
DriverOptions::OPT_READ_REPLICAS.into(),
603624
ParameterValue::Array(vec![
@@ -620,7 +641,10 @@ mod tests {
620641
#[test]
621642
fn test_read_replicas_default_weight_when_missing() {
622643
let driver_options = DriverOptionsArg::Options(BTreeMap::from_iter([
623-
(DriverOptions::OPT_URL.into(), "postgres://primary/db".into()),
644+
(
645+
DriverOptions::OPT_URL.into(),
646+
"postgres://primary/db".into(),
647+
),
624648
(
625649
DriverOptions::OPT_READ_REPLICAS.into(),
626650
ParameterValue::Array(vec![ParameterValue::Object(BTreeMap::from_iter([(
@@ -638,7 +662,10 @@ mod tests {
638662
#[test]
639663
fn test_read_replicas_empty_array() {
640664
let driver_options = DriverOptionsArg::Options(BTreeMap::from_iter([
641-
(DriverOptions::OPT_URL.into(), "postgres://primary/db".into()),
665+
(
666+
DriverOptions::OPT_URL.into(),
667+
"postgres://primary/db".into(),
668+
),
642669
(
643670
DriverOptions::OPT_READ_REPLICAS.into(),
644671
ParameterValue::Array(vec![]),
@@ -653,7 +680,10 @@ mod tests {
653680
#[test]
654681
fn test_read_replicas_missing_url_error() {
655682
let result = DriverOptionsArg::Options(BTreeMap::from_iter([
656-
(DriverOptions::OPT_URL.into(), "postgres://primary/db".into()),
683+
(
684+
DriverOptions::OPT_URL.into(),
685+
"postgres://primary/db".into(),
686+
),
657687
(
658688
DriverOptions::OPT_READ_REPLICAS.into(),
659689
ParameterValue::Array(vec![ParameterValue::Object(BTreeMap::from_iter([(

src/param_value/conversion.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ impl IntoZval for ParameterValue {
6969
}
7070
zv.set_hashtable(ht);
7171
}
72-
Self::DateTime(dt) => zv.set_string(&dt.format("%Y-%m-%d %H:%M:%S").to_string(), persistent)?,
72+
Self::DateTime(dt) => {
73+
zv.set_string(&dt.format("%Y-%m-%d %H:%M:%S").to_string(), persistent)?
74+
}
7375
Self::Null
7476
| Self::ByClauseRendered(_)
7577
| Self::SelectClauseRendered(_)
@@ -164,18 +166,29 @@ impl FromZval<'_> for ParameterValue {
164166
let result = obj.try_call_method("format", vec![&format_arg]).ok()?;
165167
let datetime_str = result.string()?;
166168
// Parse into NaiveDateTime for proper database binding
167-
let ndt = chrono::NaiveDateTime::parse_from_str(&datetime_str, "%Y-%m-%d %H:%M:%S").ok()?;
169+
let ndt = chrono::NaiveDateTime::parse_from_str(
170+
&datetime_str,
171+
"%Y-%m-%d %H:%M:%S",
172+
)
173+
.ok()?;
168174
Some(Self::DateTime(ndt))
169175
}
170176
other => {
171177
// For other classes, try calling format() method if it exists
172178
// This handles custom DateTimeInterface implementations
173-
if other.contains("DateTime") || other.ends_with("Date") || other.ends_with("Time") {
179+
if other.contains("DateTime")
180+
|| other.ends_with("Date")
181+
|| other.ends_with("Time")
182+
{
174183
let mut format_arg = Zval::new();
175184
if format_arg.set_string("Y-m-d H:i:s", false).is_ok() {
176-
if let Ok(result) = obj.try_call_method("format", vec![&format_arg]) {
185+
if let Ok(result) = obj.try_call_method("format", vec![&format_arg])
186+
{
177187
if let Some(datetime_str) = result.string() {
178-
if let Ok(ndt) = chrono::NaiveDateTime::parse_from_str(&datetime_str, "%Y-%m-%d %H:%M:%S") {
188+
if let Ok(ndt) = chrono::NaiveDateTime::parse_from_str(
189+
&datetime_str,
190+
"%Y-%m-%d %H:%M:%S",
191+
) {
179192
return Some(Self::DateTime(ndt));
180193
}
181194
}
@@ -211,7 +224,9 @@ impl Serialize for ParameterValue {
211224
Self::Int(i) => serializer.serialize_i64(*i),
212225
Self::Float(f) => serializer.serialize_f64(*f),
213226
Self::Bool(b) => serializer.serialize_bool(*b),
214-
Self::DateTime(dt) => serializer.serialize_str(&dt.format("%Y-%m-%d %H:%M:%S").to_string()),
227+
Self::DateTime(dt) => {
228+
serializer.serialize_str(&dt.format("%Y-%m-%d %H:%M:%S").to_string())
229+
}
215230

216231
Self::Array(arr) => {
217232
let mut seq = serializer.serialize_seq(Some(arr.len()))?;

src/param_value/quote.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ impl ParameterValue {
112112

113113
Self::String(s) => escape_sql_string(s, settings),
114114

115-
Self::DateTime(dt) => escape_sql_string(&dt.format("%Y-%m-%d %H:%M:%S").to_string(), settings),
115+
Self::DateTime(dt) => {
116+
escape_sql_string(&dt.format("%Y-%m-%d %H:%M:%S").to_string(), settings)
117+
}
116118

117119
Self::Array(values) => {
118120
let elements = values
@@ -267,7 +269,10 @@ mod tests {
267269
..Settings::default()
268270
};
269271
assert_eq!(super::quote_identifier("user", &settings), "\"user\"");
270-
assert_eq!(super::quote_identifier("my\"col", &settings), "\"my\"\"col\"");
272+
assert_eq!(
273+
super::quote_identifier("my\"col", &settings),
274+
"\"my\"\"col\""
275+
);
271276
}
272277

273278
#[test]

0 commit comments

Comments
 (0)