Skip to content

Commit 51c4bac

Browse files
committed
feat(code): add options "create-bytes" and "update-bytes"
1 parent 07e32f3 commit 51c4bac

File tree

13 files changed

+342
-3
lines changed

13 files changed

+342
-3
lines changed

src/bin/main.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
22
use clap_complete::{generate, Shell};
33
use dsync::{error::IOErrorToError, GenerationConfig, TableOptions};
4-
use dsync::{FileChangeStatus, StringType};
4+
use dsync::{BytesType, FileChangeStatus, StringType};
55
use std::collections::HashMap;
66
use std::io::{BufWriter, Write};
77
use std::path::PathBuf;
@@ -98,6 +98,14 @@ pub struct MainOptions {
9898
#[arg(long = "update-str", default_value = "string")]
9999
pub update_str: StringTypeCli,
100100

101+
/// Set which bytes type to use for Create* structs
102+
#[arg(long = "create-bytes", default_value = "vec")]
103+
pub create_bytes: BytesTypeCli,
104+
105+
/// Set which bytes type to use for Update* structs
106+
#[arg(long = "update-bytes", default_value = "vec")]
107+
pub update_bytes: BytesTypeCli,
108+
101109
/// Only Generate a single model file instead of a directory with "mod.rs" and "generated.rs"
102110
#[arg(long = "single-model-file")]
103111
pub single_model_file: bool,
@@ -140,6 +148,27 @@ impl From<StringTypeCli> for StringType {
140148
}
141149
}
142150

151+
#[derive(Debug, ValueEnum, Clone, PartialEq, Default)]
152+
pub enum BytesTypeCli {
153+
/// Use "Vec<u8>"
154+
#[default]
155+
Vec,
156+
/// Use "&[u8]"
157+
Slice,
158+
/// Use "Cow<[u8]>"
159+
Cow,
160+
}
161+
162+
impl From<BytesTypeCli> for BytesType {
163+
fn from(value: BytesTypeCli) -> Self {
164+
match value {
165+
BytesTypeCli::Vec => BytesType::Vec,
166+
BytesTypeCli::Slice => BytesType::Slice,
167+
BytesTypeCli::Cow => BytesType::Cow,
168+
}
169+
}
170+
}
171+
143172
fn main() {
144173
let res = actual_main();
145174

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

188219
#[cfg(feature = "tsync")]
189220
if args.tsync {

src/code.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,12 +291,22 @@ impl<'a> Struct<'a> {
291291
}
292292

293293
let lifetimes = {
294-
let lifetimes = match self.ty {
294+
let s_lifetimes = match self.ty {
295295
StructType::Read => "",
296296
StructType::Update => self.opts.get_update_str_type().get_lifetime(),
297297
StructType::Create => self.opts.get_create_str_type().get_lifetime(),
298298
};
299+
let b_lifetimes = match self.ty {
300+
StructType::Read => "",
301+
StructType::Update => self.opts.get_update_bytes_type().get_lifetime(),
302+
StructType::Create => self.opts.get_create_bytes_type().get_lifetime(),
303+
};
299304

305+
let lifetimes = [s_lifetimes, b_lifetimes]
306+
.iter()
307+
.copied()
308+
.max_by_key(|l| l.len())
309+
.unwrap_or("");
300310
if lifetimes.is_empty() {
301311
String::new()
302312
} else {
@@ -314,6 +324,12 @@ impl<'a> Struct<'a> {
314324
StructType::Update => self.opts.get_update_str_type().as_str().to_string(),
315325
StructType::Create => self.opts.get_create_str_type().as_str().to_string(),
316326
}
327+
} else if f.base_type == "Vec<u8>" {
328+
f.base_type = match self.ty {
329+
StructType::Read => f.base_type,
330+
StructType::Update => self.opts.get_update_bytes_type().as_str().to_string(),
331+
StructType::Create => self.opts.get_create_bytes_type().as_str().to_string(),
332+
}
317333
}
318334

319335
let mut field_type = f.to_rust_type();

src/lib.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,38 @@ impl StringType {
5757
}
5858
}
5959

60+
/// Available options for bytes types
61+
#[derive(Debug, Clone, Copy, PartialEq, Default)]
62+
pub enum BytesType {
63+
/// Use `Vec<u8>`
64+
#[default]
65+
Vec,
66+
/// Use `&[u8]`
67+
Slice,
68+
/// Use `Cow<[u8]>`
69+
Cow,
70+
}
71+
72+
impl BytesType {
73+
/// Get the current [BytesType] as a rust type string
74+
pub fn as_str(&self) -> &'static str {
75+
match self {
76+
BytesType::Vec => "Vec<u8>",
77+
BytesType::Slice => "&'a [u8]",
78+
BytesType::Cow => "Cow<'a, [u8]>",
79+
}
80+
}
81+
82+
/// Get the lifetime used for the current [BytesType]
83+
pub fn get_lifetime(&self) -> &'static str {
84+
match self {
85+
BytesType::Vec => "",
86+
BytesType::Slice => "'a",
87+
BytesType::Cow => "'a",
88+
}
89+
}
90+
}
91+
6092
/// Options for a individual table
6193
#[derive(Debug, Clone)]
6294
pub struct TableOptions<'a> {
@@ -85,6 +117,12 @@ pub struct TableOptions<'a> {
85117
/// Determines which string type to use for Update* structs
86118
update_str_type: StringType,
87119

120+
/// Determines which bytes type to use for Create* structs
121+
create_bytes_type: BytesType,
122+
123+
/// Determines which bytes type to use for Update* structs
124+
update_bytes_type: BytesType,
125+
88126
/// Only Generate a single model file instead of a directory with "mod.rs" and "generated.rs"
89127
single_model_file: bool,
90128

@@ -123,6 +161,14 @@ impl<'a> TableOptions<'a> {
123161
self.update_str_type
124162
}
125163

164+
pub fn get_create_bytes_type(&self) -> BytesType {
165+
self.create_bytes_type
166+
}
167+
168+
pub fn get_update_bytes_type(&self) -> BytesType {
169+
self.update_bytes_type
170+
}
171+
126172
pub fn get_autogenerated_columns(&self) -> &[&'_ str] {
127173
self.autogenerated_columns.as_deref().unwrap_or_default()
128174
}
@@ -193,6 +239,20 @@ impl<'a> TableOptions<'a> {
193239
}
194240
}
195241

