Skip to content

Commit

Permalink
Merge branch 'main' into electron-forge
Browse files Browse the repository at this point in the history
  • Loading branch information
Hbbb committed Feb 3, 2024
2 parents 8906446 + 41c8a21 commit a87d344
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 29 deletions.
13 changes: 8 additions & 5 deletions bin/budgeted-crontab.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
#/bin/sh
#/bin/bash

date=$(date +%Y-%m-%d)

echo "----- [$date] ETL: start -----" >> budgeted-cron-log.log
path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

echo "The script is located in: $path"

bin/budgeted-cli load plaid-data >> budgeted-cron-log.log
bin/budgeted-cli load csv >> budgeted-cron-log.log
bin/budgeted-cli load sqlite >> budgeted-cron-log.log
echo "----- [$date] ETL: start -----" >> budgeted-cron-log.log
$path/budgeted-cli load plaid-data >> budgeted-cron-log.log
$path/budgeted-cli load csv >> budgeted-cron-log.log
$path/budgeted-cli load sqlite >> budgeted-cron-log.log

echo "----- [$date] ETL: complete -----" >> budgeted-cron-log.log
4 changes: 2 additions & 2 deletions cli/internal/cmd/load.plaid-data.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ func LoadPlaidDataCmd(ctx context.Context) *cobra.Command {
}

