use std::fmt::{Debug, Display};
use std::future::Future;
use futures_core::future::BoxFuture;
use rbatis_core::Error;
use serde::{Deserialize, Serialize};
use serde::de::DeserializeOwned;
use serde_json::Value;
use crate::core::db::DriverType;
use crate::sql::PageLimit;
pub const DEFAULT_PAGE_SIZE: u64 = 10;
pub trait PagePlugin: Send + Sync + Debug {
fn name(&self) -> &str {
std::any::type_name::<Self>()
}
fn make_page_sql(
&self,
driver_type: &DriverType,
context_id: &str,
sql: &str,
args: &Vec<serde_json::Value>,
page: &dyn IPageRequest,
) -> Result<(String, String), crate::core::Error>;
}
pub trait IPageRequest: Send + Sync {
fn get_page_size(&self) -> u64;
fn get_page_no(&self) -> u64;
fn get_total(&self) -> u64;
fn is_search_count(&self) -> bool;
fn set_total(&mut self, arg: u64);
fn set_page_size(&mut self, arg: u64);
fn set_page_no(&mut self, arg: u64);
fn set_search_count(&mut self, arg: bool);
fn get_pages(&self) -> u64 {
if self.get_page_size() == 0 {
return 0;
}
let mut pages = self.get_total() / self.get_page_size();
if self.get_total() % self.get_page_size() != 0 {
pages = pages + 1;
}
return pages;
}
fn offset(&self) -> u64 {
if self.get_page_no() > 0 {
(self.get_page_no() - 1) * self.get_page_size()
} else {
0
}
}
}
pub trait IPage<T>: IPageRequest {
fn get_records(&self) -> &Vec<T>;
fn get_records_mut(&mut self) -> &mut Vec<T>;
fn set_records(&mut self, arg: Vec<T>);
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Page<T> {
pub records: Vec<T>,
pub total: u64,
pub pages: u64,
pub page_no: u64,
pub page_size: u64,
pub search_count: bool,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct PageRequest {
pub total: u64,
pub page_no: u64,
pub page_size: u64,
pub search_count: bool,
}
impl PageRequest {
pub fn new(page_no: u64, page_size: u64) -> Self {
return PageRequest::new_total(page_no, page_size, DEFAULT_PAGE_SIZE);
}
pub fn new_option(page_no: &Option<u64>, page_size: &Option<u64>) -> Self {
return PageRequest::new(page_no.unwrap_or(1), page_size.unwrap_or(DEFAULT_PAGE_SIZE));
}
pub fn new_total(page_no: u64, page_size: u64, total: u64) -> Self {
return PageRequest::new_plugin(String::new(), page_no, page_size, total);
}
pub fn new_plugin(plugin: String, page_no: u64, page_size: u64, total: u64) -> Self {
let mut page_no = page_no;
if page_no < 1 {
page_no = 1;
}
return Self {
total,
page_size,
page_no: page_no,
search_count: true,
};
}
}
impl Default for PageRequest {
fn default() -> Self {
return PageRequest {
total: 0,
page_size: DEFAULT_PAGE_SIZE,
page_no: 1,
search_count: true,
};
}
}
impl IPageRequest for PageRequest {
fn get_page_size(&self) -> u64 {
self.page_size
}
fn get_page_no(&self) -> u64 {
self.page_no
}
fn get_total(&self) -> u64 {
self.total
}
fn is_search_count(&self) -> bool {
self.search_count
}
fn set_total(&mut self, total: u64) {
self.total = total;
}
fn set_page_size(&mut self, arg: u64) {
self.page_size = arg;
}
fn set_page_no(&mut self, arg: u64) {
self.page_no = arg;
}
fn set_search_count(&mut self, arg: bool) {
self.search_count = arg;
}
}
impl ToString for PageRequest {
fn to_string(&self) -> String {
let result = serde_json::to_string(self);
if result.is_err() {
return String::new();
} else {
return result.unwrap();
}
}
}
impl<T> Page<T> {
pub fn new(current: u64, page_size: u64) -> Self {
return Page::new_total(current, page_size, 0);
}
pub fn new_option(current: &Option<u64>, page_size: &Option<u64>) -> Self {
return Page::new(current.unwrap_or(1), page_size.unwrap_or(DEFAULT_PAGE_SIZE));
}
pub fn new_total(page_no: u64, page_size: u64, total: u64) -> Self {
if page_no < 1 {
return Self {
total,
pages: 0,
page_size: page_size,
page_no: 1 as u64,
records: vec![],
search_count: true,
};
}
return Self {
total,
pages: 0,
page_size: page_size,
page_no,
records: vec![],
search_count: true,
};
}
}
impl<T> Default for Page<T> {
fn default() -> Self {
return Page {
records: vec![],
total: 0,
pages: 0,
page_size: DEFAULT_PAGE_SIZE,
page_no: 1,
search_count: true,
};
}
}
impl<T> IPageRequest for Page<T>
where
T: Send + Sync,
{
fn get_page_size(&self) -> u64 {
self.page_size
}
fn get_page_no(&self) -> u64 {
self.page_no
}
fn get_total(&self) -> u64 {
self.total
}
fn is_search_count(&self) -> bool {
self.search_count
}
fn set_total(&mut self, total: u64) {
self.total = total;
}
fn set_page_size(&mut self, arg: u64) {
self.page_size = arg;
}
fn set_page_no(&mut self, arg: u64) {
self.page_no = arg;
}
fn set_search_count(&mut self, arg: bool) {
self.search_count = arg;
}
}
impl<T> IPage<T> for Page<T>
where
T: Send + Sync,
{
fn get_records(&self) -> &Vec<T> {
self.records.as_ref()
}
fn get_records_mut(&mut self) -> &mut Vec<T> {
self.records.as_mut()
}
fn set_records(&mut self, arg: Vec<T>) {
self.records = arg;
}
}
impl<T> ToString for Page<T>
where
T: Send + Sync + Serialize,
{
fn to_string(&self) -> String {
let result = serde_json::to_string(self);
if result.is_err() {
return String::new();
} else {
return result.unwrap();
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct RbatisReplacePagePlugin {}
impl RbatisReplacePagePlugin {
pub fn make_count_sql(&self, sql: &str) -> String {
let mut from_index = sql.find(crate::sql::TEMPLATE.from.left_right_space);
if from_index.is_some() {
from_index = Option::Some(from_index.unwrap() + crate::sql::TEMPLATE.from.left_right_space.len());
}
let mut where_sql = sql[from_index.unwrap_or(0)..sql.len()].to_string();
if where_sql.contains(crate::sql::TEMPLATE.order_by.left_right_space) {
where_sql =
where_sql[0..where_sql.rfind(crate::sql::TEMPLATE.order_by.left_right_space).unwrap_or(where_sql.len())].to_string();
}
if where_sql.contains(crate::sql::TEMPLATE.limit.left_right_space) {
where_sql =
where_sql[0..where_sql.rfind(crate::sql::TEMPLATE.limit.left_right_space).unwrap_or(where_sql.len())].to_string();
}
format!("{} count(1) {} {} ", crate::sql::TEMPLATE.select.value, crate::sql::TEMPLATE.from.value, where_sql)
}
}
impl PagePlugin for RbatisReplacePagePlugin {
fn make_page_sql(
&self,
driver_type: &DriverType,
context_id: &str,
sql: &str,
args: &Vec<Value>,
page: &dyn IPageRequest,
) -> Result<(String, String), crate::core::Error> {
let mut sql = sql.trim().to_owned();
if !sql.starts_with(crate::sql::TEMPLATE.select.right_space) && !sql.contains(crate::sql::TEMPLATE.from.left_right_space) {
return Err(crate::core::Error::from(
"[rbatis] make_page_sql() sql must contains 'select ' And ' from '",
));
}
let mut count_sql = sql.clone();
if page.is_search_count() {
count_sql = self.make_count_sql(&count_sql);
}
let limit_sql = driver_type.page_limit_sql(page.offset(), page.get_page_size())?;
match driver_type {
DriverType::Mssql => {
sql = format!("{} RB_DATA.*, 0 {} RB_DATA_ORDER {} ({})RB_DATA {} RB_DATA_ORDER {}", crate::sql::TEMPLATE.select.value, crate::sql::TEMPLATE.r#as.value, crate::sql::TEMPLATE.from.value, sql, crate::sql::TEMPLATE.order_by.value, limit_sql);
}
_ => {
sql = sql + limit_sql.as_str();
}
}
return Ok((count_sql, sql));
}
}
#[derive(Copy, Clone, Debug)]
pub struct RbatisPackPagePlugin {}
impl RbatisPackPagePlugin {
fn make_count_sql(&self, sql: &str) -> String {
format!("{} count(1) {} ({}) a", crate::sql::TEMPLATE.select.value, crate::sql::TEMPLATE.from.value, sql)
}
}
impl PagePlugin for RbatisPackPagePlugin {
fn make_page_sql(
&self,
driver_type: &DriverType,
context_id: &str,
sql: &str,
args: &Vec<Value>,
page: &dyn IPageRequest,
) -> Result<(String, String), crate::core::Error> {
let mut sql = sql.trim().to_owned();
if !sql.starts_with(crate::sql::TEMPLATE.select.right_space) && !sql.contains(crate::sql::TEMPLATE.from.left_right_space) {
return Err(crate::core::Error::from(
"[rbatis] make_page_sql() sql must contains 'select ' And ' from '",
));
}
let mut count_sql = sql.clone();
if page.is_search_count() {
count_sql = self.make_count_sql(&count_sql);
}
let limit_sql = driver_type.page_limit_sql(page.offset(), page.get_page_size())?;
match driver_type {
DriverType::Mssql => {
sql = format!("{} RB_DATA.*, 0 {} RB_DATA_ORDER {} ({})RB_DATA {} RB_DATA_ORDER {}", crate::sql::TEMPLATE.select.value, crate::sql::TEMPLATE.r#as.value, crate::sql::TEMPLATE.from.value, sql, crate::sql::TEMPLATE.order_by.value, limit_sql);
}
_ => {
sql = sql + limit_sql.as_str();
}
}
return Ok((count_sql, sql));
}
}
#[derive(Debug)]
pub struct RbatisPagePlugin {
pub pack: RbatisPackPagePlugin,
pub replace: RbatisReplacePagePlugin,
}
impl RbatisPagePlugin {
pub fn new() -> Self {
return Self::default();
}
}
impl Default for RbatisPagePlugin {
fn default() -> Self {
Self {
pack: RbatisPackPagePlugin {},
replace: RbatisReplacePagePlugin {},
}
}
}
impl PagePlugin for RbatisPagePlugin {
fn make_page_sql(
&self,
driver_type: &DriverType,
context_id: &str,
sql: &str,
args: &Vec<Value>,
page: &dyn IPageRequest,
) -> Result<(String, String), Error> {
if sql.contains(crate::sql::TEMPLATE.group_by.left_right_space) {
return self
.pack
.make_page_sql(driver_type, context_id, sql, args, page);
} else {
return self
.replace
.make_page_sql(driver_type, context_id, sql, args, page);
}
}
}