Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
use clap_complete::{generate, Shell};
use dsync::{error::IOErrorToError, GenerationConfig, TableOptions};
use dsync::{FileChangeStatus, StringType};
use dsync::{BytesType, FileChangeStatus, StringType};
use std::collections::HashMap;
use std::io::{BufWriter, Write};
use std::path::PathBuf;
Expand Down Expand Up @@ -98,6 +98,14 @@ pub struct MainOptions {
#[arg(long = "update-str", default_value = "string")]
pub update_str: StringTypeCli,

/// Set which bytes type to use for Create* structs
#[arg(long = "create-bytes", default_value = "vec")]
pub create_bytes: BytesTypeCli,

/// Set which bytes type to use for Update* structs
#[arg(long = "update-bytes", default_value = "vec")]
pub update_bytes: BytesTypeCli,

/// Only Generate a single model file instead of a directory with "mod.rs" and "generated.rs"
#[arg(long = "single-model-file")]
pub single_model_file: bool,
Expand Down Expand Up @@ -140,6 +148,27 @@ impl From<StringTypeCli> for StringType {
}
}

#[derive(Debug, ValueEnum, Clone, PartialEq, Default)]
pub enum BytesTypeCli {
/// Use "Vec<u8>"
#[default]
Vec,
/// Use "&[u8]"
Slice,
/// Use "Cow<[u8]>"
Cow,
}

impl From<BytesTypeCli> for BytesType {
fn from(value: BytesTypeCli) -> Self {
match value {
BytesTypeCli::Vec => BytesType::Vec,
BytesTypeCli::Slice => BytesType::Slice,
BytesTypeCli::Cow => BytesType::Cow,
}
}
}

fn main() {
let res = actual_main();

Expand Down Expand Up @@ -183,7 +212,9 @@ fn actual_main() -> dsync::Result<()> {
let mut default_table_options = TableOptions::default()
.autogenerated_columns(cols.iter().map(|t| t.as_str()).collect::<Vec<&str>>())
.create_str_type(args.create_str.into())
.update_str_type(args.update_str.into());
.update_str_type(args.update_str.into())
.create_bytes_type(args.create_bytes.into())
.update_bytes_type(args.update_bytes.into());

#[cfg(feature = "tsync")]
if args.tsync {
Expand Down
18 changes: 17 additions & 1 deletion src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,12 +291,22 @@ impl<'a> Struct<'a> {
}

let lifetimes = {
let lifetimes = match self.ty {
let s_lifetimes = match self.ty {
StructType::Read => "",
StructType::Update => self.opts.get_update_str_type().get_lifetime(),
StructType::Create => self.opts.get_create_str_type().get_lifetime(),
};
let b_lifetimes = match self.ty {
StructType::Read => "",
StructType::Update => self.opts.get_update_bytes_type().get_lifetime(),
StructType::Create => self.opts.get_create_bytes_type().get_lifetime(),
};

let lifetimes = [s_lifetimes, b_lifetimes]
.iter()
.copied()
.max_by_key(|l| l.len())
.unwrap_or("");
if lifetimes.is_empty() {
String::new()
} else {
Expand All @@ -314,6 +324,12 @@ impl<'a> Struct<'a> {
StructType::Update => self.opts.get_update_str_type().as_str().to_string(),
StructType::Create => self.opts.get_create_str_type().as_str().to_string(),
}
} else if f.base_type == "Vec<u8>" {
f.base_type = match self.ty {
StructType::Read => f.base_type,
StructType::Update => self.opts.get_update_bytes_type().as_str().to_string(),
StructType::Create => self.opts.get_create_bytes_type().as_str().to_string(),
}
}

let mut field_type = f.to_rust_type();
Expand Down
64 changes: 64 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,38 @@ impl StringType {
}
}

/// Available options for bytes types
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub enum BytesType {
/// Use `Vec<u8>`
#[default]
Vec,
/// Use `&[u8]`
Slice,
/// Use `Cow<[u8]>`
Cow,
}

impl BytesType {
/// Get the current [BytesType] as a rust type string
pub fn as_str(&self) -> &'static str {
match self {
BytesType::Vec => "Vec<u8>",
BytesType::Slice => "&'a [u8]",
BytesType::Cow => "Cow<'a, [u8]>",
}
}

/// Get the lifetime used for the current [BytesType]
pub fn get_lifetime(&self) -> &'static str {
match self {
BytesType::Vec => "",
BytesType::Slice => "'a",
BytesType::Cow => "'a",
}
}
}

/// Options for a individual table
#[derive(Debug, Clone)]
pub struct TableOptions<'a> {
Expand Down Expand Up @@ -85,6 +117,12 @@ pub struct TableOptions<'a> {
/// Determines which string type to use for Update* structs
update_str_type: StringType,

/// Determines which bytes type to use for Create* structs
create_bytes_type: BytesType,

/// Determines which bytes type to use for Update* structs
update_bytes_type: BytesType,

/// Only Generate a single model file instead of a directory with "mod.rs" and "generated.rs"
single_model_file: bool,

Expand Down Expand Up @@ -123,6 +161,14 @@ impl<'a> TableOptions<'a> {
self.update_str_type
}

pub fn get_create_bytes_type(&self) -> BytesType {
self.create_bytes_type
}

pub fn get_update_bytes_type(&self) -> BytesType {
self.update_bytes_type
}

pub fn get_autogenerated_columns(&self) -> &[&'_ str] {
self.autogenerated_columns.as_deref().unwrap_or_default()
}
Expand Down Expand Up @@ -193,6 +239,20 @@ impl<'a> TableOptions<'a> {
}
}

pub fn create_bytes_type(self, type_: BytesType) -> Self {
Self {
create_bytes_type: type_,
..self
}
}

pub fn update_bytes_type(self, type_: BytesType) -> Self {
Self {
update_bytes_type: type_,
..self
}
}

pub fn set_read_only(&mut self, value: bool) {
self.read_only = value;
}
Expand All @@ -214,6 +274,8 @@ impl<'a> TableOptions<'a> {
fns: self.fns || other.fns,
create_str_type: other.create_str_type,
update_str_type: other.update_str_type,
create_bytes_type: other.create_bytes_type,
update_bytes_type: other.update_bytes_type,
single_model_file: self.single_model_file || other.single_model_file,
read_only: self.read_only || other.read_only,
}
Expand All @@ -233,6 +295,8 @@ impl<'a> Default for TableOptions<'a> {
fns: true,
create_str_type: Default::default(),
update_str_type: Default::default(),
create_bytes_type: Default::default(),
update_bytes_type: Default::default(),
single_model_file: false,
read_only: false,
}
Expand Down
1 change: 1 addition & 0 deletions test/create_update_bytes_cow/models/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod todos;
98 changes: 98 additions & 0 deletions test/create_update_bytes_cow/models/todos/generated.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/* @generated and managed by dsync */

use crate::diesel::*;
use crate::schema::*;
use diesel::QueryResult;

pub type ConnectionType = diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::pg::PgConnection>>;

/// Struct representing a row in table `todos`
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Queryable, Selectable, QueryableByName)]
#[diesel(table_name=todos, primary_key(data))]
pub struct Todos {
/// Field representing column `data`
pub data: Vec<u8>,
/// Field representing column `data_nullable`
pub data_nullable: Option<Vec<u8>>,
}

