Finding an employee record by name
Last updated
Last updated
We have been finding and displaying an employee record already, so this should be trivial to us by now. However, we have always used the id field as the key. This time, we are going to use the name of the employee as the key.
Click on the Find employee menu item to test it. For now, try to find an employee by the first name and last name.
But when you click on submit, you get this error:
It is looking for the postFindEmployee() method, so let’s create it.
Edit source\empcontrol.d and append this code:
void postFindEmployee(string fname, string lname)
{
import std.uni; //so we can use toUpper() function
string first = toUpper(fname);
string last = toUpper(lname);
Employee e = empModel.findEmployee(first, last);
if(e != Employee.init) render!("employee.dt", e);
else redirect("all_employees");
}
We are converting the names to uppercase because we are not sure how the names were inputted in the forms and saved in the database.
Edit source\empmodel.d and define this method at the end.
Employee findEmployee(string first, string last)
{
Employee e;
string sql = "select * from employees where upper(fname)=? and upper(lname)=?";
Prepared pstmt = conn.prepare(sql);
pstmt.setArgs(first, last);
Row[] rows = conn.query(pstmt).array;
if(rows.length == 0) return e;
return prepareEmployee(rows[0]);
}
In the SQL statement, we are also converting the names to uppercase before comparing. Instead of looking for the row ID, this time the method is looking for the first name and last name converted to uppercase.
Create views\employee.dt.
extends layout
block maincontent
include cssformgrid.dt
div.form-grid-wrapper
h2.center-align Employee details
div.form-grid
span.form-grid-label Employee number:
span.form-grid-field #{e.empid}
span.form-grid-label Department:
span.form-grid-field #{e.deprt}
span.form-grid-label Salary grade:
span.form-grid-field #{e.paygd}
span.form-grid-label Email address:
span.form-grid-field #{e.email}
span.form-grid-label First name:
span.form-grid-field #{e.fname}
span.form-grid-label Last name:
span.form-grid-field #{e.lname}
span.form-grid-label Phone:
span.form-grid-field #{e.phone}
span.form-grid-label Street address:
span.form-grid-field #{e.street}
span.form-grid-label City:
span.form-grid-field #{e.city}
span.form-grid-label Province:
span.form-grid-field #{e.province}
span.form-grid-label Postal code:
span.form-grid-field #{e.postcode}
span.form-grid-label ID Picture:
img(src="#{e.photo}", height="80px")
div
div
a(href="all_employees")
button.form-grid-button(type="button") Close
Then compile, run and refresh the browser. Look for an employee and click Find. If the employee was not found, it simply shows the home page.
But if the employee was found, the record should be displayed.
So here is the full source\empcontrol.d so far.
module empcontrol;
import vibe.vibe;
import empmodel;
class EmployeeController
{
EmployeeModel empModel;
private string realm = "The Lorem Ipsum Company";
this()
{
empModel = new EmployeeModel;
}
void index()
{
render!"index.dt";
}
void getAddEmployee()
{
render!("empadd.dt", departments, paygrades, provinces);
}
void postAddEmployee(Employee e)
{
import std.file;
import std.path;
import std.algorithm;
import vibe.http.auth.digest_auth;
auto pic = "picture" in request.files;
if(pic !is null)
{
string photopath = "none yet";
string ext = extension(pic.filename.name);
string[] exts = [".jpg", ".jpeg", ".png", ".gif"];
if(canFind(exts, ext))
{
photopath = "uploads/photos/" ~ e.fname ~ "_" ~ e.lname ~ ext;
string dir = "./public/uploads/photos/";
mkdirRecurse(dir);
string fullpath = dir ~ e.fname ~ "_" ~ e.lname ~ ext;
try moveFile(pic.tempPath, NativePath(fullpath));
catch (Exception ex) copyFile(pic.tempPath, NativePath(fullpath), true);
}
e.photo = photopath;
}
if(e.phone.length == 0) e.phone = "(123) 456 7890";
if(e.paygd.length == 0) e.paygd = "none yet";
if(e.postcode.length == 0) e.postcode = "A1A 1A1";
e.pword = createDigestPassword(realm, e.email, e.pword);
empModel.addEmployee(e);
redirect("all_employees");
}
void getAllEmployees()
{
Employee[] emps = empModel.getEmployees;
render!("emplistall.dt", emps);
}
void getEditEmployee(int id)
{
Employee e = empModel.getEmployee(id);
render!("empedit.dt", e, departments, paygrades, provinces);
}
void postEditEmployee(Employee e)
{
import std.file;
import std.path;
import std.algorithm;
import vibe.http.auth.digest_auth;
string photopath = e.photo;
auto pic = "picture" in request.files;
if(pic !is null)
{
string ext = extension(pic.filename.name);
string[] exts = [".jpg", ".jpeg", ".png", ".gif"];
if(canFind(exts, ext))
{
photopath = "uploads/photos/" ~ e.fname ~ "_" ~ e.lname ~ ext;
string dir = "./public/uploads/photos/";
mkdirRecurse(dir);
string fullpath = dir ~ e.fname ~ "_" ~ e.lname ~ ext;
try moveFile(pic.tempPath, NativePath(fullpath));
catch (Exception ex) copyFile(pic.tempPath, NativePath(fullpath), true);
}
}
e.photo = photopath;
if(e.phone.length == 0) e.phone = "(123) 456 7890";
if(e.paygd.length == 0) e.paygd = "none yet";
if(e.postcode.length == 0) e.postcode = "A1A 1A1";
e.pword = createDigestPassword(realm, e.email, e.pword);
empModel.editEmployee(e);
redirect("all_employees");
}
void getDeleteEmployee(int id)
{
Employee e = empModel.getEmployee(id);
render!("empdelete.dt", e);
}
void postDeleteEmployee(int id)
{
empModel.deleteEmployee(id);
redirect("all_employees");
}
void postFindEmployee(string fname, string lname)
{
import std.uni; //so we can use the toUpper() or toLower() function
string first = toUpper(fname);
string last = toUpper(lname);
Employee e = empModel.findEmployee(first, last);
if(e != Employee.init) render!("employee.dt", e);
else redirect("all_employees");
}
}
And here is the full source\empmodel.d so far.
module empmodel;
import mysql;
import std.conv;
import std.array;
struct Employee
{
int id; //row id or record id
string empid; //employee number
string deprt; //department
string paygd; //salary grade
string email; //email address
string pword; //password
string fname; //first name
string lname; //last name
string phone; //phone number
string photo; //ID photo
string street; //street address
string city; //city name
string province; //province name
string postcode; //postal code
}
struct Admin
{
string email; //email address
string pword; //passsword
}
string[] departments =
[
"Management and Admin",
"Accounting and Finance",
"Production",
"Maintenance",
"Shipping and Receiving",
"Purchasing and Supplies",
"IT Services",
"Human Resources",
"Marketing"
];
string[][] provinces =
[
["AB", "Alberta"],
["BC", "British Columbia"],
["MB", "Manitoba"],
["NB", "New Brunswick"],
["NL", "Newfoundland and Labrador"],
["NS", "Nova Scotia"],
["NT", "Northwest Territories"],
["NU", "Nunavut"],
["ON", "Ontario"],
["PE", "Prince Edward Island"],
["QC", "Quebec"],
["SK", "Saskatchewan"],
["YT", "Yukon Territory"]
];
string[] paygrades =
[
"A100", "A200", "A300", "A400",
"B100", "B200", "B300", "B400",
"C100", "C200", "C300", "C400",
"D100", "D200", "D300", "D400",
"E100", "E200", "E300", "E400",
"F100", "F200", "F300", "F400"
];
class EmployeeModel
{
Connection conn;
this()
{
string url = "host=localhost;port=3306;user=owner;pwd=qwerty;db=empdb";
conn = new Connection(url);
scope(exit) conn.close;
}
ulong addEmployee(Employee e)
{
string sql =
"insert into employees
(
empid,
deprt, paygd, email, pword,
fname, lname, phone, photo,
street, city, province, postcode
)
values(?,?,?,?,?,?,?,?,?,?,?,?,?)";
Prepared pstmt = conn.prepare(sql);
pstmt.setArgs
(
to!string(e.empid),
to!string(e.deprt),
to!string(e.paygd),
to!string(e.email),
to!string(e.pword),
to!string(e.fname),
to!string(e.lname),
to!string(e.phone),
to!string(e.photo),
to!string(e.street),
to!string(e.city),
to!string(e.province),
to!string(e.postcode)
);
return conn.exec(pstmt);
}
Employee[] getEmployees()
{
Employee[] emps;
string sql = "select * from employees";
Row[] rows = conn.query(sql).array;
if(rows.length == 0) return emps;
return prepareEmployees(rows);
}
Employee[] prepareEmployees(Row[] rows)
{
Employee[] emps;
foreach(row; rows)
{
Employee e = prepareEmployee(row);
emps ~= e;
}
return emps;
}
Employee prepareEmployee(Row row)
{
Employee e;
e.id = to!int(to!string(row[0]));
e.empid = to!string(row[1]);
e.deprt = to!string(row[2]);
e.paygd = to!string(row[3]);
e.email = to!string(row[4]);
e.pword = to!string(row[5]);
e.fname = to!string(row[6]);
e.lname = to!string(row[7]);
e.phone = to!string(row[8]);
e.photo = to!string(row[9]);
e.street = to!string(row[10]);
e.city = to!string(row[11]);
e.province = to!string(row[12]);
e.postcode = to!string(row[13]);
return e;
}
Employee getEmployee(int id)
{
string sql = "select * from employees where id=?";
Prepared pstmt = conn.prepare(sql);
pstmt.setArgs(id);
Employee e;
Row[] rows = conn.query(pstmt).array;
if(rows.length == 0) return e;
return prepareEmployee(rows[0]);
}
ulong editEmployee(Employee e)
{
string sql = "update employees set empid=?,
deprt=?, paygd=?, email=?, pword=?,
fname=?, lname=?, phone=?, photo=?,
street=?, city=?, province=?, postcode=?
where id=?";
Prepared pstmt = conn.prepare(sql);
pstmt.setArgs
(
to!string(e.empid),
to!string(e.deprt),
to!string(e.paygd),
to!string(e.email),
to!string(e.pword),
to!string(e.fname),
to!string(e.lname),
to!string(e.phone),
to!string(e.photo),
to!string(e.street),
to!string(e.city),
to!string(e.province),
to!string(e.postcode),
to!int(to!string(e.id))
);
return conn.exec(pstmt);
}
void deleteEmployee(int id)
{
string sql = "delete from employees where id=?";
Prepared pstmt = conn.prepare(sql);
pstmt.setArgs(id);
conn.exec(pstmt);
}
Employee findEmployee(string first, string last)
{
Employee e;
string sql = "select * from employees where upper(fname)=? and upper(lname)=?";
Prepared pstmt = conn.prepare(sql);
pstmt.setArgs(first, last);
Row[] rows = conn.query(pstmt).array;
if(rows.length == 0) return e;
return prepareEmployee(rows[0]);
}
}
Now we have gone through all the CRUD (create, read, update and delete) operations.
Next let’s talk about error trapping.