forked from open-policy-agent/opa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstorage.go
126 lines (104 loc) · 3.49 KB
/
storage.go
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
// Copyright 2016 The OPA Authors. All rights reserved.
// Use of this source code is governed by an Apache2
// license that can be found in the LICENSE file.
package storage
import (
"context"
)
// NewTransactionOrDie is a helper function to create a new transaction. If the
// storage layer cannot create a new transaction, this function will panic. This
// function should only be used for tests.
func NewTransactionOrDie(ctx context.Context, store Store, params ...TransactionParams) Transaction {
txn, err := store.NewTransaction(ctx, params...)
if err != nil {
panic(err)
}
return txn
}
// ReadOne is a convenience function to read a single value from the provided Store. It
// will create a new Transaction to perform the read with, and clean up after itself
// should an error occur.
func ReadOne(ctx context.Context, store Store, path Path) (interface{}, error) {
txn, err := store.NewTransaction(ctx)
if err != nil {
return nil, err
}
defer store.Abort(ctx, txn)
return store.Read(ctx, txn, path)
}
// WriteOne is a convenience function to write a single value to the provided Store. It
// will create a new Transaction to perform the write with, and clean up after itself
// should an error occur.
func WriteOne(ctx context.Context, store Store, op PatchOp, path Path, value interface{}) error {
txn, err := store.NewTransaction(ctx, WriteParams)
if err != nil {
return err
}
if err := store.Write(ctx, txn, op, path, value); err != nil {
store.Abort(ctx, txn)
return err
}
return store.Commit(ctx, txn)
}
// MakeDir inserts an empty object at path. If the parent path does not exist,
// MakeDir will create it recursively.
func MakeDir(ctx context.Context, store Store, txn Transaction, path Path) (err error) {
if len(path) == 0 {
return nil
}
node, err := store.Read(ctx, txn, path)
if err != nil {
if !IsNotFound(err) {
return err
}
if err := MakeDir(ctx, store, txn, path[:len(path)-1]); err != nil {
return err
} else if err := store.Write(ctx, txn, AddOp, path, map[string]interface{}{}); err != nil {
return err
}
return nil
}
if _, ok := node.(map[string]interface{}); ok {
return nil
}
return writeConflictError(path)
}
// Txn is a convenience function that executes f inside a new transaction
// opened on the store. If the function returns an error, the transaction is
// aborted and the error is returned. Otherwise, the transaction is committed
// and the result of the commit is returned.
func Txn(ctx context.Context, store Store, params TransactionParams, f func(Transaction) error) error {
txn, err := store.NewTransaction(ctx, params)
if err != nil {
return err
}
if err := f(txn); err != nil {
store.Abort(ctx, txn)
return err
}
return store.Commit(ctx, txn)
}
// NonEmpty returns a function that tests if a path is non-empty. A
// path is non-empty if a Read on the path returns a value or a Read
// on any of the path prefixes returns a non-object value.
func NonEmpty(ctx context.Context, store Store, txn Transaction) func([]string) (bool, error) {
return func(path []string) (bool, error) {
if _, err := store.Read(ctx, txn, Path(path)); err == nil {
return true, nil
} else if !IsNotFound(err) {
return false, err
}
for i := len(path) - 1; i > 0; i-- {
val, err := store.Read(ctx, txn, Path(path[:i]))
if err != nil && !IsNotFound(err) {
return false, err
} else if err == nil {
if _, ok := val.(map[string]interface{}); ok {
return false, nil
}
return true, nil
}
}
return false, nil
}
}