[base] Switch to mozbuild (#114)
[abstract.git] / storage / aaSaveEvent.cpp
blobbe66f509e5803281f6f3e25892230e3cc965fb9d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent tw=79 ft=cpp: */
3 /*
4 * Copyright (C) 2007 Sergey Yanovich <ynvich@gmail.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 #include <abstract/aacore.h>
24 #include "nsCOMPtr.h"
25 #include "nsStringAPI.h"
26 #include "nsEmbedString.h"
27 #include "nsIArray.h"
28 #include "nsArrayUtils.h"
30 /* Unfrozen API */
31 #include "unstable/mozIStorageConnection.h"
32 #include "unstable/mozIStorageStatement.h"
34 /* Project includes */
35 #include <abstract/base/aaIEntity.h>
36 #include <abstract/base/aaIFlow.h>
37 #include <abstract/base/aaIFact.h>
38 #include <abstract/base/aaIEvent.h>
39 #include <abstract/storage/aaISaveQuery.h>
40 #include "aaSaveEvent.h"
41 #include "aaGuard.h"
43 #define AA_READ_ID_BEGIN "SELECT id FROM "
44 #define AA_READ_ID_END " WHERE _ROWID_ == last_insert_rowid()"
46 #define AA_EVENT_SAVE "INSERT INTO event (day, id) SELECT\
47 (replace(round(julianday(?,'unixepoch')),'.0','')) AS _day,\
48 IFNULL(max(event.id),0) + 1 FROM event WHERE event.day == _day"
49 #define AA_TRANSFER_SAVE "INSERT INTO transfer (day, event_id, id, amount)\
50 SELECT (replace(round(julianday(?,'unixepoch')),'.0','')) AS _day,\
51 ? AS _event_id, IFNULL(MAX(transfer.id),0) + 1, ? FROM transfer\
52 WHERE transfer.day == _day AND transfer.event_id == _event_id"
53 #define AA_FACT_SAVE "INSERT INTO fact (day, event_id, transfer_id, side, flow_id)\
54 VALUES ((replace(round(julianday(?,'unixepoch')),'.0','')),?,?,?,?)"
55 #define AA_TRANSFER_VALIDATE "SELECT 1 FROM term AS termF, term AS termT\
56 WHERE termF.flow_id=? AND termF.side=1 AND termT.flow_id=? AND termT.side=0\
57 AND termF.resource_id=termT.resource_id;"
58 #define AA_STATE_LOAD "SELECT fact.flow_id, fact.side, fact.day,\
59 transfer.amount, flow.rate, state.id, state.start, state.side, state.amount\
60 FROM fact\
61 LEFT JOIN transfer ON fact.day == (replace(round(julianday(?,'unixepoch')),\
62 '.0', '')) AND fact.event_id == ? AND fact.day == transfer.day AND\
63 fact.event_id == transfer.event_id AND fact.transfer_id == transfer.id\
64 LEFT JOIN flow ON fact.flow_id == flow.id\
65 LEFT JOIN state ON fact.flow_id == state.flow_id AND state.paid IS NULL\
66 ORDER BY fact.flow_id, fact.side"
68 #define AA_STATE_INSERT "INSERT INTO state (flow_id, side,\
69 amount,start) VALUES (?,?,?,?)"
70 #define AA_STATE_DELETE "DELETE FROM state WHERE id == ?"
71 #define AA_STATE_UPDATE "UPDATE state SET side = ?, amount = ? WHERE id == ?"
72 #define AA_STATE_TERMINATE "UPDATE state SET paid = ? WHERE id == ?"
74 class State
76 public:
77 State() :mReady(0) {;}
78 State(mozIStorageStatement *aStatement);
79 ~State() { ; }
80 PRBool Adjust(mozIStorageConnection *aConnection);
81 private:
82 PRBool mReady;
83 PRInt64 mFlow;
84 PRBool mFactSide;
85 PRInt64 mDay;
86 double mFactSum;
87 double mRate;
88 PRBool mNew;
89 PRBool mUpdate;
90 PRInt64 mId;
91 PRBool mSide;
92 double mSum;
94 PRBool isSignificant() const {return (mSum > 0.00009) || (mSum < -0.00009);}
95 PRBool insert(mozIStorageConnection *aConnection);
96 PRBool update(mozIStorageConnection *aConnection);
97 PRBool replace(mozIStorageConnection *aConnection);
100 State::State(mozIStorageStatement *aStatement)
101 :mReady(PR_FALSE), mNew(PR_FALSE), mUpdate(PR_FALSE)
103 nsresult rv;
104 PRInt32 type;
105 PRInt64 stateStart;
107 rv = aStatement->GetInt64(0, &mFlow);
108 if (NS_FAILED(rv)) return;
110 rv = aStatement->GetInt32(1, &mFactSide);
111 if (NS_FAILED(rv)) return;
113 rv = aStatement->GetInt64(2, &mDay);
114 if (NS_FAILED(rv)) return;
116 rv = aStatement->GetDouble(3, &mFactSum);
117 if (NS_FAILED(rv)) return;
119 rv = aStatement->GetDouble(4, &mRate);
120 if (NS_FAILED(rv)) return;
122 rv = aStatement->GetTypeOfIndex(5, &type);
123 if (NS_FAILED(rv)) return;
125 if (type == mozIStorageValueArray::VALUE_TYPE_NULL) {
126 mSide = ! mFactSide;
127 mSum = mFactSum * (mSide ? mRate : (1 / mRate));
129 mNew = PR_TRUE;
130 mReady = PR_TRUE;
131 return;
134 rv = aStatement->GetInt64(5, &mId);
135 if (NS_FAILED(rv)) return;
137 rv = aStatement->GetInt64(6, &stateStart);
138 if (NS_FAILED(rv)) return;
140 if (stateStart == mDay)
141 mUpdate = PR_TRUE;
143 if (stateStart > mDay)
144 return;
146 rv = aStatement->GetInt32(7, &mSide);
147 if (NS_FAILED(rv)) return;
149 rv = aStatement->GetDouble(8, &mSum);
150 if (NS_FAILED(rv)) return;
152 if (mSide == mFactSide) {
153 double delta = mSum - mFactSum;
154 if (delta > 0) {
155 mSum = delta;
156 } else {
157 mSide = ! mSide;
158 mSum = -delta * (mSide ? mRate : (1 / mRate));
160 } else {
161 mSum += mFactSum;
164 mReady = PR_TRUE;
167 PRBool
168 State::Adjust(mozIStorageConnection *aConnection)
170 if (NS_UNLIKELY( !mReady ))
171 return PR_FALSE;
172 if ( mNew )
173 return insert(aConnection);
174 if ( mUpdate )
175 return update(aConnection);
176 return replace(aConnection);
179 PRBool
180 State::insert(mozIStorageConnection *aConnection)
182 nsresult rv;
184 if (! isSignificant() )
185 return PR_FALSE;
187 nsCOMPtr<mozIStorageStatement> statement;
188 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_INSERT),
189 getter_AddRefs(statement));
190 NS_ENSURE_SUCCESS(rv, PR_FALSE);
192 rv = statement->BindInt64Parameter(0, mFlow);
193 NS_ENSURE_SUCCESS(rv, PR_FALSE);
195 rv = statement->BindInt64Parameter(1, mSide);
196 NS_ENSURE_SUCCESS(rv, PR_FALSE);
198 rv = statement->BindDoubleParameter(2, mSum);
199 NS_ENSURE_SUCCESS(rv, PR_FALSE);
201 rv = statement->BindInt64Parameter(3, mDay);
202 NS_ENSURE_SUCCESS(rv, PR_FALSE);
204 rv = statement->Execute();
205 NS_ENSURE_SUCCESS(rv, PR_FALSE);
207 return PR_TRUE;
210 PRBool
211 State::update(mozIStorageConnection *aConnection)
213 nsresult rv;
214 nsCOMPtr<mozIStorageStatement> statement;
216 if (! isSignificant() ) {
217 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_DELETE),
218 getter_AddRefs(statement));
219 NS_ENSURE_SUCCESS(rv, PR_FALSE);
221 rv = statement->BindInt64Parameter(0, mId);
222 NS_ENSURE_SUCCESS(rv, PR_FALSE);
223 } else {
224 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_UPDATE),
225 getter_AddRefs(statement));
226 NS_ENSURE_SUCCESS(rv, PR_FALSE);
228 rv = statement->BindInt64Parameter(0, mSide);
229 NS_ENSURE_SUCCESS(rv, PR_FALSE);
231 rv = statement->BindDoubleParameter(1, mSum);
232 NS_ENSURE_SUCCESS(rv, PR_FALSE);
234 rv = statement->BindInt64Parameter(2, mId);
235 NS_ENSURE_SUCCESS(rv, PR_FALSE);
238 rv = statement->Execute();
239 NS_ENSURE_SUCCESS(rv, PR_FALSE);
241 return PR_TRUE;
244 PRBool
245 State::replace(mozIStorageConnection *aConnection)
247 nsresult rv;
248 nsCOMPtr<mozIStorageStatement> statement;
250 rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_TERMINATE),
251 getter_AddRefs(statement));
252 NS_ENSURE_SUCCESS(rv, PR_FALSE);
254 rv = statement->BindInt64Parameter(0, mDay);
255 NS_ENSURE_SUCCESS(rv, PR_FALSE);
257 rv = statement->BindInt64Parameter(1, mId);
258 NS_ENSURE_SUCCESS(rv, PR_FALSE);
260 rv = statement->Execute();
261 NS_ENSURE_SUCCESS(rv, PR_FALSE);
263 if ( isSignificant() )
264 return insert(aConnection);
266 return PR_TRUE;
269 /*************** aaSaveEvent **********************/
270 aaSaveEvent::aaSaveEvent(nsISupports *aOuter)
272 nsresult rv;
273 mConnection = do_QueryInterface(aOuter);
274 PRBool isReady;
275 if (! mConnection)
276 return;
277 rv = mConnection->GetConnectionReady(&isReady);
278 if (NS_FAILED(rv))
279 mConnection = nsnull;
282 aaSaveEvent::~aaSaveEvent()
286 NS_IMPL_ISUPPORTS1(aaSaveEvent,
287 aaISaveQuery)
288 /* aaISaveQuery */
289 NS_IMETHODIMP
290 aaSaveEvent::Save(aaIDataNode *aNode, aaIDataNode *aOldNode)
292 NS_ENSURE_TRUE(! aOldNode, NS_ERROR_INVALID_ARG);
294 nsCOMPtr<aaIEvent> event(do_QueryInterface(aNode));
295 NS_ENSURE_ARG_POINTER(event);
297 nsCOMPtr<nsIArray> block(do_QueryInterface(aNode));
298 NS_ENSURE_ARG_POINTER(block);
300 nsresult rv;
301 PRUint32 i = 0, count;
302 rv = block->GetLength( &count );
303 NS_ENSURE_SUCCESS(rv, rv);
304 NS_ENSURE_TRUE(count, NS_ERROR_INVALID_ARG);
306 rv = mConnection->BeginTransaction();
307 NS_ENSURE_SUCCESS(rv, rv);
310 aaGuard guard(mConnection);
311 rv = saveEvent(event);
312 NS_ENSURE_SUCCESS(rv, rv);
314 nsCOMPtr<aaIFact> fact;
315 for (; i < count; i++) {
316 fact = do_QueryElementAt(block, i);
317 NS_ENSURE_TRUE(fact, NS_ERROR_INVALID_ARG);
318 fact->SetEvent( event );
319 rv = saveFact(fact);
320 if (NS_FAILED(rv)) return rv;
322 rv = adjustStates(event);
323 NS_ENSURE_SUCCESS(rv, rv);
324 return guard.Dismiss();
328 /* Private methods */
329 PRInt64
330 aaSaveEvent::readID(const char *table)
332 nsresult rv;
334 nsEmbedCString query(AA_READ_ID_BEGIN);
335 query += table;
336 query += AA_READ_ID_END;
338 nsCOMPtr<mozIStorageStatement> statement;
339 rv = mConnection->CreateStatement(query, getter_AddRefs(statement));
340 NS_ENSURE_SUCCESS(rv, -1);
342 PRBool ignore;
343 rv = statement->ExecuteStep(&ignore);
344 NS_ENSURE_SUCCESS(rv, -1);
346 PRInt64 id = -1;
347 rv = statement->GetInt64(0, &id);
348 statement->Reset();
350 return id;
353 nsresult
354 aaSaveEvent::saveEvent(aaIEvent *aEvent)
356 nsresult rv;
358 PRTime time;
359 rv = aEvent->GetTime(&time);
360 NS_ENSURE_SUCCESS(rv, rv);
361 time /= 1000000;
363 nsCOMPtr<mozIStorageStatement> statement;
364 rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(AA_EVENT_SAVE),
365 getter_AddRefs(statement));
366 NS_ENSURE_SUCCESS(rv, rv);
368 rv = statement->BindInt64Parameter(0, time);
369 NS_ENSURE_SUCCESS(rv, rv);
371 rv = statement->Execute();
372 NS_ENSURE_SUCCESS(rv, rv);
374 PRInt64 id = readID("event");
375 NS_ENSURE_SUCCESS(id != -1, NS_ERROR_FAILURE);
377 return aEvent->SetId(id);
380 nsresult
381 aaSaveEvent::validateTransfer(PRInt64 fromFlowId, PRInt64 toFlowId)
383 NS_ENSURE_TRUE(fromFlowId || toFlowId, NS_ERROR_INVALID_ARG);
384 if (!fromFlowId || ! toFlowId)
385 return NS_OK;
387 nsresult rv;
388 nsCOMPtr<mozIStorageStatement> statement;
389 rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(AA_TRANSFER_VALIDATE),
390 getter_AddRefs(statement));
391 NS_ENSURE_SUCCESS(rv, rv);
393 rv = statement->BindInt64Parameter(0, fromFlowId);
394 NS_ENSURE_SUCCESS(rv, rv);
396 rv = statement->BindInt64Parameter(1, toFlowId);
397 NS_ENSURE_SUCCESS(rv, rv);
399 PRBool isFirst = PR_TRUE;
400 PRBool hasMore;
401 PRInt32 state;
402 do {
403 rv = statement->ExecuteStep(&hasMore);
404 if (NS_FAILED(rv))
405 break;
406 rv = statement->GetState(&state);
407 if (NS_FAILED(rv))
408 break;
409 if (state != mozIStorageStatement::MOZ_STORAGE_STATEMENT_EXECUTING) {
410 if (isFirst) {
411 statement->Reset();
412 return NS_ERROR_FAILURE;
414 } else {
415 if (!isFirst) {
416 rv = NS_ERROR_FAILURE;
417 break;
419 isFirst = PR_FALSE;
421 } while (hasMore);
422 statement->Reset();
423 NS_ENSURE_SUCCESS(rv, rv);
425 return rv;
428 nsresult
429 aaSaveEvent::saveAct(aaIFact *fact)
431 NS_ENSURE_ARG_POINTER(fact);
433 nsresult rv;
434 double amount;
435 rv = fact->GetAmount( &amount );
436 NS_ENSURE_SUCCESS(rv, rv);
437 NS_ENSURE_TRUE(amount > 0.00009 || amount < -0.00009, NS_ERROR_INVALID_ARG);
439 PRTime time;
440 rv = fact->GetTime(&time);
441 NS_ENSURE_SUCCESS(rv, rv);
442 time /= 1000000;
444 PRInt64 eventId;
445 rv = fact->GetEventId(&eventId);
446 NS_ENSURE_SUCCESS(rv, rv);
448 nsCOMPtr<mozIStorageStatement> statement;
449 rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(AA_TRANSFER_SAVE),
450 getter_AddRefs(statement));
451 NS_ENSURE_SUCCESS(rv, rv);
453 rv = statement->BindInt64Parameter(0, time);
454 NS_ENSURE_SUCCESS(rv, rv);
455 rv = statement->BindInt64Parameter(1, eventId);
456 NS_ENSURE_SUCCESS(rv, rv);
457 rv = statement->BindDoubleParameter(2, amount);
458 NS_ENSURE_SUCCESS(rv, rv);
460 rv = statement->Execute();
461 NS_ENSURE_SUCCESS(rv, rv);
463 PRInt64 id = readID("transfer");
464 NS_ENSURE_SUCCESS(id != -1, NS_ERROR_FAILURE);
466 rv = fact->SetId(id);
467 NS_ENSURE_SUCCESS(rv, rv);
469 return NS_OK;
472 nsresult
473 aaSaveEvent::saveFact(aaIFact *fact)
475 NS_ENSURE_ARG_POINTER(fact);
477 nsresult rv;
478 PRInt64 giveFlowId = 0, takeFlowId = 0, eventId, factId;
479 nsCOMPtr<aaIFlow> flow;
480 rv = fact->GetTakeFrom(getter_AddRefs( flow ));
481 NS_ENSURE_SUCCESS(rv, rv);
482 if (flow) {
483 rv = flow->GetId( &takeFlowId );
484 NS_ENSURE_SUCCESS(rv, rv);
487 rv = fact->GetGiveTo(getter_AddRefs( flow ));
488 NS_ENSURE_SUCCESS(rv, rv);
489 if (flow) {
490 rv = flow->GetId( &giveFlowId );
491 NS_ENSURE_SUCCESS(rv, rv);
494 rv = validateTransfer(takeFlowId, giveFlowId);
495 if (NS_FAILED(rv)) return rv;
497 rv = saveAct(fact);
498 NS_ENSURE_SUCCESS(rv, rv);
500 PRTime time;
501 rv = fact->GetTime(&time);
502 NS_ENSURE_SUCCESS(rv, rv);
503 time /= 1000000;
505 rv = fact->GetEventId(&eventId);
506 NS_ENSURE_SUCCESS(rv, rv);
508 rv = fact->GetId(&factId);
509 NS_ENSURE_SUCCESS(rv, rv);
511 nsCOMPtr<mozIStorageStatement> statement;
512 rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(AA_FACT_SAVE),
513 getter_AddRefs(statement));
514 NS_ENSURE_SUCCESS(rv, rv);
516 if (giveFlowId) {
517 rv = statement->BindInt64Parameter(0, time);
518 NS_ENSURE_SUCCESS(rv, rv);
519 rv = statement->BindInt64Parameter(1, eventId);
520 NS_ENSURE_SUCCESS(rv, rv);
521 rv = statement->BindInt64Parameter(2, factId);
522 NS_ENSURE_SUCCESS(rv, rv);
523 rv = statement->BindInt32Parameter(3, 0);
524 NS_ENSURE_SUCCESS(rv, rv);
525 rv = statement->BindInt64Parameter(4, giveFlowId);
526 NS_ENSURE_SUCCESS(rv, rv);
528 rv = statement->Execute();
529 NS_ENSURE_SUCCESS(rv, rv);
531 if (takeFlowId) {
532 rv = statement->BindInt64Parameter(0, time);
533 NS_ENSURE_SUCCESS(rv, rv);
534 rv = statement->BindInt64Parameter(1, eventId);
535 NS_ENSURE_SUCCESS(rv, rv);
536 rv = statement->BindInt64Parameter(2, factId);
537 NS_ENSURE_SUCCESS(rv, rv);
538 rv = statement->BindInt32Parameter(3, 1);
539 NS_ENSURE_SUCCESS(rv, rv);
540 rv = statement->BindInt64Parameter(4, takeFlowId);
541 NS_ENSURE_SUCCESS(rv, rv);
543 rv = statement->Execute();
544 NS_ENSURE_SUCCESS(rv, rv);
546 return NS_OK;
549 nsresult
550 aaSaveEvent::adjustStates(aaIEvent *aEvent)
552 nsresult rv;
553 nsCOMPtr<mozIStorageStatement> statement;
555 PRInt64 eventId;
556 rv = aEvent->GetId(&eventId);
557 NS_ENSURE_SUCCESS(rv, rv);
559 PRTime time;
560 rv = aEvent->GetTime(&time);
561 NS_ENSURE_SUCCESS(rv, rv);
562 time /= 1000000;
564 rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(AA_STATE_LOAD),
565 getter_AddRefs(statement));
566 NS_ENSURE_SUCCESS(rv, rv);
568 rv = statement->BindInt64Parameter(0, time);
569 NS_ENSURE_SUCCESS(rv, rv);
571 rv = statement->BindInt64Parameter(1, eventId);
572 NS_ENSURE_SUCCESS(rv, rv);
574 PRBool hasMore;
575 PRInt32 state;
576 do {
577 rv = statement->ExecuteStep(&hasMore);
578 if (NS_FAILED(rv))
579 break;
580 rv = statement->GetState(&state);
581 if (NS_FAILED(rv))
582 break;
583 if (state == mozIStorageStatement::MOZ_STORAGE_STATEMENT_EXECUTING) {
584 State state(statement);
585 if (! state.Adjust(mConnection) ) {
586 rv = NS_ERROR_FAILURE;
587 break;
590 } while (hasMore);
591 statement->Reset();
592 NS_ENSURE_SUCCESS(rv, rv);
594 return rv;