1#![warn(missing_docs)]
4
5use crate::{
10 CRS, E, Expression, MyError, QString,
11 config::config,
12 ds::{DataSource, sql::MIN_DATE_SQL},
13 op::Op,
14};
15use sqlx::{AssertSqlSafe, FromRow, Pool, Sqlite, pool::PoolOptions, sqlite::SqliteConnectOptions};
16use std::{cmp::Ordering, str::FromStr};
17use tracing::{debug, info};
18use unicode_normalization::{UnicodeNormalization, char::is_combining_mark};
19
20const GPKG_APPLICATION_ID: i32 = 0x47504B47;
21const FIND_TABLE: &str = "SELECT * FROM gpkg_contents WHERE table_name = $1";
22const FIND_SRS: &str = "SELECT * FROM gpkg_spatial_ref_sys WHERE srs_id = $1";
23const EPSG_AUTH: &str = "EPSG";
24
25const CQL2_CI: &str = "CQL2_CI";
27const CQL2_AI: &str = "CQL2_AI";
29const CQL2_CAI: &str = "CQL2_CI_AI";
31
32#[derive(Debug, FromRow)]
34struct Pragma(String);
35
36#[derive(Debug, FromRow)]
39struct RowID(i32);
40
41#[derive(Debug, FromRow)]
43struct TSpatialRefSys {
44 organization: String,
45 organization_coordsys_id: i32,
46}
47
48#[allow(dead_code)]
50#[derive(Debug, FromRow)]
51pub(crate) struct TContents {
52 table_name: String,
53 data_type: String,
54 srs_id: Option<i32>,
55}
56
57#[derive(Debug)]
60#[allow(dead_code)]
61pub struct GPkgDataSource {
62 layer: String,
63 pool: Pool<Sqlite>,
64 srid: Option<u32>,
65}
66
67impl DataSource for GPkgDataSource {
68 fn srid(&self) -> Option<u32> {
69 self.srid
70 }
71}
72
73impl GPkgDataSource {
74 pub async fn from(gpkg_url: &str, layer_name: &str) -> Result<Self, MyError> {
76 let collate_ci = |a: &str, b: &str| cmp_ci(a, b);
82
83 let collate_ai = |a: &str, b: &str| cmp_ai(a, b);
85
86 let collate_aci = |a: &str, b: &str| cmp_aci(a, b);
88
89 let pool_opts = unsafe {
93 SqliteConnectOptions::from_str(gpkg_url)?
94 .extension("mod_spatialite")
95 .collation(CQL2_CI, collate_ci)
96 .collation(CQL2_AI, collate_ai)
97 .collation(CQL2_CAI, collate_aci)
98 };
99
100 let pool = PoolOptions::new().connect_with(pool_opts).await?;
101
102 let pragma = sqlx::query_as::<_, RowID>("PRAGMA application_id")
105 .fetch_one(&pool)
106 .await?;
107 let application_id = pragma.0;
108 if application_id != GPKG_APPLICATION_ID {
109 return Err(MyError::Runtime("Unexpected application_id".into()));
110 }
111
112 let pragma = sqlx::query_as::<_, Pragma>("PRAGMA integrity_check")
114 .fetch_one(&pool)
115 .await?;
116 if pragma.0 != "ok" {
117 return Err(MyError::Runtime("Failed integrity_check".into()));
118 }
119
120 let fk_values: Vec<_> = sqlx::query("PRAGMA foreign_key_check")
122 .fetch_all(&pool)
123 .await?;
124 if !fk_values.is_empty() {
125 return Err(MyError::Runtime("Found invalid FK value(s)".into()));
126 }
127
128 let layer = sqlx::query_as::<_, TContents>(FIND_TABLE)
130 .bind(layer_name)
131 .fetch_one(&pool)
132 .await?;
133 if layer.data_type != "features" {
135 return Err(MyError::Runtime("Layer is NOT vector-based".into()));
136 }
137
138 let sql = format!(
140 r#"CREATE VIRTUAL TABLE IF NOT EXISTS "vgpkg_{0}" USING VirtualGPKG("{0}");"#,
141 layer_name
142 );
143 let safe_sql = AssertSqlSafe(sql);
144 sqlx::query(safe_sql).execute(&pool).await?;
145
146 let srid = match layer.srs_id {
147 Some(fk) => match fk {
153 -1 => {
154 info!("GeoPackage uses the undefined Cartesian SRS");
155 None
156 }
157 0 => {
158 info!("GeoPackage uses the undefined geographic SRS");
159 None
160 }
161 x => {
162 let srs = sqlx::query_as::<_, TSpatialRefSys>(FIND_SRS)
167 .bind(x)
168 .fetch_one(&pool)
169 .await?;
170 let authority = srs.organization;
172 if !authority.eq_ignore_ascii_case(EPSG_AUTH) {
173 return Err(MyError::Runtime(
174 format!("Unexpected ({authority}) Authority").into(),
175 ));
176 }
177
178 let it = srs.organization_coordsys_id;
179 let epsg_code = format!("{authority}:{x}");
180 let _ = CRS::new(&epsg_code)?;
182 Some(u32::try_from(it)?)
183 }
184 },
185 None => None,
186 };
187 debug!("srid = {srid:?}");
188
189 Ok(Self {
190 layer: layer_name.to_owned(),
191 pool,
192 srid,
193 })
194 }
195
196 pub fn pool(&self) -> &Pool<Sqlite> {
198 &self.pool
199 }
200
201 pub fn vtable(&self) -> String {
207 format!("vgpkg_{}", self.layer)
208 }
209
210 pub fn to_sql(&self, exp: &Expression) -> Result<String, MyError> {
213 let mut e = exp.to_inner()?;
214 let it = E::reduce(&mut e)?;
215 let res = self.to_sql_impl(it);
216 debug!("to_sql: {res:?}");
217 res
218 }
219
220 fn to_sql_impl(&self, exp: E) -> Result<String, MyError> {
221 match exp {
222 E::Null => Ok("NULL".to_owned()),
223 E::Unbounded => Ok(MIN_DATE_SQL.to_owned()),
224 E::Bool(true) => Ok("TRUE".to_owned()),
225 E::Bool(false) => Ok("FALSE".to_owned()),
226 E::Num(x) => Ok(x.to_string()),
227 E::Str(x) => qstr_to_sql(x),
228 E::Date(x) => Ok(format!("'{}'", x.date())),
229 E::Timestamp(x) => Ok(format!("'{}'", x.datetime())),
230 E::Spatial(x) => Ok(x.to_sql()?),
231 E::Id(x) => Ok(x.to_owned()),
232 E::Monadic(op, x) if op.nullable() => {
234 let is_literal = x.is_literal_or_id();
235 let lhs = self.to_sql_impl(*x)?;
236 let z_op = op.to_sql();
237 if is_literal {
238 Ok(format!("{lhs} {z_op}"))
239 } else {
240 Ok(format!("({lhs}) {z_op}"))
241 }
242 }
243 E::Monadic(op, x) => match op {
244 Op::Neg | Op::Minus => {
245 let is_literal = x.is_literal_or_id();
246 let rhs = self.to_sql_impl(*x)?;
247 let z_op = op.to_sql();
248 if is_literal {
249 Ok(format!("{z_op} {rhs}"))
250 } else {
251 Ok(format!("{z_op} ({rhs})"))
252 }
253 }
254 Op::CaseI => match *x {
255 E::Monadic(Op::AccentI, y) => {
256 let rhs = self.to_sql_impl(*y)?;
257 Ok(format!("{rhs} COLLATE {CQL2_CAI}"))
258 }
259 _ => {
260 let rhs = self.to_sql_impl(*x)?;
261 Ok(format!("{rhs} COLLATE {CQL2_CI}"))
262 }
263 },
264 Op::AccentI => match *x {
265 E::Monadic(Op::CaseI, y) => {
266 let rhs = self.to_sql_impl(*y)?;
267 Ok(format!("{rhs} COLLATE {CQL2_CAI}"))
268 }
269 _ => {
270 let rhs = self.to_sql_impl(*x)?;
271 Ok(format!("{rhs} COLLATE {CQL2_AI}"))
272 }
273 },
274 x => unreachable!("Unexpected ({x}) monadic operator"),
275 },
276 E::Dyadic(op, a, b)
277 if matches!(op, Op::IsBetween) || matches!(op, Op::IsNotBetween) =>
278 {
279 match *b {
281 E::Array(rhs) => {
282 let z_op = op.to_sql();
283 let lhs = self.to_sql_impl(*a)?;
284 let lo = self.to_sql_impl(rhs[0].to_owned())?;
285 let hi = self.to_sql_impl(rhs[1].to_owned())?;
286 Ok(format!("{lhs} {z_op} {lo} AND {hi}"))
287 }
288 _ => unreachable!("Expetced [NOT] BETWEEN's RHS expression to be an array"),
289 }
290 }
291 E::Dyadic(op, a, b) if op.spatial() => match op {
292 Op::SWithin | Op::SOverlaps | Op::STouches => self.reduce_precision(op, *a, *b),
293 _ => {
294 let lhs = self.to_sql_impl(*a)?;
295 let rhs = self.to_sql_impl(*b)?;
296 let z_op = op.to_sql();
297 Ok(format!("{z_op}({lhs}, {rhs})"))
298 }
299 },
300 E::Dyadic(op, a, b) if op.temporal() => match op {
301 Op::TAfter => self.t_after_sql(*a, *b),
302 Op::TBefore => self.t_before_sql(*a, *b),
303 Op::TDisjoint => self.t_disjoint_sql(*a, *b),
304 Op::TEquals => self.t_equals_sql(*a, *b),
305 Op::TIntersects => self.t_intersects_sql(*a, *b),
306
307 Op::TContains => self.t_contains_sql(*a, *b),
308 Op::TDuring => self.t_during_sql(*a, *b),
309 Op::TFinishedBy => self.t_finished_by_sql(*a, *b),
310 Op::TFinishes => self.t_finishes_sql(*a, *b),
311 Op::TMeets => self.t_meets_sql(*a, *b),
312 Op::TMetBy => self.t_met_by_sql(*a, *b),
313 Op::TOverlappedBy => self.t_overlapped_by_sql(*a, *b),
314 Op::TOverlaps => self.t_overlaps_sql(*a, *b),
315 Op::TStartedBy => self.t_started_by_sql(*a, *b),
316 Op::TStarts => self.t_starts_sql(*a, *b),
317 x => unreachable!("Unexpected ({x:?}) operator"),
318 },
319 E::Dyadic(op, a, b) if op.array() => {
320 let z_op = op.to_sql();
321 let lhs = self.to_sql_impl(*a)?;
322 let rhs = self.to_sql_impl(*b)?;
323 Ok(format!("{lhs} {z_op} {rhs}"))
324 }
325 E::Dyadic(op, a, b) if matches!(op, Op::IsLike) || matches!(op, Op::IsNotLike) => {
326 let a_is_literal = a.is_literal_or_id();
327 let lhs = self.to_sql_impl(*a)?;
328 let rhs = self.to_sql_impl(*b)?;
329 let z_op = op.to_sql();
330 match a_is_literal {
331 true => Ok(format!("{lhs} {z_op} ({rhs})")),
332 false => Ok(format!("({lhs}) {z_op} ({rhs})")),
333 }
334 }
335 E::Dyadic(op, a, b) => {
336 let a_is_literal = a.is_literal_or_id();
337 let b_is_literal = b.is_literal_or_id();
338 let lhs = self.to_sql_impl(*a)?;
339 let rhs = self.to_sql_impl(*b)?;
340 let z_op = op.to_sql();
341 match (a_is_literal, b_is_literal) {
342 (true, true) => Ok(format!("{lhs} {z_op} {rhs}")),
343 (true, false) => Ok(format!("{lhs} {z_op} ({rhs})")),
344 (false, true) => Ok(format!("({lhs}) {z_op} {rhs}")),
345 (false, false) => Ok(format!("({lhs}) {z_op} ({rhs})")),
346 }
347 }
348 E::Function(x) => {
349 let params: Result<Vec<String>, MyError> =
350 x.params.into_iter().map(|x| self.to_sql_impl(x)).collect();
351 let params_ = params?;
352 Ok(format!("{}({})", x.name, params_.join(", ")))
353 }
354 E::Array(x) => {
357 let items: Result<Vec<String>, MyError> =
358 x.into_iter().map(|x| self.to_sql_impl(x)).collect();
359 let items_ = items?;
360 Ok(format!("({})", items_.join(", ")))
361 }
362 x => unreachable!("{x:?} cannot be translated to SQL"),
363 }
364 }
365
366 fn reduce_precision(&self, op: Op, a: E, b: E) -> Result<String, MyError> {
375 let a_is_id = a.is_id();
376 let b_is_id = b.is_id();
377 let (lhs, rhs) = match (a_is_id, b_is_id) {
378 (true, false) => {
379 let lhs = self.reduce_precision_sql(a)?;
380 let rhs = self.to_sql_impl(b)?;
381 (lhs, rhs)
382 }
383 (false, true) => {
384 let lhs = self.to_sql_impl(a)?;
385 let rhs = self.reduce_precision_sql(b)?;
386 (lhs, rhs)
387 }
388 _ => {
389 let lhs = self.to_sql_impl(a)?;
390 let rhs = self.to_sql_impl(b)?;
391 (lhs, rhs)
392 }
393 };
394 let z_op = op.to_sql();
395 Ok(format!("{z_op}({lhs}, {rhs})"))
396 }
397
398 fn reduce_precision_sql(&self, a: E) -> Result<String, MyError> {
399 let it = format!(
400 "ST_ReducePrecision({}, 1E-{})",
401 self.to_sql_impl(a)?,
402 config().default_precision()
403 );
404 Ok(it)
405 }
406
407 fn t_after_sql(&self, a: E, b: E) -> Result<String, MyError> {
409 let (a_is_interval, b_is_interval, e0, e1, e2, e3) = crate::unfold_expressions!(a, b);
410 match (a_is_interval, b_is_interval) {
411 (false, false) => Ok(format!(
412 "{} > {}",
413 self.to_sql_impl(e0)?,
414 self.to_sql_impl(e2)?
415 )),
416 (false, true) => {
418 let base = format!("{} > {}", self.to_sql_impl(e0)?, self.to_sql_impl(e3)?);
419 let sql = crate::check_ids!(e2, base);
420 Ok(sql)
421 }
422 (true, false) => {
423 let base = format!("{} > {}", self.to_sql_impl(e0)?, self.to_sql_impl(e2)?);
424 let sql = crate::check_ids!(e1, base);
425 Ok(sql)
426 }
427 (true, true) => {
428 let base = format!("{} > {}", self.to_sql_impl(e0)?, self.to_sql_impl(e3)?);
429 let sql = crate::check_ids!(e1, e2, base);
430 Ok(sql)
431 }
432 }
433 }
434
435 fn t_before_sql(&self, a: E, b: E) -> Result<String, MyError> {
436 let (a_is_interval, b_is_interval, e0, e1, e2, e3) = crate::unfold_expressions!(a, b);
437 match (a_is_interval, b_is_interval) {
438 (false, false) => Ok(format!(
439 "{} < {}",
440 self.to_sql_impl(e0)?,
441 self.to_sql_impl(e2)?
442 )),
443 (false, true) => {
444 let base = format!("{} < {}", self.to_sql_impl(e0)?, self.to_sql_impl(e2)?);
445 let sql = crate::check_ids!(e3, base);
446 Ok(sql)
447 }
448 (true, false) => {
449 let base = format!("{} < {}", self.to_sql_impl(e1)?, self.to_sql_impl(e2)?);
450 let sql = crate::check_ids!(e0, base);
451 Ok(sql)
452 }
453 (true, true) => {
454 let base = format!("{} < {}", self.to_sql_impl(e1)?, self.to_sql_impl(e2)?);
455 let sql = crate::check_ids!(e0, e3, base);
456 Ok(sql)
457 }
458 }
459 }
460
461 fn t_disjoint_sql(&self, a: E, b: E) -> Result<String, MyError> {
462 let (a_is_interval, b_is_interval, e0, e1, e2, e3) = crate::unfold_expressions!(a, b);
463 match (a_is_interval, b_is_interval) {
464 (false, false) => Ok(format!(
465 "{} != {}",
466 self.to_sql_impl(e0)?,
467 self.to_sql_impl(e2)?
468 )),
469 (false, true) => {
470 let e2_ = e2.clone();
471 let e3_ = e3.clone();
472 let s0 = self.to_sql_impl(e0)?;
473 let s2 = self.to_sql_impl(e2)?;
474 let s3 = self.to_sql_impl(e3)?;
475 let base1 = format!("{s0} < {s2}");
476 let sql1 = crate::check_ids!(e3_, base1);
477 let base2 = format!("{s0} > {s3}");
478 let sql2 = crate::check_ids!(e2_, base2);
479 Ok(format!("({sql1}) OR ({sql2})"))
480 }
481 (true, false) => {
482 let e0_ = e0.clone();
483 let e1_ = e1.clone();
484 let s0 = self.to_sql_impl(e0)?;
485 let s1 = self.to_sql_impl(e1)?;
486 let s2 = self.to_sql_impl(e2)?;
487 let base1 = format!("{s1} < {s2}");
488 let sql1 = crate::check_ids!(e0_, base1);
489 let base2 = format!("{s0} > {s2}");
490 let sql2 = crate::check_ids!(e1_, base2);
491 Ok(format!("({sql1}) OR ({sql2})"))
492 }
493 (true, true) => {
494 let e0_ = e0.clone();
495 let e1_ = e1.clone();
496 let e2_ = e2.clone();
497 let e3_ = e3.clone();
498 let s0 = self.to_sql_impl(e0)?;
499 let s1 = self.to_sql_impl(e1)?;
500 let s2 = self.to_sql_impl(e2)?;
501 let s3 = self.to_sql_impl(e3)?;
502 let base1 = format!("{s1} < {s2}");
503 let sql1 = crate::check_ids!(e0_, e3_, base1);
504 let base2 = format!("{s0} > {s3}");
505 let sql2 = crate::check_ids!(e1_, e2_, base2);
506 Ok(format!("({sql1}) OR ({sql2})"))
507 }
508 }
509 }
510
511 fn t_equals_sql(&self, a: E, b: E) -> Result<String, MyError> {
512 let (a_is_interval, b_is_interval, e0, e1, e2, e3) = crate::unfold_expressions!(a, b);
513 match (a_is_interval, b_is_interval) {
514 (false, false) => Ok(format!(
515 "{} = {}",
516 self.to_sql_impl(e0)?,
517 self.to_sql_impl(e2)?
518 )),
519 (false, true) => Ok(format!(
520 "({0} = {1}) AND ({0} = {2})",
521 self.to_sql_impl(e0)?,
522 self.to_sql_impl(e2)?,
523 self.to_sql_impl(e3)?
524 )),
525 (true, false) => Ok(format!(
526 "({0} = {2}) AND ({1} = {2})",
527 self.to_sql_impl(e0)?,
528 self.to_sql_impl(e1)?,
529 self.to_sql_impl(e2)?
530 )),
531 (true, true) => Ok(format!(
532 "({0} = {2}) AND ({1} = {3})",
533 self.to_sql_impl(e0)?,
534 self.to_sql_impl(e1)?,
535 self.to_sql_impl(e2)?,
536 self.to_sql_impl(e3)?
537 )),
538 }
539 }
540
541 fn t_intersects_sql(&self, a: E, b: E) -> Result<String, MyError> {
542 let (a_is_interval, b_is_interval, e0, e1, e2, e3) = crate::unfold_expressions!(a, b);
543 match (a_is_interval, b_is_interval) {
544 (false, false) => Ok(format!(
545 "{} = {}",
546 self.to_sql_impl(e0)?,
547 self.to_sql_impl(e2)?
548 )),
549 (false, true) => Ok(format!(
550 "NOT(({0} < {1}) OR ({0} > {2}))",
551 self.to_sql_impl(e0)?,
552 self.to_sql_impl(e2)?,
553 self.to_sql_impl(e3)?
554 )),
555 (true, false) => Ok(format!(
556 "NOT(({1} < {2}) OR ({0} > {2}))",
557 self.to_sql_impl(e0)?,
558 self.to_sql_impl(e1)?,
559 self.to_sql_impl(e2)?
560 )),
561 (true, true) => Ok(format!(
562 "NOT(({1} < {2}) OR ({0} > {3}))",
563 self.to_sql_impl(e0)?,
564 self.to_sql_impl(e1)?,
565 self.to_sql_impl(e2)?,
566 self.to_sql_impl(e3)?
567 )),
568 }
569 }
570
571 fn t_contains_sql(&self, a: E, b: E) -> Result<String, MyError> {
573 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
574 Ok(format!(
575 "({0} < {2}) AND ({1} > {3})",
576 self.to_sql_impl(e0)?,
577 self.to_sql_impl(e1)?,
578 self.to_sql_impl(e2)?,
579 self.to_sql_impl(e3)?
580 ))
581 }
582
583 fn t_during_sql(&self, a: E, b: E) -> Result<String, MyError> {
584 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
585 Ok(format!(
586 "({0} > {2}) AND ({1} < {3})",
587 self.to_sql_impl(e0)?,
588 self.to_sql_impl(e1)?,
589 self.to_sql_impl(e2)?,
590 self.to_sql_impl(e3)?
591 ))
592 }
593
594 fn t_finished_by_sql(&self, a: E, b: E) -> Result<String, MyError> {
595 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
596 Ok(format!(
597 "({0} < {2}) AND ({1} = {3})",
598 self.to_sql_impl(e0)?,
599 self.to_sql_impl(e1)?,
600 self.to_sql_impl(e2)?,
601 self.to_sql_impl(e3)?
602 ))
603 }
604
605 fn t_finishes_sql(&self, a: E, b: E) -> Result<String, MyError> {
606 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
607 Ok(format!(
608 "({0} > {2}) AND ({1} = {3})",
609 self.to_sql_impl(e0)?,
610 self.to_sql_impl(e1)?,
611 self.to_sql_impl(e2)?,
612 self.to_sql_impl(e3)?
613 ))
614 }
615
616 fn t_meets_sql(&self, a: E, b: E) -> Result<String, MyError> {
617 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
618 let base = format!("{0} = {1}", self.to_sql_impl(e1)?, self.to_sql_impl(e2)?);
619 let sql = crate::check_ids!(e0, e3, base);
620 Ok(sql)
621 }
622
623 fn t_met_by_sql(&self, a: E, b: E) -> Result<String, MyError> {
624 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
625 let base = format!("{0} = {1}", self.to_sql_impl(e0)?, self.to_sql_impl(e3)?);
626 let sql = crate::check_ids!(e1, e2, base);
627 Ok(sql)
628 }
629
630 fn t_overlapped_by_sql(&self, a: E, b: E) -> Result<String, MyError> {
631 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
632 Ok(format!(
633 "({0} > {2}) AND ({0} < {3}) AND ({1} > {3})",
634 self.to_sql_impl(e0)?,
635 self.to_sql_impl(e1)?,
636 self.to_sql_impl(e2)?,
637 self.to_sql_impl(e3)?
638 ))
639 }
640
641 fn t_overlaps_sql(&self, a: E, b: E) -> Result<String, MyError> {
642 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
643 Ok(format!(
644 "({0} < {2}) AND ({1} > {2}) AND ({1} < {3})",
645 self.to_sql_impl(e0)?,
646 self.to_sql_impl(e1)?,
647 self.to_sql_impl(e2)?,
648 self.to_sql_impl(e3)?
649 ))
650 }
651
652 fn t_started_by_sql(&self, a: E, b: E) -> Result<String, MyError> {
653 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
654 Ok(format!(
655 "({0} = {2}) AND ({1} > {3})",
656 self.to_sql_impl(e0)?,
657 self.to_sql_impl(e1)?,
658 self.to_sql_impl(e2)?,
659 self.to_sql_impl(e3)?
660 ))
661 }
662
663 fn t_starts_sql(&self, a: E, b: E) -> Result<String, MyError> {
664 let (e0, e1, e2, e3) = crate::unfold_intervals!(a, b);
665 Ok(format!(
666 "({0} = {2}) AND ({1} < {3})",
667 self.to_sql_impl(e0)?,
668 self.to_sql_impl(e1)?,
669 self.to_sql_impl(e2)?,
670 self.to_sql_impl(e3)?
671 ))
672 }
673}
674
675fn cmp_ci(a: &str, b: &str) -> Ordering {
677 a.to_lowercase().cmp(&b.to_lowercase())
678}
679
680fn cmp_ai(a: &str, b: &str) -> Ordering {
682 let lhs = a.nfd().filter(|x| !is_combining_mark(*x)).nfc();
683 let rhs = b.nfd().filter(|x| !is_combining_mark(*x)).nfc();
684 lhs.cmp(rhs)
685}
686
687fn cmp_aci(a: &str, b: &str) -> Ordering {
690 let x = a.to_lowercase();
691 let y = b.to_lowercase();
692 let lhs = x.nfd().filter(|x| !is_combining_mark(*x)).nfc();
693 let rhs = y.nfd().filter(|x| !is_combining_mark(*x)).nfc();
694 lhs.cmp(rhs)
695}
696
697fn qstr_to_sql(qs: QString) -> Result<String, MyError> {
699 match qs.flags() {
700 0 => Ok(format!("'{}'", qs.inner())),
701 1 => Ok(format!("'{}' COLLATE {CQL2_CI}", qs.inner())),
702 2 => Ok(format!("'{}' COLLATE {CQL2_AI}", qs.inner())),
703 3 => Ok(format!("'{}' COLLATE {CQL2_CAI}", qs.inner())),
704 x => {
705 let msg = format!("String w/ '{x}' flags has NO direct SQL representation");
706 Err(MyError::Runtime(msg.into()))
707 }
708 }
709}
710
711#[macro_export]
723macro_rules! gen_gpkg_ds {
724 ($vis:vis, $name:expr, $gpkg_url:expr, $layer:expr, $feature:expr) => {
725 ::paste::paste! {
726 $vis struct [<$name GPkg>](GPkgDataSource);
728
729 impl [<$name GPkg>] {
730 $vis async fn new() -> Result<Self, MyError> {
732 let gpkp = GPkgDataSource::from($gpkg_url, $layer).await?;
733 Ok(Self(gpkp))
734 }
735
736 $vis fn to_resource(r: $feature) -> Result<Resource, Box<dyn Error>> {
738 let row = $feature::try_from(r)?;
739 Ok(Resource::try_from(row)?)
740 }
741
742 $vis fn vtable(&self) -> String {
744 self.0.vtable()
745 }
746
747 $vis fn inner(&self) -> &GPkgDataSource {
749 &self.0
750 }
751 }
752
753 impl ::core::fmt::Display for [<$name GPkg>] {
754 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
755 write!(f, "{}GPkg({})", $name, $layer)
756 }
757 }
758
759 #[::async_trait::async_trait]
760 impl StreamableDS for [<$name GPkg>] {
761 type Item = $feature;
762 type Err = MyError;
763
764 async fn fetch(
765 &self
766 ) -> Result<::futures::stream::BoxStream<'_, Result<$feature, MyError>>, MyError> {
767 let sql = format!("SELECT * FROM {}", $layer);
768 let safe_sql = ::sqlx::AssertSqlSafe(sql);
769 let it = sqlx::query_as::<_, $feature>(safe_sql)
770 .fetch(self.0.pool())
771 .map_err(MyError::SQL);
772 Ok(Box::pin(it))
773 }
774
775 async fn stream(
776 &self
777 ) -> Result<::futures::stream::BoxStream<'_, Result<Resource, MyError>>, MyError> {
778 let rows = self.fetch().await?;
779 let resources = rows
780 .try_filter_map(|row| async move {
781 match Resource::try_from(row) {
782 Ok(x) => Ok(Some(x)),
783 Err(x) => Err(x),
784 }
785 })
786 .boxed();
787 Ok(resources)
788 }
789
790 async fn fetch_where(
791 &self,
792 exp: &Expression,
793 ) -> Result<::futures::stream::BoxStream<'_, Result<$feature, MyError>>, MyError> {
794 let where_clause = self.0.to_sql(exp)?;
795 let sql = format!(r#"SELECT * FROM "{}" WHERE {}"#, self.vtable(), where_clause);
796 let safe_sql = ::sqlx::AssertSqlSafe(sql);
797 let it = sqlx::query_as::<_, $feature>(safe_sql)
798 .fetch(self.0.pool())
799 .map_err(MyError::SQL);
800 Ok(Box::pin(it))
801 }
802
803 async fn stream_where(
804 &self,
805 exp: &Expression,
806 ) -> Result<::futures::stream::BoxStream<'_, Result<Resource, MyError>>, MyError> {
807 let rows = self.fetch_where(exp).await?;
808 let resources = rows
809 .try_filter_map(|row| async move {
810 match Resource::try_from(row) {
811 Ok(x) => Ok(Some(x)),
812 Err(x) => Err(x),
813 }
814 })
815 .boxed();
816 Ok(resources)
817 }
818 }
819 }
820 };
821}
822
823#[cfg(test)]
824mod tests {
825 use super::*;
826
827 #[test]
828 fn test_cmp_ci() {
829 let eq = cmp_ci("abc", "ABC");
830 assert_eq!(eq, Ordering::Equal);
831
832 let eq = cmp_ci("ABC", "abc");
833 assert_eq!(eq, Ordering::Equal);
834
835 let eq = cmp_ci("aBc", "AbC");
836 assert_eq!(eq, Ordering::Equal);
837
838 let eq = cmp_ci("abcd", "ABCe");
839 assert_eq!(eq, Ordering::Less);
840
841 let eq = cmp_ci("bcd", "ACz");
842 assert_eq!(eq, Ordering::Greater);
843 }
844
845 #[test]
846 fn test_cmp_ai() {
847 let eq = cmp_ai("ÁBC", "ABC");
848 assert_eq!(eq, Ordering::Equal);
849
850 let eq = cmp_ai("ÁBC", "ABÇ");
851 assert_eq!(eq, Ordering::Equal);
852 }
853
854 #[test]
855 fn test_cmp_aci() {
856 let eq = cmp_aci("ábc", "ABÇ");
857 assert_eq!(eq, Ordering::Equal);
858 }
859}