so much amazing stuff

This commit is contained in:
Adam D. Ruppe 2019-07-07 22:44:11 -04:00
parent 4953cba8fa
commit 03315adfa6
9 changed files with 139 additions and 11 deletions

46
cgi.d
View File

@ -2746,9 +2746,28 @@ struct Uri {
}
}
n.removeDots();
return n;
}
void removeDots() {
auto parts = this.path.split("/");
string[] toKeep;
foreach(part; parts) {
if(part == ".") {
continue;
} else if(part == "..") {
toKeep = toKeep[0 .. $-1];
continue;
} else {
toKeep ~= part;
}
}
this.path = toKeep.join("/");
}
unittest {
auto uri = Uri("test.html");
assert(uri.path == "test.html");
@ -2810,6 +2829,10 @@ struct Uri {
assert(url.basedOn(Uri("http://test.com/what/test.html?a=b&c=d#what")) == "http://test.com/what/test.html?query=answer");
assert(url.basedOn(Uri("http://test.com")) == "http://test.com?query=answer");
url = Uri("/test/bar");
assert(Uri("./").basedOn(url) == "/test/", Uri("./").basedOn(url));
assert(Uri("../").basedOn(url) == "/");
//auto uriBefore = url;
url = Uri("#anchor"); // everything should remain the same except the anchor
//uriBefore.anchor = "anchor");
@ -6458,16 +6481,22 @@ auto callFromCgi(alias method, T)(T dg, Cgi cgi) {
auto ident = idents[idx];
if(cgi.requestMethod == Cgi.RequestMethod.GET) {
if(ident !in cgi.get) {
static if(is(defaults[idx] == void))
throw new MissingArgumentException(__traits(identifier, method), ident, param.stringof);
else
static if(is(defaults[idx] == void)) {
static if(is(param == bool))
params[idx] = false;
else
throw new MissingArgumentException(__traits(identifier, method), ident, param.stringof);
} else
params[idx] = defaults[idx];
}
} else {
if(ident !in cgi.post) {
static if(is(defaults[idx] == void))
throw new MissingArgumentException(__traits(identifier, method), ident, param.stringof);
else
static if(is(defaults[idx] == void)) {
static if(is(param == bool))
params[idx] = false;
else
throw new MissingArgumentException(__traits(identifier, method), ident, param.stringof);
} else
params[idx] = defaults[idx];
}
}
@ -6510,6 +6539,9 @@ auto callFromCgi(alias method, T)(T dg, Cgi cgi) {
} else static if(isSomeString!T || isIntegral!T || isFloatingPoint!T) {
*what = to!T(value);
return true;
} else static if(is(T == bool)) {
*what = value == "1" || value == "yes" || value == "t" || value == "true" || value == "on";
return true;
} else static if(is(T == K[], K)) {
K tmp;
if(name == paramName) {
@ -6552,6 +6584,8 @@ auto callFromCgi(alias method, T)(T dg, Cgi cgi) {
auto k = to!K(insideBrackets);
V v;
if(auto ptr = k in *what)
v = *ptr;
name = name[0 .. paramName.length];
//writeln(name, afterName, " ", paramName);

View File

@ -3,6 +3,7 @@ module arsd.database;
public import std.variant;
import std.string;
public import std.datetime;
/*
Database 2.0 plan, WIP:
@ -48,6 +49,9 @@ interface Database {
return queryImpl(sql, args);
}
/// turns a systime into a value understandable by the target database as a timestamp to be concated into a query. so it should be quoted and escaped etc as necessary
string sysTimeToValue(SysTime);
/// Prepared statement api
/*
PreparedStatement prepareStatement(string sql, int numberOfArguments);
@ -355,9 +359,14 @@ class SelectBuilder : SqlBuilder {
// used in the internal placeholder thing
string toSql(Database db, Variant a) {
auto v = a.peek!(void*);
if(v && (*v is null))
if(v && (*v is null)) {
return "NULL";
else {
} else if(auto t = a.peek!(SysTime)) {
return db.sysTimeToValue(*t);
} else if(auto t = a.peek!(DateTime)) {
// FIXME: this might be broken cuz of timezones!
return db.sysTimeToValue(cast(SysTime) *t);
} else {
string str = to!string(a);
return '\'' ~ db.escape(str) ~ '\'';
}

View File

@ -48,10 +48,29 @@ struct Nullable(T) {
isNull = false;
value = v;
}
T toArsdJsvar() { return value; }
}
struct Timestamp {
string value;
string toArsdJsvar() { return value; }
// FIXME: timezone
static Timestamp fromStrings(string date, string time) {
if(time.length < 6)
time ~= ":00";
import std.datetime;
return Timestamp(SysTime.fromISOExtString(date ~ "T" ~ time).toISOExtString());
}
}
SysTime parseDbTimestamp(string s) {
if(s.length == 0) return SysTime.init;
auto date = s[0 .. 10];
auto time = s[11 .. 20];
auto tz = s[20 .. $];
return SysTime.fromISOExtString(date ~ "T" ~ time ~ tz);
}
struct Constraint(string sql) {}
@ -61,6 +80,9 @@ struct UniqueIndex(Fields...) {}
struct Serial {
int value;
int toArsdJsvar() { return value; }
int getValue() { return value; }
alias getValue this;
}
@ -148,6 +170,7 @@ string generateCreateTableFor(alias O)() {
static foreach(attr; __traits(getAttributes, member)) {
static if(is(typeof(attr) == Default)) {
// FIXME: postgresism there, try current_timestamp in sqlite
sql ~= " DEFAULT " ~ attr.sql;
} else static if(is(attr == Unique)) {
sql ~= " UNIQUE";
@ -282,9 +305,11 @@ void insert(O)(ref O t, Database db) {
builder.addVariable(memberName, __traits(getMember, t, memberName));
else static if(is(T == bool))
builder.addVariable(memberName, __traits(getMember, t, memberName));
else static if(is(T == Timestamp))
{} // skipping... for now at least
else static if(is(T == enum))
else static if(is(T == Timestamp)) {
auto v = __traits(getMember, t, memberName).value;
if(v.length)
builder.addVariable(memberName, v);
} else static if(is(T == enum))
builder.addVariable(memberName, cast(int) __traits(getMember, t, memberName));
}
}}

20
http2.d
View File

@ -514,8 +514,28 @@ struct Uri {
}
}
n.removeDots();
return n;
}
void removeDots() {
auto parts = this.path.split("/");
string[] toKeep;
foreach(part; parts) {
if(part == ".") {
continue;
} else if(part == "..") {
toKeep = toKeep[0 .. $-1];
continue;
} else {
toKeep ~= part;
}
}
this.path = toKeep.join("/");
}
}
/*

View File

@ -49,6 +49,11 @@ class MsSql : Database {
query("START TRANSACTION");
}
// possible fixme, idk if this is right
override string sysTimeToValue(SysTime s) {
return "'" ~ escape(s.toISOExtString()) ~ "'";
}
ResultSet queryImpl(string sql, Variant[] args...) {
sql = escapedVariants(this, sql, args);

View File

@ -74,6 +74,9 @@ class MySqlResult : ResultSet {
mysql_free_result(result);
}
string sysTimeToValue(SysTime s) {
return "cast('" ~ escape(s.toISOExtString()) ~ "' as datetime)";
}
MYSQL_FIELD[] fields() {
int numFields = mysql_num_fields(result);

View File

@ -41,6 +41,10 @@ class PostgreSql : Database {
PQfinish(conn);
}
string sysTimeToValue(SysTime s) {
return "'" ~ escape(s.toISOExtString()) ~ "'::timestamptz";
}
/**
Prepared statement support

View File

@ -91,6 +91,10 @@ class Sqlite : Database {
throw new DatabaseException(error());
}
string sysTimeToValue(SysTime s) {
return "datetime('" ~ escape(s.toISOExtString()) ~ "')";
}
// my extension for easier editing
version(sqlite_extended_metadata_available) {
ResultByDataObject queryDataObject(T...)(string sql, T t) {

View File

@ -39,6 +39,30 @@ Document renderTemplate(string templateName, var context = var.emptyObject, var
return encodeComponent(f.get!string);
};
context.formatDate = function string(string s) {
if(s.length < 10)
return s;
auto year = s[0 .. 4];
auto month = s[5 .. 7];
auto day = s[8 .. 10];
return month ~ "/" ~ day ~ "/" ~ year;
};
context.formatTime = function string(string s) {
if(s.length < 20)
return s;
auto hour = s[11 .. 13].to!int;
auto minutes = s[14 .. 16].to!int;
auto seconds = s[17 .. 19].to!int;
auto am = (hour >= 12) ? "PM" : "AM";
if(hour > 12)
hour -= 12;
return hour.to!string ~ (minutes < 10 ? ":0" : ":") ~ minutes.to!string ~ " " ~ am;
};
auto skeleton = new Document(readText("templates/skeleton.html"), true, true);
auto document = new Document();
document.parseSawAspCode = (string) => true; // enable adding <% %> to the dom