1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

mod column_type;
pub use column_type::{ColumnType, FromDataError};

mod data;
pub use data::ColumnData;


#[derive(Debug, Clone, PartialEq)]
pub struct Column {
	pub name: &'static str,
	pub kind: ColumnKind,
	pub index: IndexKind
}

impl Column {

	pub fn new<T>(name: &'static str, len: Option<usize>, index: IndexKind) -> Self
	where T: ColumnType {

		let mut kind = T::column_kind();
		if let Some(len) = len {
			kind = match kind {
				ColumnKind::Text => ColumnKind::Varchar(len),
				_ => panic!("column kind {:?} doenst support len attribute", kind)
			};
		}

		Self { name, kind, index }
	}

	/*pub fn name(&self) -> &'static str {
		self.name
	}

	pub fn kind_string(&self) -> String {
		self.kind.to_string(self.name)
	}

	pub fn index_str(&self) -> &'static str {
		self.index.to_str()
	}

	pub fn not_null_str(&self) -> &'static str {
		match self.index {
			IndexKind::Primary => "",
			_ => self.kind.not_null_str()
		}
	}

	pub fn to_sql(&self) -> String {
		let index_str = if self.index.is_constraint() {
			self.index_str()
		} else {""};
		format!("{} {} {} {}", self.name(), self.kind_string(), index_str, self.not_null_str())
	}*/

}


/*
ToColumnType
*/

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ColumnKind {
	Boolean,
	// Char(usize),
	Varchar(usize),
	FixedText(usize),
	Text,
	Date,
	Timestamp,
	F64,
	F32,
	I64,
	I32,
	I16,
	Option(Box<ColumnKind>),
	TextArray,
	Bytea,
	Json
}

impl ColumnKind {

	pub fn short(&self) -> &'static str {
		match self {
			Self::Boolean => "boolean",
			// Self::Char(_) => "char",
			Self::Varchar(_) => "varchar",
			Self::FixedText(_) => "text",
			Self::Text => "text",
			Self::Date => "date",
			Self::Timestamp => "timestamp",
			Self::F64 => "float8",
			Self::F32 => "float4",
			Self::I64 => "int8",
			Self::I32 => "int4",
			Self::I16 => "int2",
			Self::Option(t) => t.short(),
			Self::TextArray => "text []",
			Self::Bytea => "bytea",
			Self::Json => "json"
		}
	}

	pub fn value(&self, name: &str) -> String {
		match self {
			// Self::Char(v) => Some(v.to_string()),
			Self::Varchar(v) => format!("({})", v),
			Self::FixedText(v) => format!(" CHECK (length({})={})", name, v),
			Self::Option(t) => t.value(name),
			_ => String::new()
		}
	}

	pub fn to_string(&self, name: &str) -> String {
		format!("{}{}", self.short(), self.value(name))
	}

	pub fn not_null_str(&self) -> &'static str {
		match self {
			Self::Option(_) => "null",
			_ => "not null"
		}
	}

}



#[derive(Debug, Clone, PartialEq)]
pub enum IndexKind {
	Primary,
	Unique,
	NamedUnique(&'static str),
	Index,
	None
}

impl IndexKind {
	/*pub fn parse(index: Option<&'static str>) -> Self {
		if index.is_none() {return Self::None}
		match index.unwrap() {
			"primary" => Self::Primary,
			"unique" => Self::Unique,
			"index" => Self::Index,
			"none" => Self::None,
			"" => Self::None,
			i => panic!("unknown index {}", i)
		}
	}*/

	/*pub fn to_str(&self) -> &'static str {
		match self {
			Self::Primary => "primary key",
			Self::Unique => "unique",
			Self::Index => "index",
			Self::None => ""
		}
	}*/

	/*pub fn is_constraint(&self) -> bool {
		match self {
			Self::Primary |
			Self::Unique => true,
			_ => false
		}
	}*/

	pub fn is_none(&self) -> bool {
		matches!(self, Self::None)
	}
}

/*
CREATE TABLE account(
   user_id serial PRIMARY KEY,
   username VARCHAR (50) UNIQUE NOT NULL,
   password VARCHAR (50) NOT NULL,
   email VARCHAR (355) UNIQUE NOT NULL,
   created_on TIMESTAMP NOT NULL,
   last_login TIMESTAMP
);

// UNIQUE

// INDEX

CREATE TABLE account_role
(
  user_id integer NOT NULL,
  role_id integer NOT NULL,
  grant_date timestamp without time zone,
  PRIMARY KEY (user_id, role_id),
  CONSTRAINT account_role_role_id_fkey FOREIGN KEY (role_id)
      REFERENCES role (role_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT account_role_user_id_fkey FOREIGN KEY (user_id)
      REFERENCES account (user_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);
*/

/*
all types

bigint	int8	signed eight-byte integer
bigserial	serial8	autoincrementing eight-byte integer
bit [ (n) ]	 	fixed-length bit string
varbit [ (n) ]	variable-length bit string
boolean	bool	logical Boolean (true/false)
box	 	rectangular box on a plane
bytea	 	binary data ("byte array")
char [ (n) ]	fixed-length character string
varchar [ (n) ]	variable-length character string
cidr	 	IPv4 or IPv6 network address
circle	 	circle on a plane
date	 	calendar date (year, month, day)
float8	double precision floating-point number (8 bytes)
inet	 	IPv4 or IPv6 host address
integer	int, int4	signed four-byte integer
interval [ fields ] [ (p) ]	 	time span
json	 	textual JSON data
jsonb	 	binary JSON data, decomposed
line	 	infinite line on a plane
lseg	 	line segment on a plane
macaddr	 	MAC (Media Access Control) address
money	 	currency amount
numeric [ (p, s) ]	decimal [ (p, s) ]	exact numeric of selectable precision
path	 	geometric path on a plane
pg_lsn	 	PostgreSQL Log Sequence Number
point	 	geometric point on a plane
polygon	 	closed geometric path on a plane
real	float4	single precision floating-point number (4 bytes)
smallint	int2	signed two-byte integer
smallserial	serial2	autoincrementing two-byte integer
serial	serial4	autoincrementing four-byte integer
text	 	variable-length character string
time [ (p) ] [ without time zone ]	 	time of day (no time zone)
time [ (p) ] with time zone	timetz	time of day, including time zone
timestamp [ (p) ] [ without time zone ]	 	date and time (no time zone)
timestamp [ (p) ] with time zone	timestamptz	date and time, including time zone
tsquery	 	text search query
tsvector	 	text search document
txid_snapshot	 	user-level transaction ID snapshot
uuid	 	universally unique identifier
xml	 	XML data
*/