Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: service/datastore/dumper/dumper.go

Issue 2037433002: Add datastore dumper tool. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gae@allow_unsigned
Patch Set: fix copyright Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | service/datastore/dumper/dumper_example_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 // Package dumper implements a very VERY dumb datastore-dumping debugging aid.
6 // You shouldn't plan on having this work with the production datastore with any
7 // appreciable amount of data.
8 //
9 // This will take an arbitrary query (or even a query for every entity in the
10 // entire datastore), and print every entity to some output stream.
11 package dumper
12
13 import (
14 "fmt"
15 "io"
16 "os"
17 "sort"
18 "strings"
19
20 "github.com/luci/gae/service/datastore"
21 "golang.org/x/net/context"
22 )
23
24 // Key is a key into a PropFilterMap
25 type Key struct {
26 Kind string
27 PropName string
28 }
29
30 // A PropFilterMap maps from Kind+PropertyName tuples to a formatting function. You
31 // may use this to specially format particular properties.
32 type PropFilterMap map[Key]func(datastore.Property) string
33
34 // KindFilterMap maps from a Kind to a formatting function. You may use this to
35 // specially format particular Kinds. If this function returns an empty string,
36 // the default formatting function (including any PropFilterMap entries) will be
37 // used.
38 type KindFilterMap map[string]func(*datastore.Key, datastore.PropertyMap) string
39
40 // Config is a configured dumper.
41 type Config struct {
42 // OutStream is the output stream to use. If this is nil, os.Stdout will be
43 // used.
44 OutStream io.Writer
45
46 // WithSpecial, if true, includes entities which have kinds that begin a nd
47 // end with "__". By default, these entities are skipped.
48 WithSpecial bool
49
50 // PropFilters is an optional property filter map for controlling the
51 // rendering of certain Kind/Property values.
52 PropFilters PropFilterMap
53
54 // KindFilters is an optional kind filter for controlling the rendering of
55 // certain Kind values.
56 KindFilters KindFilterMap
57 }
58
59 // Query will dump everything matching the provided query.
60 //
61 // If the provided query is nil, a kindless query without any filters will be
62 // used.
63 func (cfg Config) Query(c context.Context, q *datastore.Query) (n int, err error ) {
64 ds := datastore.Get(c)
65
66 if q == nil {
67 q = datastore.NewQuery("")
68 }
69
70 out := cfg.OutStream
71 if out == nil {
72 out = os.Stdout
73 }
74
75 fmtVal := func(kind, name string, prop datastore.Property) string {
76 if fn := cfg.PropFilters[Key{kind, name}]; fn != nil {
77 return fn(prop)
78 }
79 return prop.String()
80 }
81
82 prnt := func(format string, args ...interface{}) (err error) {
83 var amt int
84 amt, err = fmt.Fprintf(out, format, args...)
85 n += amt
86 return
87 }
88
89 prop := func(kind, name string, vals []datastore.Property) (err error) {
90 if len(vals) <= 1 {
91 return prnt(" %q: [%s]\n", name, fmtVal(kind, name, val s[0]))
92 }
93 if err = prnt(" %q: [\n %s", name, fmtVal(kind, name, vals[0 ])); err != nil {
94 return
95 }
96 for _, v := range vals[1:] {
97 if err = prnt(",\n %s", fmtVal(kind, name, v)); err ! = nil {
98 return
99 }
100 }
101 return prnt("\n ]\n")
102 }
103
104 err = ds.Run(q, func(pm datastore.PropertyMap) error {
105 key := datastore.GetMetaDefault(pm, "key", nil).(*datastore.Key)
106 if !cfg.WithSpecial && strings.HasPrefix(key.Kind(), "__") && st rings.HasSuffix(key.Kind(), "__") {
107 return nil
108 }
109 if err := prnt("\n%s:\n", key); err != nil {
110 return err
111 }
112 pm, _ = pm.Save(false)
113
114 // See if we have a KindFilter for this
115 if flt, ok := cfg.KindFilters[key.Kind()]; ok {
116 if kindOut := flt(key, pm); kindOut != "" {
117 for _, l := range strings.Split(kindOut, "\n") {
118 if err := prnt(" %s\n", l); err != nil {
119 return err
120 }
121 }
122 return nil
123 }
124 }
125
126 keys := make([]string, 0, len(pm))
127 for k := range pm {
128 keys = append(keys, k)
129 }
130 sort.Strings(keys)
131 for _, k := range keys {
132 if err := prop(key.Kind(), k, pm[k]); err != nil {
133 return err
134 }
135 }
136 return nil
137 })
138 return
139 }
140
141 // Query dumps the provided query to stdout without special entities and with
142 // default rendering.
143 func Query(c context.Context, q *datastore.Query) {
144 Config{}.Query(c, q)
145 }
146
147 // All dumps all entities to stdout without special entities and with default
148 // rendering.
149 func All(c context.Context) {
150 Config{}.Query(c, nil)
151 }
OLDNEW
« no previous file with comments | « no previous file | service/datastore/dumper/dumper_example_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698