for _, institution := range institutions {
err = pc.LoadTransactions(ctx, institution.PlaidAccessToken)
err = pc.LoadTransactions(ctx, institution.PlaidId, institution.PlaidAccessToken)

if err != nil {
return errors.Wrap(err, "failed to load transactions")
}

err = pc.LoadAccounts(ctx, institution.PlaidAccessToken)
err = pc.LoadAccounts(ctx, institution.PlaidId, institution.PlaidAccessToken)
if err != nil {
return errors.Wrap(err, "failed to load accounts")
}
Expand Down
17 changes: 17 additions & 0 deletions cli/internal/db/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 11 additions & 6 deletions cli/internal/db/query.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion cli/internal/db/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ CREATE TABLE IF NOT EXISTS "Institution" (
"plaidId" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"plaidAccessToken" TEXT NOT NULL
);
, "color" TEXT, "logo" TEXT);
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE IF NOT EXISTS "Transaction" (
"plaidId" TEXT NOT NULL PRIMARY KEY,
Expand Down Expand Up @@ -74,3 +74,17 @@ CREATE TABLE IF NOT EXISTS "AccountBalance" (
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "AccountBalance_accountPlaidId_fkey" FOREIGN KEY ("accountPlaidId") REFERENCES "Account" ("plaidId") ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE TABLE IF NOT EXISTS "Budget" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"amount" REAL NOT NULL,
"range" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "BudgetRule" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"budgetId" INTEGER NOT NULL,
"column" TEXT NOT NULL,
"operator" TEXT NOT NULL DEFAULT 'CONTAINS',
"value" TEXT NOT NULL,
CONSTRAINT "BudgetRule_budgetId_fkey" FOREIGN KEY ("budgetId") REFERENCES "Budget" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
5 changes: 3 additions & 2 deletions cli/internal/plaid/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"context"
"errors"
"io"
"path/filepath"

"github.com/plaid/plaid-go/v20/plaid"
)

func (pc *APIClient) LoadAccounts(ctx context.Context, accessToken string) error {
func (pc *APIClient) LoadAccounts(ctx context.Context, institutionId string, accessToken string) error {
accountsGetRequest := plaid.NewAccountsGetRequest(accessToken)
accountsGetRequest.SetOptions(plaid.AccountsGetRequestOptions{})

Expand All @@ -32,7 +33,7 @@ func (pc *APIClient) LoadAccounts(ctx context.Context, accessToken string) error
return err
}

if err = pc.SetCache(ctx, "accounts", "", body); err != nil {
if err = pc.SetCache(ctx, filepath.Join("accounts", institutionId), "", body); err != nil {
return err
}

Expand Down
19 changes: 15 additions & 4 deletions cli/internal/plaid/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ func (pc *APIClient) GetNextCursor(ctx context.Context, prefix string) (string,
if err := json.Unmarshal(data, syncResponse); err != nil {
return "", err
}

return syncResponse.GetNextCursor(), nil
}

func (pc *APIClient) GetCache(ctx context.Context, path string) ([]byte, error) {
func (pc *APIClient) GetCache(ctx context.Context, prefix string) ([]byte, error) {
var lastEntry os.DirEntry
cachePath := pc.cacheDir + "/" + path
cachePath := filepath.Join(pc.cacheDir, prefix)
err := os.MkdirAll(cachePath, 0755)
if err != nil {
return nil, err
}

entries, err := os.ReadDir(cachePath)
if err != nil {
Expand All @@ -58,9 +63,15 @@ func (pc *APIClient) GetCache(ctx context.Context, path string) ([]byte, error)
return nil, nil
}

func (pc *APIClient) SetCache(ctx context.Context, path string, cursor string, bytes []byte) error {
func (pc *APIClient) SetCache(ctx context.Context, prefix string, cursor string, bytes []byte) error {
cachePath := filepath.Join(pc.cacheDir, prefix)
err := os.MkdirAll(cachePath, 0755)
if err != nil {
return err
}

timestamp := strings.Replace(time.Now().Format(time.RFC3339Nano), ":", "X", -1)
fileName := filepath.Join(pc.cacheDir, path, fmt.Sprintf("%s_%s.json", timestamp, strings.Replace(cursor, "/", "_", -1)))
fileName := filepath.Join(cachePath, fmt.Sprintf("%s_%s.json", timestamp, strings.Replace(cursor, "/", "_", -1)))

log.Println("writing", fileName)
if err := os.WriteFile(fileName, bytes, 0644); err != nil {
Expand Down
8 changes: 5 additions & 3 deletions cli/internal/plaid/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ import (
"errors"
"io"
"log"
"path/filepath"

"github.com/plaid/plaid-go/v20/plaid"
)

func (pc *APIClient) LoadTransactions(ctx context.Context, accessToken string) error {
func (pc *APIClient) LoadTransactions(ctx context.Context, institutionId string, accessToken string) error {
var hasMore bool = true
prefix := filepath.Join("transactions", institutionId)

// Get previous cursor from the latest cached response
cursor, err := pc.GetNextCursor(ctx, "transactions")
cursor, err := pc.GetNextCursor(ctx, prefix)
if err != nil {
return err
}
Expand Down Expand Up @@ -64,7 +66,7 @@ func (pc *APIClient) LoadTransactions(ctx context.Context, accessToken string) e
nextCursor := resp.GetNextCursor()
cursor = nextCursor

if err := pc.SetCache(ctx, "transactions", cursor, body); err != nil {
if err := pc.SetCache(ctx, prefix, cursor, body); err != nil {
return err
}
}
Expand Down
8 changes: 6 additions & 2 deletions electron/lib/crontab/crontab.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { exec, execSync } from 'node:child_process'
import path from 'node:path'

const morningSyncEntry = '0 0 * * * bin/budgeted-crontab.sh'
const eveningSyncEntry = '0 12 * * * bin/budgeted-crontab.sh'
const pwd = execSync('pwd').toString().trim()
const scriptPath = path.join(pwd, 'bin/budgeted-crontab.sh')

const morningSyncEntry = `0 0 * * * ${scriptPath}`
const eveningSyncEntry = `0 12 * * * ${scriptPath}`

/**
* Writes the crontab entries for the morning and evening ETL jobs
Expand Down
17 changes: 17 additions & 0 deletions prisma/migrations/20240129234021_add_budgets/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- CreateTable
CREATE TABLE "Budget" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"amount" REAL NOT NULL,
"range" INTEGER NOT NULL
);

-- CreateTable
CREATE TABLE "BudgetRule" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"budgetId" INTEGER NOT NULL,
"column" TEXT NOT NULL,
"operator" TEXT NOT NULL DEFAULT 'CONTAINS',
"value" TEXT NOT NULL,
CONSTRAINT "BudgetRule_budgetId_fkey" FOREIGN KEY ("budgetId") REFERENCES "Budget" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
25 changes: 21 additions & 4 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,21 @@ model Account {
availableBalance Float?
isoCurrencyCode String?
transactions Transaction[]
Institution Institution? @relation(fields: [institutionPlaidId], references: [plaidId])
institution Institution? @relation(fields: [institutionPlaidId], references: [plaidId])
institutionPlaidId String?
importedAt DateTime @default(now())
importLog ImportLog? @relation(fields: [importLogId], references: [id])
importLogId Int?
AccountBalance AccountBalance[]
accountBalances AccountBalance[]
}

model ImportLog {
id Int @id @default(autoincrement())
syncStartedAt DateTime @default(now())
syncCompletedAt DateTime? @updatedAt
transactionsCount Int?
Transaction Transaction[]
Account Account[]
transactions Transaction[]
accounts Account[]
}

model AccountBalance {
Expand All @@ -89,3 +89,20 @@ model AccountBalance {
accountPlaidId String
createdAt DateTime @default(now())
}

model Budget {
id Int @id @default(autoincrement())
name String
amount Float
range Int
budgetRules BudgetRule[]
}

model BudgetRule {
id Int @id @default(autoincrement())
budget Budget @relation(fields: [budgetId], references: [id])
budgetId Int
column String
operator String @default("CONTAINS")
value String
}

0 comments on commit a87d344

Please sign in to comment.