-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bd9c025
commit 5ff381c
Showing
3 changed files
with
286 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
{ | ||
"cSpell.words": [ | ||
"imdb" | ||
"imdb", | ||
"sqdb" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package riemann | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"log" | ||
|
||
_ "github.com/mattn/go-sqlite3" | ||
) | ||
|
||
type SqliteDivisorDb struct { | ||
DBPath string | ||
db *sql.DB | ||
} | ||
|
||
func (sqdb SqliteDivisorDb) Initialize() { | ||
|
||
db, err := sql.Open("sqlite3", sqdb.DBPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
sqlStmt := ` | ||
CREATE TABLE RiemannDivisorSums ( | ||
n UNSIGNED BIG INT CONSTRAINT divisor_sum_pk PRIMARY KEY, | ||
divisor_sum UNSIGNED BIG INT, | ||
witness_value REAL | ||
); | ||
` | ||
_, err = db.Exec(sqlStmt) | ||
if err != nil { | ||
panic(err) | ||
} | ||
db.Close() | ||
} | ||
|
||
func (sqdb *SqliteDivisorDb) ensureInit() { | ||
db, err := sql.Open("sqlite3", sqdb.DBPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
sqdb.db = db | ||
} | ||
|
||
func (sqdb SqliteDivisorDb) Load() []RiemannDivisorSum { | ||
sqdb.ensureInit() | ||
defer sqdb.db.Close() | ||
sqlStmt := ` | ||
SELECT n, divisor_sum, witness_value | ||
FROM RiemannDivisorSums | ||
ORDER BY n asc; | ||
` | ||
rows, err := sqdb.db.Query(sqlStmt) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer rows.Close() | ||
output := []RiemannDivisorSum{} | ||
for rows.Next() { | ||
var n, divisorSum int64 | ||
var witnessValue float64 | ||
err = rows.Scan(&n, &divisorSum, &witnessValue) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
output = append(output, RiemannDivisorSum{ | ||
N: n, | ||
DivisorSum: divisorSum, | ||
WitnessValue: witnessValue, | ||
}) | ||
} | ||
return output | ||
} | ||
|
||
func (sqdb SqliteDivisorDb) Upsert(rds []RiemannDivisorSum) { | ||
sqdb.ensureInit() | ||
defer sqdb.db.Close() | ||
|
||
tx, err := sqdb.db.Begin() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
sqlStmt, err := tx.Prepare(` | ||
INSERT INTO | ||
RiemannDivisorSums(n, divisor_sum, witness_value) | ||
VALUES(?, ?, ?) | ||
ON CONFLICT(n) DO UPDATE SET | ||
divisor_sum=excluded.divisor_sum, | ||
witness_value=excluded.witness_value; | ||
; | ||
`) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer sqlStmt.Close() | ||
for _, value := range rds { | ||
_, err := sqlStmt.Exec( | ||
fmt.Sprintf("%d", value.N), | ||
fmt.Sprintf("%d", value.DivisorSum), | ||
fmt.Sprintf("%f", value.WitnessValue), | ||
) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
tx.Commit() | ||
sqdb.db.Close() | ||
} | ||
|
||
func (sqdb SqliteDivisorDb) Summarize() SummaryStats { | ||
sqdb.ensureInit() | ||
defer sqdb.db.Close() | ||
|
||
largestNStms := ` | ||
SELECT * | ||
FROM RiemannDivisorSums | ||
ORDER BY n DESC | ||
LIMIT 1; | ||
` | ||
row := sqdb.db.QueryRow(largestNStms) | ||
var n, divisorSum int64 | ||
var witnessValue float64 | ||
err := row.Scan(&n, &divisorSum, &witnessValue) | ||
if err != nil { | ||
return SummaryStats{ | ||
LargestWitnessValue: RiemannDivisorSum{}, | ||
LargestComputedN: RiemannDivisorSum{}, | ||
} | ||
} | ||
|
||
largest_computed_n := RiemannDivisorSum{ | ||
N: n, | ||
DivisorSum: divisorSum, | ||
WitnessValue: witnessValue, | ||
} | ||
|
||
largestWitnessStmt := ` | ||
SELECT * | ||
FROM RiemannDivisorSums | ||
ORDER BY witness_value DESC | ||
LIMIT 1; | ||
` | ||
row = sqdb.db.QueryRow(largestWitnessStmt) | ||
err = row.Scan(&n, &divisorSum, &witnessValue) | ||
if err != nil { | ||
panic(err) | ||
} | ||
largest_witness_value := RiemannDivisorSum{ | ||
N: n, | ||
DivisorSum: divisorSum, | ||
WitnessValue: witnessValue, | ||
} | ||
|
||
return SummaryStats{ | ||
LargestWitnessValue: largest_witness_value, | ||
LargestComputedN: largest_computed_n, | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package riemann_test | ||
|
||
import ( | ||
"os" | ||
"sort" | ||
|
||
"github.com/alexsanjoseph/riemann-divisor-sum-go/riemann" | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
const DBPath = "test.sqlite" | ||
|
||
var _ = BeforeEach(func() { | ||
os.Remove(DBPath) | ||
var db = riemann.DivisorDb(&riemann.SqliteDivisorDb{DBPath: DBPath}) | ||
db.Initialize() | ||
}) | ||
|
||
var _ = AfterEach(func() { | ||
os.Remove(DBPath) | ||
}) | ||
|
||
var _ = Describe("Sqlite Database Tests", func() { | ||
|
||
It("is initially empty", func() { | ||
var db = riemann.DivisorDb(&riemann.SqliteDivisorDb{DBPath: DBPath}) | ||
loadedData := db.Load() | ||
Expect(len(loadedData)).To(Equal(0)) | ||
}) | ||
|
||
It("Upserts correctly", func() { | ||
var db = riemann.DivisorDb(&riemann.SqliteDivisorDb{DBPath: DBPath}) | ||
records := []riemann.RiemannDivisorSum{ | ||
{N: 1, DivisorSum: 1, WitnessValue: 1}, | ||
{N: 2, DivisorSum: 2, WitnessValue: 2}, | ||
} | ||
|
||
By("upserting fine from empty", func() { | ||
db.Upsert(records) | ||
loadedData := db.Load() | ||
sort.Slice(loadedData, func(p, q int) bool { | ||
return loadedData[p].N < loadedData[q].N | ||
}) | ||
Expect(loadedData).To(Equal(records)) | ||
}) | ||
|
||
By("upserting fine from non-empty", func() { | ||
newRecords := []riemann.RiemannDivisorSum{ | ||
{N: 3, DivisorSum: 3, WitnessValue: 3}, | ||
{N: 4, DivisorSum: 4, WitnessValue: 4}, | ||
} | ||
db.Upsert(newRecords) | ||
loadedData := db.Load() | ||
sort.Slice(loadedData, func(p, q int) bool { | ||
return loadedData[p].N < loadedData[q].N | ||
}) | ||
Expect(loadedData).To(Equal(append(records, newRecords...))) | ||
}) | ||
|
||
By("overriding existing docs when upserted", func() { | ||
newRecords := []riemann.RiemannDivisorSum{ | ||
{N: 3, DivisorSum: 3, WitnessValue: 10}, | ||
{N: 5, DivisorSum: 5, WitnessValue: 5}, | ||
} | ||
expectedNewRecords := []riemann.RiemannDivisorSum{ | ||
{N: 3, DivisorSum: 3, WitnessValue: 10}, | ||
{N: 4, DivisorSum: 4, WitnessValue: 4}, | ||
{N: 5, DivisorSum: 5, WitnessValue: 5}, | ||
} | ||
db.Upsert(newRecords) | ||
loadedData := db.Load() | ||
sort.Slice(loadedData, func(p, q int) bool { | ||
return loadedData[p].N < loadedData[q].N | ||
}) | ||
Expect(loadedData).To(Equal(append(records, expectedNewRecords...))) | ||
}) | ||
|
||
}) | ||
|
||
It("Summarizes", func() { | ||
var db = riemann.DivisorDb(&riemann.SqliteDivisorDb{DBPath: DBPath}) | ||
By("correctly summarizing empty data", func() { | ||
summaryData := db.Summarize() | ||
expectedSummaryData := riemann.SummaryStats{ | ||
LargestWitnessValue: riemann.RiemannDivisorSum{}, | ||
LargestComputedN: riemann.RiemannDivisorSum{}, | ||
} | ||
Expect(summaryData).To(Equal(expectedSummaryData)) | ||
}) | ||
|
||
By("correctly summarizing non-empty data", func() { | ||
records := []riemann.RiemannDivisorSum{ | ||
{N: 1, DivisorSum: 1, WitnessValue: 10}, | ||
{N: 2, DivisorSum: 2, WitnessValue: 20}, | ||
{N: 3, DivisorSum: 2, WitnessValue: 3}, | ||
} | ||
db.Upsert(records) | ||
summaryData := db.Summarize() | ||
expectedSummaryData := riemann.SummaryStats{ | ||
LargestWitnessValue: riemann.RiemannDivisorSum{N: 2, DivisorSum: 2, WitnessValue: 20}, | ||
LargestComputedN: riemann.RiemannDivisorSum{N: 3, DivisorSum: 2, WitnessValue: 3}, | ||
} | ||
Expect(summaryData).To(Equal(expectedSummaryData)) | ||
}) | ||
|
||
}) | ||
|
||
It("Summarizes for float values", func() { | ||
var db = riemann.DivisorDb(&riemann.SqliteDivisorDb{DBPath: DBPath}) | ||
By("correctly summarizing non-empty data", func() { | ||
records := []riemann.RiemannDivisorSum{ | ||
{N: 10092, DivisorSum: 24388, WitnessValue: 1.088}, | ||
{N: 10080, DivisorSum: 39000, WitnessValue: 1.788}, | ||
} | ||
db.Upsert(records) | ||
summaryData := db.Summarize() | ||
expectedSummaryData := riemann.SummaryStats{ | ||
LargestWitnessValue: riemann.RiemannDivisorSum{N: 10080, DivisorSum: 39000, WitnessValue: 1.788}, | ||
LargestComputedN: riemann.RiemannDivisorSum{N: 10092, DivisorSum: 24388, WitnessValue: 1.088}, | ||
} | ||
Expect(summaryData).To(Equal(expectedSummaryData)) | ||
}) | ||
}) | ||
|
||
}) |