/// Create Struct for a row in table `todos` for [`Todos`]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Insertable)]
#[diesel(table_name=todos)]
pub struct CreateTodos<'a> {
/// Field representing column `data`
pub data: Cow<'a, [u8]>,
/// Field representing column `data_nullable`
pub data_nullable: Option<Cow<'a, [u8]>>,
}

/// Update Struct for a row in table `todos` for [`Todos`]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, AsChangeset, PartialEq, Default)]
#[diesel(table_name=todos)]
pub struct UpdateTodos<'a> {
/// Field representing column `data_nullable`
pub data_nullable: Option<Option<Cow<'a, [u8]>>>,
}

/// Result of a `.paginate` function
#[derive(Debug, serde::Serialize)]
pub struct PaginationResult<T> {
/// Resulting items that are from the current page
pub items: Vec<T>,
/// The count of total items there are
pub total_items: i64,
/// Current page, 0-based index
pub page: i64,
/// Size of a page
pub page_size: i64,
/// Number of total possible pages, given the `page_size` and `total_items`
pub num_pages: i64,
}

impl Todos {
/// Insert a new row into `todos` with a given [`CreateTodos`]
pub fn create(db: &mut ConnectionType, item: &CreateTodos) -> QueryResult<Self> {
use crate::schema::todos::dsl::*;

insert_into(todos).values(item).get_result::<Self>(db)
}

/// Get a row from `todos`, identified by the primary key
pub fn read(db: &mut ConnectionType, param_data: Vec<u8>) -> QueryResult<Self> {
use crate::schema::todos::dsl::*;

todos.filter(data.eq(param_data)).first::<Self>(db)
}

/// Paginates through the table where page is a 0-based index (i.e. page 0 is the first page)
pub fn paginate(db: &mut ConnectionType, page: i64, page_size: i64) -> QueryResult<PaginationResult<Self>> {
use crate::schema::todos::dsl::*;

let page_size = if page_size < 1 { 1 } else { page_size };
let total_items = todos.count().get_result(db)?;
let items = todos.limit(page_size).offset(page * page_size).load::<Self>(db)?;

Ok(PaginationResult {
items,
total_items,
page,
page_size,
/* ceiling division of integers */
num_pages: total_items / page_size + i64::from(total_items % page_size != 0)
})
}

/// Update a row in `todos`, identified by the primary key with [`UpdateTodos`]
pub fn update(db: &mut ConnectionType, param_data: Vec<u8>, item: &UpdateTodos) -> QueryResult<Self> {
use crate::schema::todos::dsl::*;

diesel::update(todos.filter(data.eq(param_data))).set(item).get_result(db)
}

/// Delete a row in `todos`, identified by the primary key
pub fn delete(db: &mut ConnectionType, param_data: Vec<u8>) -> QueryResult<usize> {
use crate::schema::todos::dsl::*;

diesel::delete(todos.filter(data.eq(param_data))).execute(db)
}
}
2 changes: 2 additions & 0 deletions test/create_update_bytes_cow/models/todos/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub use generated::*;
pub mod generated;
6 changes: 6 additions & 0 deletions test/create_update_bytes_cow/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
diesel::table! {
todos (data) {
data -> Binary,
data_nullable -> Nullable<Binary>,
}
}
7 changes: 7 additions & 0 deletions test/create_update_bytes_cow/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"

cd $SCRIPT_DIR

cargo run -- -i schema.rs -o models -g id -g created_at -g updated_at -c "diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::pg::PgConnection>>" --create-bytes=cow --update-bytes=cow
1 change: 1 addition & 0 deletions test/create_update_bytes_slice/models/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod todos;
Loading