From df0df49aae07c6eb3ae955ee86f10959b7fc4a02 Mon Sep 17 00:00:00 2001 From: Chris Belsole Date: Tue, 15 Jun 2021 13:17:02 -0400 Subject: [PATCH 1/4] updated worksheets and dat and changed references to homelight --- .circleci/config.yml | 4 +- Makefile | 2 +- README.md | 347 ++++++++++++++++++------------------ bench_test.go | 2 +- computed_by_test.go | 2 +- dbstore.go | 4 +- dbstore_test.go | 2 +- enums_test.go | 2 +- examples/feature_test.go | 2 +- fuzz/fuzz.go | 2 +- go.mod | 7 +- go.sum | 36 +--- refs_test.go | 2 +- slices_test.go | 2 +- testutil_test.go | 2 +- tools/wstest.go | 2 +- worksheets.go | 2 +- wstesting/wstesting.go | 2 +- wstesting/wstesting_test.go | 2 +- 19 files changed, 203 insertions(+), 223 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4955d16..b271dff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ shared: &run_steps # postgres - run: sudo apt install postgresql-client - - run: psql ws_test ws_user -h localhost -p 5432 -f /go/src/github.com/helloeave/worksheets/schema.sql + - run: psql ws_test ws_user -h localhost -p 5432 -f /go/src/github.com/homelight/worksheets/schema.sql # golang - run: go get -v -t -d ./... @@ -27,7 +27,7 @@ jobs: POSTGRES_DB: ws_test POSTGRES_PASSWORD: "" - working_directory: /go/src/github.com/helloeave/worksheets + working_directory: /go/src/github.com/homelight/worksheets <<: *run_steps workflows: diff --git a/Makefile b/Makefile index c86e0c1..5b78a9e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ fuzz: clean - go-fuzz-build github.com/helloeave/worksheets/fuzz + go-fuzz-build github.com/homelight/worksheets/fuzz go-fuzz -bin=./worksheets-fuzz.zip -workdir=fuzz/ clean: diff --git a/README.md b/README.md index a394de2..6d6c08e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Worksheets -- Overview [![CircleCI](https://circleci.com/gh/helloeave/worksheets.svg?style=svg&circle-token=273512d656713e7f4a7ed0d464aa297999c54f0b)](https://circleci.com/gh/helloeave/worksheets) -[![GoDoc](https://godoc.org/github.com/helloeave/worksheets?status.svg)](https://godoc.org/github.com/helloeave/worksheets) +[![GoDoc](https://godoc.org/github.com/homelight/worksheets?status.svg)](https://godoc.org/github.com/homelight/worksheets) ## Prerequisites @@ -13,33 +13,33 @@ Let's start with a motivating example, easily representing a borrower's legal na We start by giving the definition for what data describe a `borrower` worksheet - worksheet borrower { - 1:first_name text - 2:last_name text - 3:dob date - 4:can_take_mortgage computed { - return dob > now + 18 years - } - } + worksheet borrower { + 1:first_name text + 2:last_name text + 3:dob date + 4:can_take_mortgage computed { + return dob > now + 18 years + } + } From this definition, we generate Golang hooks to manipulte borrowers' worksheets, store and retrieve them - joey := worksheet.Create("borrower") - joey.SetText("first_name", "Joey") - joey.SetText("last_name", "Pizzapie") - joey.SetDate("dob", 1980, 5, 23) + joey := worksheet.Create("borrower") + joey.SetText("first_name", "Joey") + joey.SetText("last_name", "Pizzapie") + joey.SetDate("dob", 1980, 5, 23) We can query worksheet - joey.GetBool("can_take_mortgage") + joey.GetBool("can_take_mortgage") Store the worksheet - bytes, err := joey.Marshal() + bytes, err := joey.Marshal() And retrieve the worksheet - joey, err := worksheet.Unmarshal("borrower", bytes) + joey, err := worksheet.Unmarshal("borrower", bytes) # Contributing @@ -47,19 +47,18 @@ And retrieve the worksheet If you want to contribute, you can get tests running locally as follows: - - cd path/to/worksheets - createuser --createdb ws_user - createdb --username=ws_user ws_test - psql -U ws_user ws_test -f schema.sql - go get -t ./... - go test -v ./... + cd path/to/worksheets + createuser --createdb ws_user + createdb --username=ws_user ws_test + psql -U ws_user ws_test -f schema.sql + go get -t ./... + go test -v ./... or `$ go test -v ./... -testify.m ` for individual tests. To update your schema, you can simply re-run - psql -U ws_user ws_test -f schema.sql + psql -U ws_user ws_test -f schema.sql ## Running Benchmarks @@ -67,24 +66,24 @@ For benchmarks to be interesting, we need to have a primed database with lots of In `bench_test.go`, the start of each benchmark has priming code, e.g. `b.prime(100000)`. You'll want to run benchmarks in two steps: 1. put a high number to prime the databse with lots of data, then run the benchmark - go test -v -run=NOTHING -bench=. -benchtime=15s + go test -v -run=NOTHING -bench=. -benchtime=15s This will take a long time, since before running, the benchmark will first write a lot of data in the local db. Once that completes, you can comment out or change the priming to `0`, and run the benchmark again - go test -v -run=NOTHING -bench=. -benchtime=15s + go test -v -run=NOTHING -bench=. -benchtime=15s # Worksheet Definition All centers around the concept of a `worksheet` which is constituted of typed named fields - worksheet person { - 1:age number[0] - 2:first_name text - } + worksheet person { + 1:age number[0] + 2:first_name text + } The general syntax for a field is - index:name type [extras] + index:name type [extras] (We explain the need for the index in the storage section. Those familiar with Thrift or Protocol Buffers can see the parralel with these data representation tools.) @@ -96,11 +95,11 @@ The simplest fields we have are there to store values. In the example above, bot Input fields can also be constrained - 3:social_security_number number[0] constrained_by { - ok := 100_00_0000 <= social_security_number - ok = ok && social_security_number <= 999_99_9999 - return ok - } + 3:social_security_number number[0] constrained_by { + ok := 100_00_0000 <= social_security_number + ok = ok && social_security_number <= 999_99_9999 + return ok + } When fields are constrained, edits which do not satisfy the constraint are rejected. @@ -108,10 +107,10 @@ When fields are constrained, edits which do not satisfy the constraint are rejec We can also derive values from the various inputs. We call these 'output fields' or computed fields - 1:date_of_birth date - 2:age number[0] computed_by { - return (now - date) in years - } + 1:date_of_birth date + 2:age number[0] computed_by { + return (now - date) in years + } (We discuss the syntax in which expressions can be written in a later section.) @@ -121,7 +120,7 @@ Computed fields are determined when their inputs changes, and then materialized. All worksheets have a unique identifier - id text + id text Which is set upon creation, and cannot be ever edited. @@ -129,7 +128,7 @@ Which is set upon creation, and cannot be ever edited. All worksheets are versionned, with their version number starting at `1`. The version is stored in a field present on all worksheets - version number[0] + version number[0] This `version` field is set to `1` upon creation, and incremented on every edit. Versions are used to detect concurrent edits, and abort an edit that was done on an older version of the worksheet than the one it would now be applied to. Edits are discussed in greater detail later. @@ -157,35 +156,35 @@ _TODO(pascal): We likely want to support enums in the language to allow introspe While the language does not have a specific support for enums, these can be described easily with the use of single field worksheets - worksheet name_suffixes { - 1:suffix text constrained_by { - return suffix in [ - "Jr.", - "Sr." - ... - ] - } - } + worksheet name_suffixes { + 1:suffix text constrained_by { + return suffix in [ + "Jr.", + "Sr." + ... + ] + } + } Which can then be used - worksheet borrower { - ... + worksheet borrower { + ... - 3:first_name text - 4:last_name text - 5:suffix name_suffixes + 3:first_name text + 4:last_name text + 5:suffix name_suffixes - ... - } + ... + } And the Golang hooks allow handling of single field worksheets in a natural way, by automatically 'boxing' - borrower.SetText("suffix", "Jr.") + borrower.SetText("suffix", "Jr.") Or 'unboxing' - borrower.GetText("suffix") + borrower.GetText("suffix") ### Numbers @@ -207,7 +206,7 @@ Loss of precision however needs to be explicitely handled. For instance, with the field `age number[0]`, the expression - age, _ = 5.200 round down + age, _ = 5.200 round down would yield `5` in the `age` field. @@ -237,35 +236,35 @@ When dividing, a rounding mode must always be provided such that the syntax for For instance, consider the following example. We need to create a `map[repayment]` to represent repayment of $700 in yearly taxes, over a 12 months period. If we were to split in equal parts, we would need to pay $58.33... which is not feasibly. Instead, here we force ourselves to round to cents, i.e. a `number[2]`. - first_month = month of closing_date + 1 - total_paid := 0 - for current_month := first_month; current_month < first_month + 1 year; current_month++ { - mp := yearly_taxes / 12 round down - total_paid += mp - payment_schedule << payment { - month = current_month - amount = mp - } - } - - remainder := yearly_taxes - total_paid - switch remainder % 2 { - case 0: - payment_schedule[first_month + 6 months].amount += remainder / 2 - payment_schedule[first_month + 12 months].amount += remainder / 2 - case 1: - payment_schedule[first_month + 12 months].amount += remainder - } + first_month = month of closing_date + 1 + total_paid := 0 + for current_month := first_month; current_month < first_month + 1 year; current_month++ { + mp := yearly_taxes / 12 round down + total_paid += mp + payment_schedule << payment { + month = current_month + amount = mp + } + } + + remainder := yearly_taxes - total_paid + switch remainder % 2 { + case 0: + payment_schedule[first_month + 6 months].amount += remainder / 2 + payment_schedule[first_month + 12 months].amount += remainder / 2 + case 1: + payment_schedule[first_month + 12 months].amount += remainder + } ### Time and Date _TODO(pascal) Write this out._ -* time as instant in time, timezone less concept, only display (because it can be lossy) needs timezone in some cases +- time as instant in time, timezone less concept, only display (because it can be lossy) needs timezone in some cases -* date as a timezone depenedent concept, range of time, so 9/1/2017 ET delineates a specific range +- date as a timezone depenedent concept, range of time, so 9/1/2017 ET delineates a specific range -* date without timezone, to represent input of borrowers, needs to then be interpreted in the context of a timezone to be useful +- date without timezone, to represent input of borrowers, needs to then be interpreted in the context of a timezone to be useful also, how do we convert to date objects @@ -277,16 +276,16 @@ some_date.year / .month / .day -> yields sub-component (since date is already tz ## Slices -* have slices too! -* describe operations on slices, simplified because we don't really care about pre-allocating, so the simplest `slice = append(slice, value)` is enough, the `len(slice)`, then things like `slice[index]` as well as re-slicing `slice[start:]`, `slice[:end]`, or `slice[start:end]` -* would be have `undefined` for slices, or only empty? having an unknonw number of middle names is different than no middle name for instance, which would push towards having `undefined` -* likely same consideration as maps in terms of which values can be placed in a slice +- have slices too! +- describe operations on slices, simplified because we don't really care about pre-allocating, so the simplest `slice = append(slice, value)` is enough, the `len(slice)`, then things like `slice[index]` as well as re-slicing `slice[start:]`, `slice[:end]`, or `slice[start:end]` +- would be have `undefined` for slices, or only empty? having an unknonw number of middle names is different than no middle name for instance, which would push towards having `undefined` +- likely same consideration as maps in terms of which values can be placed in a slice ## Keyed Worksheets, Maps, and Tuples In addition to the structures covered earlier, we have - map[W] + map[W] which represents a collection of worksheets `W`, indexed by the key of `W`. @@ -294,7 +293,7 @@ which represents a collection of worksheets `W`, indexed by the key of `W`. As we shall see in the next section, worksheets' keys can be one or multiple values joined together in N-tuples. To represent this, we introduce - tuple[T1, ..., Tn] + tuple[T1, ..., Tn] NOTE #1: We don't want to allow `tuple[map[foo]]`, so how do we differentiate the simple types, from more complex types like maps? Maps can be the type of fields, but the type which can go in tuples is a subset of that. Maybe 'base type' as `S` and field type `T` is a sufficient distinction? Then maps and tuples would be field types, one over worksheets, the other over only base types. @@ -305,13 +304,13 @@ NOTE #2: It would make sense to have undefindeness defined only over base types, Worksheets present in maps must keyed: one or more fields of the worksheet serve as a unique key for the purpose of the mapping keyed_by { - first_name - last_name + first_name + last_name } or - keyed_by identity + keyed_by identity When a worksheet is added in a map for the first time, all the fields covered by the key are frozen and are not allowed to be mutated later. This means that if a computed field is part of a key, all the inputs to this computed fields will be frozen. @@ -331,15 +330,15 @@ when iterating over maps, iteration order is the order in which items were added have a way to have 'interface' worksheets which expose set of fields, e.g. - view income { - yearly_gross_income number[2] - } + view income { + yearly_gross_income number[2] + } and then describe certain worksheets as conforming with these views - worksheet w2_income implements income { - ... - } + worksheet w2_income implements income { + ... + } # Editing Worksheets @@ -351,23 +350,23 @@ There are a three basic steps to editing a worksheet Let's go through them with the help of a contrived example - worksheet borrower { - 1:name text - 2:greeting text computed { - return "Hello, " + name - } - } + worksheet borrower { + 1:name text + 2:greeting text computed { + return "Hello, " + name + } + } We can _propose_ the edit - set name "Joey" + set name "Joey" Which yields the _actual_ edit - [ on borrower(the-id-here) @ version 5 ] - [ set version 6 ] - set name "Joey" - set greeting "Hello, Joey" + [ on borrower(the-id-here) @ version 5 ] + [ set version 6 ] + set name "Joey" + set greeting "Hello, Joey" And when _applied_ mutates the worksheet as intended. (In future examples, we omit the concurrent modification part of edits.) @@ -391,33 +390,33 @@ When a proposed edit block is applied to a worksheet, all computed fields whose Let's consider the worksheet - worksheet borrower { - 1:name text - 2:name_short text computed { - if len(name) > 5 { - return substr(name, 5) - } - return name - } - 3:greeting text computed { - return "Hello, " + name_short - } - } + worksheet borrower { + 1:name text + 2:name_short text computed { + if len(name) > 5 { + return substr(name, 5) + } + return name + } + 3:greeting text computed { + return "Hello, " + name_short + } + } And the proposed edit - set name "Samantha" + set name "Samantha" The first tentative edit would be - set name "Samantha" - set name_short "Saman" + set name "Samantha" + set name_short "Saman" The second (and final) edit would be - set name "Samantha" - set name_short "Saman" - set greeting "Hello, Saman" + set name "Samantha" + set name_short "Saman" + set greeting "Hello, Saman" ## Applying Edits @@ -429,28 +428,28 @@ We also make it possible for user specified code to intercept the fixed-point ca Example - func (myEditor *) OnEdit(current Worksheet, proposed_edit Edit) (Edit, error) { - if current.GetText("name") == "Joey" { - return proposed_edit.SetText("name", "Joey Pizzapie"), nil - } - return proposed_edit, nil - } + func (myEditor *) OnEdit(current Worksheet, proposed_edit Edit) (Edit, error) { + if current.GetText("name") == "Joey" { + return proposed_edit.SetText("name", "Joey Pizzapie"), nil + } + return proposed_edit, nil + } NOTE: We'd want the `Edit` struct to have sufficient introspection such that we can clearly write cases like the TRID Rule where we need to capture the _first_ time all 6 fields are set on a specific worksheet. Maybe we should also provide a pre/post worksheet with the state before any edit, the state after if the edit were to succeed as is? Need to think through what that code would look like and design the hook with that in mind. One idea would be to be able to verify 'is any of these six fields being modified?', and 'is the resulting edit one where all six fields are complete?', and 'has the trid rule triggered date been set?'. - if current.GetDate("trid_rule_triggered").IsUndefined() { - if proposed_edit.IsSetting("ssn") - proposed_edit.IsSetting("...") || - proposed_edit.IsSetting("...") || - ... { - if !current.GetText("ssn").IsUndefined() && - ... { + if current.GetDate("trid_rule_triggered").IsUndefined() { + if proposed_edit.IsSetting("ssn") + proposed_edit.IsSetting("...") || + proposed_edit.IsSetting("...") || + ... { + if !current.GetText("ssn").IsUndefined() && + ... { - } - } - } + } + } + } Though we'd not even need to verify whether these fields are part of the edit, it's implicit, and more 'underlying structure proof' not too. By 'underlying structure proof' we mean that the code assumes less about the internal structure of the fields, they could be inputs or computed fields, and we wouldn't really care. @@ -458,49 +457,49 @@ Though we'd not even need to verify whether these fields are part of the edit, i Assume we have the worksheet - worksheet cyclic_edits { - 1:right bool - 2:wrong bool computed_by { - return !right - } - } + worksheet cyclic_edits { + 1:right bool + 2:wrong bool computed_by { + return !right + } + } And we propose the edit - set right false + set right false Due to the computed field, this would yield 'actual edit #1' - set right false - set wrong true + set right false + set wrong true Now, assume that we have edit reacting code which flips these fields around - if wrong { - set right true - } else { - set right false - } + if wrong { + set right true + } else { + set right false + } We would then yield the 'actual edit #2' - set right true - set wrong true + set right true + set wrong true And, due to the computed field, this would yield 'actual edit #3' - set right true - set wrong false + set right true + set wrong false Further modified via the event reacting code into 'actual edit #4' - set right false - set wrong false + set right false + set wrong false And again, due to the computed field, this would yield 'actual edit #5' - set right false - set wrong true + set right false + set wrong true Which is in fact the same as 'actual edit #1'. We have created an infinite loop in the fixed-point calculation! @@ -533,7 +532,9 @@ To prevent such 'unstable edits', we detect cycles of edits, and error out, henc _to cover_ ## ACLs + ## Encyption + ## Audit Trail # Introspection, and Reflection @@ -566,17 +567,17 @@ ideas from We have a complex sheet requiring a formal sign off by an operator - worksheet requires_review { ... + worksheet requires_review { ... We track the version at which the operator signed off in `signed_off_version`, and the property of being `signed_off` is computed - worksheet sign_off { - 1:requires_review requires_review - 2:signed_off_version number[0] - 3:signed_off computed { - return requires_review.version == signed_off_version - } - } + worksheet sign_off { + 1:requires_review requires_review + 2:signed_off_version number[0] + 3:signed_off computed { + return requires_review.version == signed_off_version + } + } This ensures that any modification to the sheet `requires_review` nullifies the sign off. diff --git a/bench_test.go b/bench_test.go index ba6a03c..664eefa 100644 --- a/bench_test.go +++ b/bench_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/helloeave/dat/sqlx-runner" + "github.com/homelight/dat/sqlx-runner" _ "github.com/lib/pq" ) diff --git a/computed_by_test.go b/computed_by_test.go index 30943d2..7f0ff60 100644 --- a/computed_by_test.go +++ b/computed_by_test.go @@ -17,7 +17,7 @@ import ( "math" "strings" - "github.com/helloeave/dat/sqlx-runner" + "github.com/homelight/dat/sqlx-runner" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/dbstore.go b/dbstore.go index 8b4030f..3c329fa 100644 --- a/dbstore.go +++ b/dbstore.go @@ -20,9 +20,9 @@ import ( "strings" "time" - "github.com/helloeave/dat/sqlx-runner" + runner "github.com/homelight/dat/sqlx-runner" "github.com/lib/pq" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" ) // Store ... TODO(pascal): write about abstraction. diff --git a/dbstore_test.go b/dbstore_test.go index 2c271d4..deebf07 100644 --- a/dbstore_test.go +++ b/dbstore_test.go @@ -17,7 +17,7 @@ import ( "strings" "time" - "github.com/helloeave/dat/sqlx-runner" + "github.com/homelight/dat/sqlx-runner" "github.com/satori/go.uuid" "github.com/stretchr/testify/require" ) diff --git a/enums_test.go b/enums_test.go index 76e1052..eb013bb 100644 --- a/enums_test.go +++ b/enums_test.go @@ -15,7 +15,7 @@ package worksheets import ( "github.com/stretchr/testify/require" - "github.com/helloeave/dat/sqlx-runner" + "github.com/homelight/dat/sqlx-runner" ) var enumsDefs = ` diff --git a/examples/feature_test.go b/examples/feature_test.go index 946fe66..fe311c1 100644 --- a/examples/feature_test.go +++ b/examples/feature_test.go @@ -15,7 +15,7 @@ package examples import ( "testing" - "github.com/helloeave/worksheets/wstesting" + "github.com/homelight/worksheets/wstesting" ) func TestExampleFeature(t *testing.T) { diff --git a/fuzz/fuzz.go b/fuzz/fuzz.go index 5ea176a..7646214 100644 --- a/fuzz/fuzz.go +++ b/fuzz/fuzz.go @@ -17,7 +17,7 @@ package worksheets import ( "strings" - "github.com/helloeave/worksheets" + "github.com/homelight/worksheets" ) func Fuzz(data []byte) int { diff --git a/go.mod b/go.mod index 54013ac..1648ed5 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,12 @@ -module github.com/helloeave/worksheets +module github.com/homelight/worksheets -go 1.13 +go 1.16 require ( github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cucumber/gherkin-go v5.1.0+incompatible github.com/garyburd/redigo v1.6.0 // indirect - github.com/helloeave/dat v1.1.10-0.20190910155710-6a72ab0a0d6c - github.com/jmoiron/sqlx v1.2.0 // indirect + github.com/homelight/dat v1.1.11 github.com/lib/pq v1.2.0 github.com/mgutz/jo v1.1.0 // indirect github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab // indirect diff --git a/go.sum b/go.sum index 2ec6122..77b19e8 100644 --- a/go.sum +++ b/go.sum @@ -10,24 +10,18 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/garyburd/redigo v1.0.1-0.20160525165706-b8dc90050f24/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/helloeave/dat v1.1.10-0.20190910155710-6a72ab0a0d6c h1:haar8QPds+v425hipqkbytHtRuwIXAcdzlShpmXLlKE= -github.com/helloeave/dat v1.1.10-0.20190910155710-6a72ab0a0d6c/go.mod h1:y37O71q6AJ5PMWQurYMcN4t5KaFden8bJ6HUwCJAKuo= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/homelight/dat v1.1.11 h1:LTPcw0ZjP/LOrIalenIHABqx7WKGGoEMlsyKh8hT52w= +github.com/homelight/dat v1.1.11/go.mod h1:o4uVR6qF4MBdYqjnfn4PJNfCIFNj9/dA08T2oxmKu90= github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= -github.com/jmoiron/sqlx v0.0.0-20160524032753-a7f971fe8ea8/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= -github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= +github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v0.0.0-20160511035104-ee1442bda7bd/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= @@ -35,10 +29,8 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= -github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/jo v0.0.0-20151208164356-0b027231853f/go.mod h1:N638tkDlOBlY8fcrY6JMX/homNKJqXr+nG3MVTYWffk= @@ -64,27 +56,15 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b h1:3S2h5FadpNr0zUUCVZjlKIEYF+KaX/OBplTGo89CYHI= golang.org/x/sys v0.0.0-20190910064555-bbd175535a8b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/appengine v1.6.2 h1:j8RI1yW0SkI+paT6uGwMlrMI/6zwYA6/CFil8rxOzGI= -google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/refs_test.go b/refs_test.go index 872973b..1d0ddf2 100644 --- a/refs_test.go +++ b/refs_test.go @@ -17,7 +17,7 @@ import ( "math" "strings" - "github.com/helloeave/dat/sqlx-runner" + "github.com/homelight/dat/sqlx-runner" "github.com/stretchr/testify/require" ) diff --git a/slices_test.go b/slices_test.go index c915e8d..0c5c652 100644 --- a/slices_test.go +++ b/slices_test.go @@ -16,7 +16,7 @@ import ( "fmt" "math" - "github.com/helloeave/dat/sqlx-runner" + "github.com/homelight/dat/sqlx-runner" "github.com/stretchr/testify/require" ) diff --git a/testutil_test.go b/testutil_test.go index 49b0827..66f2b7d 100644 --- a/testutil_test.go +++ b/testutil_test.go @@ -18,7 +18,7 @@ import ( "strings" "testing" - "github.com/helloeave/dat/sqlx-runner" + "github.com/homelight/dat/sqlx-runner" _ "github.com/lib/pq" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" diff --git a/tools/wstest.go b/tools/wstest.go index 43951fc..7ec8971 100644 --- a/tools/wstest.go +++ b/tools/wstest.go @@ -18,7 +18,7 @@ import ( "os" "path/filepath" - "github.com/helloeave/worksheets/wstesting" + "github.com/homelight/worksheets/wstesting" ) func main() { diff --git a/worksheets.go b/worksheets.go index 53bd0a6..17359cf 100644 --- a/worksheets.go +++ b/worksheets.go @@ -16,7 +16,7 @@ import ( "fmt" "io" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" ) // Definitions groups all definitions for a workbook, which may consists of diff --git a/wstesting/wstesting.go b/wstesting/wstesting.go index ef4f777..7c50f64 100644 --- a/wstesting/wstesting.go +++ b/wstesting/wstesting.go @@ -24,7 +24,7 @@ import ( "github.com/cucumber/gherkin-go" - "github.com/helloeave/worksheets" + "github.com/homelight/worksheets" ) type command interface { diff --git a/wstesting/wstesting_test.go b/wstesting/wstesting_test.go index 4f1801c..3aec84f 100644 --- a/wstesting/wstesting_test.go +++ b/wstesting/wstesting_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "github.com/helloeave/worksheets" + "github.com/homelight/worksheets" ) type Zuite struct { From 399dc652315a7f49e6a299d2ebd9e0ba81c59c3d Mon Sep 17 00:00:00 2001 From: Chris Belsole Date: Tue, 15 Jun 2021 13:40:24 -0400 Subject: [PATCH 2/4] add context aware db methods and updated imports --- bench_test.go | 2 +- clone.go | 2 +- computed_by_test.go | 2 +- dbstore.go | 103 ++++++++++++++------ dbstore_test.go | 226 +++++++++++++++++++++++++++++++++++++++++++- enums_test.go | 3 +- marshaling.go | 4 +- refs_test.go | 2 +- runtime_test.go | 10 +- slices_test.go | 2 +- testutil_test.go | 2 +- values.go | 2 +- 12 files changed, 314 insertions(+), 46 deletions(-) diff --git a/bench_test.go b/bench_test.go index 664eefa..a925bed 100644 --- a/bench_test.go +++ b/bench_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/homelight/dat/sqlx-runner" + runner "github.com/homelight/dat/sqlx-runner" _ "github.com/lib/pq" ) diff --git a/clone.go b/clone.go index 866edb6..ba6d306 100644 --- a/clone.go +++ b/clone.go @@ -15,7 +15,7 @@ package worksheets import ( "fmt" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" ) // Clone duplicates this worksheet, and all worksheets it points to, in order diff --git a/computed_by_test.go b/computed_by_test.go index 7f0ff60..79a7f31 100644 --- a/computed_by_test.go +++ b/computed_by_test.go @@ -17,7 +17,7 @@ import ( "math" "strings" - "github.com/homelight/dat/sqlx-runner" + runner "github.com/homelight/dat/sqlx-runner" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/dbstore.go b/dbstore.go index 3c329fa..795e595 100644 --- a/dbstore.go +++ b/dbstore.go @@ -13,6 +13,7 @@ package worksheets import ( + "context" "fmt" "math" "regexp" @@ -20,31 +21,37 @@ import ( "strings" "time" - runner "github.com/homelight/dat/sqlx-runner" "github.com/lib/pq" uuid "github.com/satori/go.uuid" + + runner "github.com/homelight/dat/sqlx-runner" ) // Store ... TODO(pascal): write about abstraction. type Store interface { // Load loads the worksheet with identifier `id` from the store. Load(id string) (*Worksheet, error) + LoadContext(ctx context.Context, id string) (*Worksheet, error) // SaveOrUpdate saves or updates a worksheet to the store. On success, // returns an edit identifier. SaveOrUpdate(ws *Worksheet) (string, error) + SaveOrUpdateContext(ctx context.Context, ws *Worksheet) (string, error) // Save saves a new worksheet to the store. On success, returns an edit // identifier. Save(ws *Worksheet) (string, error) + SaveContext(ctx context.Context, ws *Worksheet) (string, error) // Update updates an existing worksheet in the store. On success, returns an // edit identifier. Update(ws *Worksheet) (string, error) + UpdateContext(ctx context.Context, ws *Worksheet) (string, error) - // Edit returns a specific edit, the time at which the edit occured, and all + // Edit returns a specific edit, the time at which the edit occurred, and all // worksheets modified as a map of their ids to the resulting version. Edit(editId string) (time.Time, map[string]int, error) + EditContext(ctx context.Context, editId string) (time.Time, map[string]int, error) } type DbStore struct { @@ -141,6 +148,14 @@ var tableToEntities = map[string]interface{}{ } func (s *Session) Edit(editId string) (time.Time, map[string]int, error) { + return s.editCommon(context.Background(), editId) +} + +func (s *Session) EditContext(ctx context.Context, editId string) (time.Time, map[string]int, error) { + return s.editCommon(ctx, editId) +} + +func (s *Session) editCommon(ctx context.Context, editId string) (time.Time, map[string]int, error) { var editRecs []rEdit if err := s.tx. Select("*"). @@ -166,6 +181,14 @@ func (s *Session) Edit(editId string) (time.Time, map[string]int, error) { } func (s *Session) Load(id string) (*Worksheet, error) { + return s.loadCommon(context.Background(), id) +} + +func (s *Session) LoadContext(ctx context.Context, id string) (*Worksheet, error) { + return s.loadCommon(ctx, id) +} + +func (s *Session) loadCommon(ctx context.Context, id string) (*Worksheet, error) { loader := &loader{ s: s, graph: make(map[string]*Worksheet), @@ -184,24 +207,48 @@ func (s *Session) newPersister() *persister { } func (s *Session) SaveOrUpdate(ws *Worksheet) (string, error) { + return s.saveOrUpdateCommon(context.Background(), ws) +} + +func (s *Session) SaveOrUpdateContext(ctx context.Context, ws *Worksheet) (string, error) { + return s.saveOrUpdateCommon(ctx, ws) +} + +func (s *Session) saveOrUpdateCommon(ctx context.Context, ws *Worksheet) (string, error) { p := s.newPersister() - if err := p.saveOrUpdate(ws); err != nil { + if err := p.saveOrUpdate(ctx, ws); err != nil { return "", err } return p.editId, nil } func (s *Session) Save(ws *Worksheet) (string, error) { + return s.saveCommon(context.Background(), ws) +} + +func (s *Session) SaveContext(ctx context.Context, ws *Worksheet) (string, error) { + return s.saveCommon(ctx, ws) +} + +func (s *Session) saveCommon(ctx context.Context, ws *Worksheet) (string, error) { p := s.newPersister() - if err := p.save(ws); err != nil { + if err := p.save(ctx, ws); err != nil { return "", err } return p.editId, nil } func (s *Session) Update(ws *Worksheet) (string, error) { + return s.updateCommon(context.Background(), ws) +} + +func (s *Session) UpdateContext(ctx context.Context, ws *Worksheet) (string, error) { + return s.updateCommon(ctx, ws) +} + +func (s *Session) updateCommon(ctx context.Context, ws *Worksheet) (string, error) { p := s.newPersister() - if err := p.update(ws); err != nil { + if err := p.update(ctx, ws); err != nil { return "", err } return p.editId, nil @@ -287,7 +334,7 @@ func (l *loader) loadWorksheet(id string) (*Worksheet, error) { break } slicesIds := make([]interface{}, len(slicesToHydrate)) - for sliceId, _ := range slicesToHydrate { + for sliceId := range slicesToHydrate { slicesIds = append(slicesIds, sliceId) } var sliceElementsRecs []rSliceElement @@ -450,7 +497,7 @@ type persister struct { graph map[string]bool } -func (p *persister) saveOrUpdate(ws *Worksheet) error { +func (p *persister) saveOrUpdate(ctx context.Context, ws *Worksheet) error { var count int if err := p.s.tx. Select("count(*)"). @@ -461,13 +508,13 @@ func (p *persister) saveOrUpdate(ws *Worksheet) error { } if count == 0 { - return p.save(ws) + return p.save(ctx, ws) } else { - return p.update(ws) + return p.update(ctx, ws) } } -func (p *persister) save(ws *Worksheet) error { +func (p *persister) save(ctx context.Context, ws *Worksheet) error { // already done? if _, ok := p.graph[ws.Id()]; ok { return nil @@ -477,7 +524,7 @@ func (p *persister) save(ws *Worksheet) error { // cascade updates to children and parents for _, value := range ws.data { for _, childWs := range extractChildWs(value) { - if err := p.saveOrUpdate(childWs); err != nil { + if err := p.saveOrUpdate(ctx, childWs); err != nil { return err } } @@ -485,7 +532,7 @@ func (p *persister) save(ws *Worksheet) error { for _, byParentFieldIndex := range ws.parents { for _, byParentId := range byParentFieldIndex { for _, parentWs := range byParentId { - if err := p.saveOrUpdate(parentWs); err != nil { + if err := p.saveOrUpdate(ctx, parentWs); err != nil { return err } } @@ -501,7 +548,7 @@ func (p *persister) save(ws *Worksheet) error { Version: ws.Version(), Name: ws.Name(), }). - Exec(); err != nil { + ExecContext(ctx); err != nil { return err } @@ -515,7 +562,7 @@ func (p *persister) save(ws *Worksheet) error { WorksheetId: ws.Id(), ToVersion: ws.Version(), }). - Exec(); err != nil { + ExecContext(ctx); err != nil { return err } @@ -547,7 +594,7 @@ func (p *persister) save(ws *Worksheet) error { } } } - if _, err := insertValues.Exec(); err != nil { + if _, err := insertValues.ExecContext(ctx); err != nil { return err } @@ -565,7 +612,7 @@ func (p *persister) save(ws *Worksheet) error { }) } } - if _, err := insertSliceElements.Exec(); err != nil { + if _, err := insertSliceElements.ExecContext(ctx); err != nil { return err } } @@ -582,7 +629,7 @@ func (p *persister) save(ws *Worksheet) error { }) } } - if _, err := insertParentElements.Exec(); err != nil { + if _, err := insertParentElements.ExecContext(ctx); err != nil { return err } } @@ -595,7 +642,7 @@ func (p *persister) save(ws *Worksheet) error { return nil } -func (p *persister) update(ws *Worksheet) error { +func (p *persister) update(ctx context.Context, ws *Worksheet) error { // already done? if _, ok := p.graph[ws.Id()]; ok { return nil @@ -605,7 +652,7 @@ func (p *persister) update(ws *Worksheet) error { // cascade updates to children and parents for _, value := range ws.data { for _, childWs := range extractChildWs(value) { - if err := p.saveOrUpdate(childWs); err != nil { + if err := p.saveOrUpdate(ctx, childWs); err != nil { return err } } @@ -613,7 +660,7 @@ func (p *persister) update(ws *Worksheet) error { for _, byParentFieldIndex := range ws.parents { for _, byParentId := range byParentFieldIndex { for _, parentWs := range byParentId { - if err := p.saveOrUpdate(parentWs); err != nil { + if err := p.saveOrUpdate(ctx, parentWs); err != nil { return err } } @@ -730,7 +777,7 @@ func (p *persister) update(ws *Worksheet) error { WorksheetId: ws.Id(), ToVersion: newVersion, }). - Exec() + ExecContext(ctx) if isSpecificUniqueConstraintErr(err, "worksheet_edits_worksheet_id_to_version_key") { return fmt.Errorf("concurrent update detected (%s)", err) } else if err != nil { @@ -744,7 +791,7 @@ func (p *persister) update(ws *Worksheet) error { Where("worksheet_id = $1", ws.Id()). Where("from_version <= $1 and $1 <= to_version", oldVersion). Where(inClause("index", len(valuesToUpdate)), ughconvert(valuesToUpdate)...). - Exec(); err != nil { + ExecContext(ctx); err != nil { return err } @@ -760,7 +807,7 @@ func (p *persister) update(ws *Worksheet) error { Value: dbWriteValue(change.after), }) } - if _, err := insert.Exec(); err != nil { + if _, err := insert.ExecContext(ctx); err != nil { return err } @@ -776,7 +823,7 @@ func (p *persister) update(ws *Worksheet) error { Where("slice_id = $1", sliceId). Where("from_version <= $1 and $1 <= to_version", oldVersion). Where(inClause("rank", len(ranks)), ranks...). - Exec(); err != nil { + ExecContext(ctx); err != nil { return err } } @@ -793,7 +840,7 @@ func (p *persister) update(ws *Worksheet) error { Value: dbWriteValue(add.value), }) } - if _, err := insert.Exec(); err != nil { + if _, err := insert.ExecContext(ctx); err != nil { return err } } @@ -804,7 +851,7 @@ func (p *persister) update(ws *Worksheet) error { Where("parent_id = $1", ws.Id()). Where("parent_field_index = $1", index). Where(inClause("child_id", len(childrenWsId)), childrenWsId...). - Exec(); err != nil { + ExecContext(ctx); err != nil { return err } } @@ -819,7 +866,7 @@ func (p *persister) update(ws *Worksheet) error { }) } } - if _, err := insertParentElements.Exec(); err != nil { + if _, err := insertParentElements.ExecContext(ctx); err != nil { return err } } @@ -829,7 +876,7 @@ func (p *persister) update(ws *Worksheet) error { Update("worksheets"). Set("version", newVersion). Where("id = $1 and version = $2", ws.Id(), oldVersion). - Exec(); err != nil { + ExecContext(ctx); err != nil { return err } else if result.RowsAffected != 1 { return fmt.Errorf("concurrent update detected") diff --git a/dbstore_test.go b/dbstore_test.go index deebf07..5e76a33 100644 --- a/dbstore_test.go +++ b/dbstore_test.go @@ -13,12 +13,13 @@ package worksheets import ( + "context" "math" "strings" "time" - "github.com/homelight/dat/sqlx-runner" - "github.com/satori/go.uuid" + runner "github.com/homelight/dat/sqlx-runner" + uuid "github.com/satori/go.uuid" "github.com/stretchr/testify/require" ) @@ -45,6 +46,29 @@ func (s *Zuite) TestDbExample() { require.Equal(s.T(), `"Alice"`, wsFromStore.MustGet("name").String()) } +func (s *Zuite) TestDbContextExample() { + ws := s.store.defs.MustNewWorksheet("simple") + ws.MustSet("name", NewText("Alice")) + + s.MustRunTransaction(func(tx *runner.Tx) error { + session := s.store.Open(tx) + _, err := session.SaveContext(context.Background(), ws) + return err + }) + + var wsFromStore *Worksheet + s.MustRunTransaction(func(tx *runner.Tx) error { + session := s.store.Open(tx) + var err error + wsFromStore, err = session.LoadContext(context.Background(), ws.Id()) + return err + }) + + require.Len(s.T(), wsFromStore.MustGet("id").String(), 38) + require.Equal(s.T(), `1`, wsFromStore.MustGet("version").String()) + require.Equal(s.T(), `"Alice"`, wsFromStore.MustGet("name").String()) +} + func (s *Zuite) TestSave() { ws, err := s.store.defs.NewWorksheet("simple") require.NoError(s.T(), err) @@ -126,6 +150,87 @@ func (s *Zuite) TestSave() { }, editTouchedWs) } +func (s *Zuite) TestSaveContext() { + ws, err := s.store.defs.NewWorksheet("simple") + require.NoError(s.T(), err) + + err = ws.Set("name", NewText("Alice")) + require.NoError(s.T(), err) + + var editId string + s.MustRunTransaction(func(tx *runner.Tx) error { + session := s.store.Open(tx) + session.clock = &fakeClock{1234} + + var err error + editId, err = session.SaveContext(context.Background(), ws) + return err + }) + + snap := s.snapshotDbState() + + require.Equal(s.T(), []rWorksheet{ + { + Id: ws.Id(), + Version: 1, + Name: "simple", + }, + }, snap.wsRecs) + + require.Equal(s.T(), []rEdit{ + { + EditId: editId, + CreatedAt: 1234, + WorksheetId: ws.Id(), + ToVersion: 1, + }, + }, snap.editRecs) + + require.Equal(s.T(), []rValueForTesting{ + { + WorksheetId: ws.Id(), + Index: indexId, + FromVersion: 1, + ToVersion: math.MaxInt32, + Value: ws.Id(), + }, + { + WorksheetId: ws.Id(), + Index: indexVersion, + FromVersion: 1, + ToVersion: math.MaxInt32, + Value: `1`, + }, + { + WorksheetId: ws.Id(), + Index: 83, + FromVersion: 1, + ToVersion: math.MaxInt32, + Value: `Alice`, + }, + }, snap.valuesRecs) + + // Upon Save, orig needs to be set to data. + require.Empty(s.T(), ws.diff()) + + // Edit. + var ( + editCreatedAt time.Time + editTouchedWs map[string]int + ) + s.MustRunTransaction(func(tx *runner.Tx) error { + session := s.store.Open(tx) + + var err error + editCreatedAt, editTouchedWs, err = session.EditContext(context.Background(), editId) + return err + }) + require.Equal(s.T(), int64(1234), editCreatedAt.UnixNano()) + require.Equal(s.T(), map[string]int{ + ws.Id(): 1, + }, editTouchedWs) +} + func (s *Zuite) TestUpdate() { ws, err := s.store.defs.NewWorksheet("simple") require.NoError(s.T(), err) @@ -243,6 +348,123 @@ func (s *Zuite) TestUpdate() { }, updateTouchedWs) } +func (s *Zuite) TestUpdateContext() { + ws, err := s.store.defs.NewWorksheet("simple") + require.NoError(s.T(), err) + + err = ws.Set("name", NewText("Alice")) + require.NoError(s.T(), err) + + var saveId string + s.MustRunTransaction(func(tx *runner.Tx) error { + session := s.store.Open(tx) + session.clock = &fakeClock{1000} + + var err error + saveId, err = session.SaveContext(context.Background(), ws) + return err + }) + + err = ws.Set("name", NewText("Bob")) + require.NoError(s.T(), err) + + var updateId string + s.MustRunTransaction(func(tx *runner.Tx) error { + session := s.store.Open(tx) + session.clock = &fakeClock{2000} + + var err error + updateId, err = session.UpdateContext(context.Background(), ws) + return err + }) + + snap := s.snapshotDbState() + + require.Equal(s.T(), []rWorksheet{ + { + Id: ws.Id(), + Version: 2, + Name: "simple", + }, + }, snap.wsRecs) + + require.Equal(s.T(), []rEdit{ + { + EditId: saveId, + CreatedAt: 1000, + WorksheetId: ws.Id(), + ToVersion: 1, + }, + { + EditId: updateId, + CreatedAt: 2000, + WorksheetId: ws.Id(), + ToVersion: 2, + }, + }, snap.editRecs) + + require.Equal(s.T(), []rValueForTesting{ + { + WorksheetId: ws.Id(), + Index: indexId, + FromVersion: 1, + ToVersion: math.MaxInt32, + Value: ws.Id(), + }, + { + WorksheetId: ws.Id(), + Index: indexVersion, + FromVersion: 1, + ToVersion: 1, + Value: `1`, + }, + { + WorksheetId: ws.Id(), + Index: indexVersion, + FromVersion: 2, + ToVersion: math.MaxInt32, + Value: `2`, + }, + { + WorksheetId: ws.Id(), + Index: 83, + FromVersion: 1, + ToVersion: 1, + Value: `Alice`, + }, + { + WorksheetId: ws.Id(), + Index: 83, + FromVersion: 2, + ToVersion: math.MaxInt32, + Value: `Bob`, + }, + }, snap.valuesRecs) + + // Upon update, version must increase + require.Equal(s.T(), 2, ws.Version()) + + // Upon Update, orig needs to be set to data. + require.Empty(s.T(), ws.diff()) + + // Edit. + var ( + updateCreatedAt time.Time + updateTouchedWs map[string]int + ) + s.MustRunTransaction(func(tx *runner.Tx) error { + session := s.store.Open(tx) + + var err error + updateCreatedAt, updateTouchedWs, err = session.EditContext(context.Background(), updateId) + return err + }) + require.Equal(s.T(), int64(2000), updateCreatedAt.UnixNano()) + require.Equal(s.T(), map[string]int{ + ws.Id(): 2, + }, updateTouchedWs) +} + func (s *Zuite) TestUpdateUndefinedField() { ws, err := s.store.defs.NewWorksheet("simple") require.NoError(s.T(), err) diff --git a/enums_test.go b/enums_test.go index eb013bb..1d6b072 100644 --- a/enums_test.go +++ b/enums_test.go @@ -13,9 +13,8 @@ package worksheets import ( + runner "github.com/homelight/dat/sqlx-runner" "github.com/stretchr/testify/require" - - "github.com/homelight/dat/sqlx-runner" ) var enumsDefs = ` diff --git a/marshaling.go b/marshaling.go index 4a5ca91..466359c 100644 --- a/marshaling.go +++ b/marshaling.go @@ -205,8 +205,8 @@ func (ss *StructScanner) StructScan(ws *Worksheet, dest interface{}) error { } ctx := &structScanCtx{ - converters: ss.converterRegistry, - dests: make(map[string]*wsDestination), + converters: ss.converterRegistry, + dests: make(map[string]*wsDestination), allowUndefinedToNonPointer: ss.AllowUndefinedToNonPointer, } diff --git a/refs_test.go b/refs_test.go index 1d0ddf2..a3cf59a 100644 --- a/refs_test.go +++ b/refs_test.go @@ -17,7 +17,7 @@ import ( "math" "strings" - "github.com/homelight/dat/sqlx-runner" + runner "github.com/homelight/dat/sqlx-runner" "github.com/stretchr/testify/require" ) diff --git a/runtime_test.go b/runtime_test.go index ae94c19..af95585 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -159,11 +159,11 @@ func (s *Zuite) TestRuntime_parseAndEvalExpr() { `sumiftrue(slice_n0, undefined)`: `undefined`, // if - `if(true, 1, 3)`: `1`, - `if(false, 1, 3)`: `3`, - `if(undefined, 1, 3)`: `undefined`, - `if(true, 1, 3 / 0 round down 0)`: `1`, - `if(false, 1 / 0 round down 0, 3)`: `3`, + `if(true, 1, 3)`: `1`, + `if(false, 1, 3)`: `3`, + `if(undefined, 1, 3)`: `undefined`, + `if(true, 1, 3 / 0 round down 0)`: `1`, + `if(false, 1 / 0 round down 0, 3)`: `3`, `if(0 < -1, "unused", if("a" == "a", "good", 1 / 0 round down 0))`: `"good"`, `if(true, 1)`: `1`, `if(false, 1)`: `undefined`, diff --git a/slices_test.go b/slices_test.go index 0c5c652..3ffedda 100644 --- a/slices_test.go +++ b/slices_test.go @@ -16,7 +16,7 @@ import ( "fmt" "math" - "github.com/homelight/dat/sqlx-runner" + runner "github.com/homelight/dat/sqlx-runner" "github.com/stretchr/testify/require" ) diff --git a/testutil_test.go b/testutil_test.go index 66f2b7d..47f8b73 100644 --- a/testutil_test.go +++ b/testutil_test.go @@ -18,7 +18,7 @@ import ( "strings" "testing" - "github.com/homelight/dat/sqlx-runner" + runner "github.com/homelight/dat/sqlx-runner" _ "github.com/lib/pq" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" diff --git a/values.go b/values.go index 6e33630..56a44a4 100644 --- a/values.go +++ b/values.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - "github.com/satori/go.uuid" + uuid "github.com/satori/go.uuid" ) var ( From 90b3d4fcac3917990e683cd4bd8d97666832faf8 Mon Sep 17 00:00:00 2001 From: Chris Belsole Date: Tue, 15 Jun 2021 14:14:10 -0400 Subject: [PATCH 3/4] added go 1.14, 1.15, 1.16 to circle --- .circleci/config.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index b271dff..e506d5d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,6 +8,7 @@ shared: &run_steps timeout: 5 # postgres + - run: sudo apt-get update - run: sudo apt install postgresql-client - run: psql ws_test ws_user -h localhost -p 5432 -f /go/src/github.com/homelight/worksheets/schema.sql @@ -30,6 +31,42 @@ jobs: working_directory: /go/src/github.com/homelight/worksheets <<: *run_steps + buildGo1.14: + docker: + - image: circleci/golang:1.14 + - image: circleci/postgres:9.6-alpine + environment: + POSTGRES_USER: ws_user + POSTGRES_DB: ws_test + POSTGRES_PASSWORD: "" + + working_directory: /go/src/github.com/homelight/worksheets + <<: *run_steps + + buildGo1.15: + docker: + - image: circleci/golang:1.15 + - image: circleci/postgres:9.6-alpine + environment: + POSTGRES_USER: ws_user + POSTGRES_DB: ws_test + POSTGRES_PASSWORD: "" + + working_directory: /go/src/github.com/homelight/worksheets + <<: *run_steps + + buildGo1.16: + docker: + - image: circleci/golang:1.16 + - image: circleci/postgres:9.6-alpine + environment: + POSTGRES_USER: ws_user + POSTGRES_DB: ws_test + POSTGRES_PASSWORD: "" + + working_directory: /go/src/github.com/homelight/worksheets + <<: *run_steps + workflows: version: 2 build_on_git_push: From 4749d3102098ee6b4cb566a081e5cb093989b7bc Mon Sep 17 00:00:00 2001 From: Chris Belsole Date: Tue, 15 Jun 2021 14:16:33 -0400 Subject: [PATCH 4/4] actually add the test runs --- .circleci/config.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index e506d5d..64b5516 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -72,9 +72,15 @@ workflows: build_on_git_push: jobs: - buildGo1.13 + - buildGo1.14 + - buildGo1.15 + - buildGo1.16 build_nightly: jobs: - buildGo1.13 + - buildGo1.14 + - buildGo1.15 + - buildGo1.16 triggers: - schedule: cron: "0 0 * * *"