-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexpense
executable file
·169 lines (143 loc) · 3.84 KB
/
expense
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
#! /usr/bin/env ruby
require 'pg'
require 'io/console'
class ExpenseData
attr_reader :connection
def initialize
@connection = PG.connect(dbname: "expenses")
setup_schema
end
def list_expenses
result = connection.exec("SELECT * FROM expenses ORDER BY created_on;")
print_count(result)
print_expenses(result)
print_total(result)
end
def add_expense(amount, memo)
unless amount && memo
puts "You must provide an amount and a memo."
return
end
sql = "INSERT INTO expenses (amount, memo) VALUES ($1, $2)"
connection.exec_params(sql, [amount, memo])
end
def search_expenses(query)
unless query
puts "You must provide a search query."
return
end
sql = "SELECT * FROM expenses WHERE memo ILIKE $1;"
result = connection.exec_params(sql, ["%#{query}%"])
print_count(result)
print_expenses(result)
print_total(result)
end
def delete_expense(id)
unless id
puts "You must specify the id of the expense you'd like to delete."
return
end
sql = "SELECT * FROM expenses where id = $1"
result = connection.exec_params(sql, [id])
if result.ntuples == 1
sql = "DELETE FROM expenses WHERE id = $1;"
connection.exec_params(sql, [id])
puts "The following expense has been deleted:"
print_expenses(result)
else
puts "There is no expense with the id '#{id}'."
return
end
end
def delete_all_expenses
puts "This will delete all expenses. Are you sure? (Y/n)"
unless $stdin.getch == 'Y'
return
end
connection.exec("DELETE FROM expenses;")
puts "All expenses have been deleted."
end
private
def print_expenses(result)
result.each do |tuple|
columns = [ tuple['id'].rjust(3),
tuple['created_on'].rjust(10),
tuple['amount'].rjust(12),
tuple['memo'] ]
puts columns.join(' | ')
end
end
def print_total(result)
if result.ntuples > 0
total = result.field_values('amount').map(&:to_f).inject(&:+)
puts '-' * 50
puts "Total #{('%.2f' % total).rjust(25)}"
end
end
def print_count(result)
if result.ntuples == 0
puts "There are no expenses."
else
puts "There are #{result.ntuples} expenses."
end
end
def setup_schema
result = connection.exec <<~SQL
SELECT COUNT(*)
FROM information_schema.tables
WHERE table_schema = 'public' AND table_name = 'expenses';
SQL
if result.field_values('count').first.to_i == 0
connection.exec <<~SQL
CREATE TABLE expenses (
id serial PRIMARY KEY,
amount numeric (6,2) NOT NULL,
memo varchar NOT NULL,
created_on date NOT NULL DEFAULT CURRENT_DATE,
CHECK (amount > 0)
);
SQL
end
end
end
class CLI
attr_reader :command, :arguments, :application
def initialize
@command = ARGV[0]
@arguments = ARGV[1..-1]
@application = ExpenseData.new
end
def run
case command
when "list"
application.list_expenses
when "add"
amount = arguments[0]
memo = arguments[1]
application.add_expense(amount, memo)
when "search"
query = arguments[0]
application.search_expenses(query)
when "delete"
id = arguments[0]
application.delete_expense(id)
when "clear"
application.delete_all_expenses
else
display_help
end
end
def display_help
puts <<~HELP
An expense recording system
Commands:
add AMOUNT MEMO [DATE] - record a new expense
clear - delete all expenses
list - list all expenses
delete NUMBER - remove expense with id NUMBER
search QUERY - list expenses with a matching memo field
HELP
end
end
cli = CLI.new
cli.run