242+
pub fn create_bytes_type(self, type_: BytesType) -> Self {
243+
Self {
244+
create_bytes_type: type_,
245+
..self
246+
}
247+
}
248+
249+
pub fn update_bytes_type(self, type_: BytesType) -> Self {
250+
Self {
251+
update_bytes_type: type_,
252+
..self
253+
}
254+
}
255+
196256
pub fn set_read_only(&mut self, value: bool) {
197257
self.read_only = value;
198258
}
@@ -214,6 +274,8 @@ impl<'a> TableOptions<'a> {
214274
fns: self.fns || other.fns,
215275
create_str_type: other.create_str_type,
216276
update_str_type: other.update_str_type,
277+
create_bytes_type: other.create_bytes_type,
278+
update_bytes_type: other.update_bytes_type,
217279
single_model_file: self.single_model_file || other.single_model_file,
218280
read_only: self.read_only || other.read_only,
219281
}
@@ -233,6 +295,8 @@ impl<'a> Default for TableOptions<'a> {
233295
fns: true,
234296
create_str_type: Default::default(),
235297
update_str_type: Default::default(),
298+
create_bytes_type: Default::default(),
299+
update_bytes_type: Default::default(),
236300
single_model_file: false,
237301
read_only: false,
238302
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod todos;
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/* @generated and managed by dsync */
2+
3+
use crate::diesel::*;
4+
use crate::schema::*;
5+
use diesel::QueryResult;
6+
7+
pub type ConnectionType = diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::pg::PgConnection>>;
8+
9+
/// Struct representing a row in table `todos`
10+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Queryable, Selectable, QueryableByName)]
11+
#[diesel(table_name=todos, primary_key(data))]
12+
pub struct Todos {
13+
/// Field representing column `data`
14+
pub data: Vec<u8>,
15+
/// Field representing column `data_nullable`
16+
pub data_nullable: Option<Vec<u8>>,
17+
}
18+
19+
/// Create Struct for a row in table `todos` for [`Todos`]
20+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Insertable)]
21+
#[diesel(table_name=todos)]
22+
pub struct CreateTodos<'a> {
23+
/// Field representing column `data`
24+
pub data: Cow<'a, [u8]>,
25+
/// Field representing column `data_nullable`
26+
pub data_nullable: Option<Cow<'a, [u8]>>,
27+
}
28+
29+
/// Update Struct for a row in table `todos` for [`Todos`]
30+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, AsChangeset, PartialEq, Default)]
31+
#[diesel(table_name=todos)]
32+
pub struct UpdateTodos<'a> {
33+
/// Field representing column `data_nullable`
34+
pub data_nullable: Option<Option<Cow<'a, [u8]>>>,
35+
}
36+
37+
/// Result of a `.paginate` function
38+
#[derive(Debug, serde::Serialize)]
39+
pub struct PaginationResult<T> {
40+
/// Resulting items that are from the current page
41+
pub items: Vec<T>,
42+
/// The count of total items there are
43+
pub total_items: i64,
44+
/// Current page, 0-based index
45+
pub page: i64,
46+
/// Size of a page
47+
pub page_size: i64,
48+
/// Number of total possible pages, given the `page_size` and `total_items`
49+
pub num_pages: i64,
50+
}
51+
52+
impl Todos {
53+
/// Insert a new row into `todos` with a given [`CreateTodos`]
54+
pub fn create(db: &mut ConnectionType, item: &CreateTodos) -> QueryResult<Self> {
55+
use crate::schema::todos::dsl::*;
56+
57+
insert_into(todos).values(item).get_result::<Self>(db)
58+
}
59+
60+
/// Get a row from `todos`, identified by the primary key
61+
pub fn read(db: &mut ConnectionType, param_data: Vec<u8>) -> QueryResult<Self> {
62+
use crate::schema::todos::dsl::*;
63+
64+
todos.filter(data.eq(param_data)).first::<Self>(db)
65+
}
66+
67+
/// Paginates through the table where page is a 0-based index (i.e. page 0 is the first page)
68+
pub fn paginate(db: &mut ConnectionType, page: i64, page_size: i64) -> QueryResult<PaginationResult<Self>> {
69+
use crate::schema::todos::dsl::*;
70+
71+
let page_size = if page_size < 1 { 1 } else { page_size };
72+
let total_items = todos.count().get_result(db)?;
73+
let items = todos.limit(page_size).offset(page * page_size).load::<Self>(db)?;
74+
75+
Ok(PaginationResult {
76+
items,
77+
total_items,
78+
page,
79+
page_size,
80+
/* ceiling division of integers */
81+
num_pages: total_items / page_size + i64::from(total_items % page_size != 0)
82+
})
83+
}
84+
85+
/// Update a row in `todos`, identified by the primary key with [`UpdateTodos`]
86+
pub fn update(db: &mut ConnectionType, param_data: Vec<u8>, item: &UpdateTodos) -> QueryResult<Self> {
87+
use crate::schema::todos::dsl::*;
88+
89+
diesel::update(todos.filter(data.eq(param_data))).set(item).get_result(db)
90+
}
91+
92+
/// Delete a row in `todos`, identified by the primary key
93+
pub fn delete(db: &mut ConnectionType, param_data: Vec<u8>) -> QueryResult<usize> {
94+
use crate::schema::todos::dsl::*;
95+
96+
diesel::delete(todos.filter(data.eq(param_data))).execute(db)
97+
}
98+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub use generated::*;
2+
pub mod generated;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
diesel::table! {
2+
todos (data) {
3+
data -> Binary,
4+
data_nullable -> Nullable<Binary>,
5+
}
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
4+
5+
cd $SCRIPT_DIR
6+
7+
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
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod todos;

0 commit comments

Comments
 (0)