gromer

#golang#htmx#ssr

git clone https://git.pyrossh.dev/gromer

gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.


95c57d6 — Peter John 2022-03-20T18:30:52+05:30
add Collection

Generated files not shown: go.sum

Files changed (4) hide show
  1. aa/main.go +0 -131
  2. cmd/gromer/main.go +2 -6
  3. collection.go +77 -0
  4. go.mod +4 -5
aa/main.go DELETED
@@ -1,131 +0,0 @@
1
- package main
2
-
3
- import (
4
- "bytes"
5
- "strings"
6
-
7
- "golang.org/x/net/html"
8
- )
9
-
10
- type M map[string]interface{}
11
-
12
- type ReqContext struct {
13
- JS *bytes.Buffer
14
- CSS *bytes.Buffer
15
- }
16
-
17
- type Component func(ReqContext) string
18
-
19
- var components = map[string]Component{}
20
-
21
- func RegisterComponent(k string, v Component) {
22
- components[k] = v
23
- }
24
-
25
- func Html2(ctx ReqContext, input string, data map[string]interface{}) string {
26
- return input
27
- }
28
-
29
- func ParseHTML(ctx ReqContext, input string, data map[string]interface{}) *html.Node {
30
- doc, err := html.Parse(bytes.NewBufferString(input))
31
- if err != nil {
32
- panic(err)
33
- }
34
- return doc
35
- }
36
-
37
- func init() {
38
- RegisterComponent("Layout", func(c ReqContext) string {
39
- return Html2(c, `
40
- <html>
41
- <body>
42
- <div>
43
- <slot></slot>
44
- </div>
45
- </body>
46
- </html>
47
- `, M{})
48
- })
49
- }
50
-
51
- func properTitle(input string) string {
52
- words := strings.Split(input, " ")
53
- smallwords := " a an on the to "
54
-
55
- for index, word := range words {
56
- if strings.Contains(smallwords, " "+word+" ") && word != string(word[0]) {
57
- words[index] = word
58
- } else {
59
- words[index] = strings.Title(word)
60
- }
61
- }
62
- return strings.Join(words, " ")
63
- }
64
-
65
- func main() {
66
- // vctx := velvet.NewContext()
67
- // for k, v := range data {
68
- // vctx.Set(k, v)
69
- // }
70
- // s, err := velvet.Render(textOutput, vctx)
71
- // if err != nil {
72
- // panic(err)
73
- // }
74
- ctx := ReqContext{JS: bytes.NewBuffer(nil), CSS: bytes.NewBuffer(nil)}
75
- txt := `
76
- <Layout>
77
- <p>
78
- Hello world
79
- </p>
80
- </Layout>
81
- `
82
- docs := ParseHTML(ctx, txt, M{})
83
- textOutput := ""
84
- var f func(txt string, n *html.Node)
85
- f = func(txt string, n *html.Node) {
86
- removeExtraStuff := func(tag string) bool {
87
- return !strings.Contains(txt, "<"+tag+">") && n.Type == html.ElementNode && n.Data == tag
88
- }
89
- constainsHtml := removeExtraStuff("html") || removeExtraStuff("body") || removeExtraStuff("head")
90
- if !constainsHtml && n.Type == html.ElementNode {
91
- textOutput += "<" + n.Data + ">"
92
- }
93
- if n.Type == html.TextNode {
94
- textOutput += n.Data
95
- }
96
- if n.Type == html.ElementNode && n.Data == "slot" {
97
- }
98
- if c, ok := components[properTitle(n.Data)]; ok {
99
- ctext := c(ctx)
100
- newNodes := ParseHTML(ctx, ctext, M{})
101
- f(ctext, newNodes)
102
- }
103
- for c := n.FirstChild; c != nil; c = c.NextSibling {
104
- f(txt, c)
105
- }
106
- if !constainsHtml && n.Type == html.ElementNode {
107
- textOutput += "</" + n.Data + ">"
108
- }
109
- }
110
- f(txt, docs)
111
- println("textOutput", textOutput)
112
- }
113
-
114
- // func Index2(c *context.ReqContext) (interface{}, int, error) {
115
- // data := M{
116
- // "userID": c.UserID,
117
- // "message": "I ❤️ Alpine",
118
- // }
119
- // return Html(`
120
- // <page x-data="pageData">
121
- // <div class="flex flex-col items-center justify-center">
122
- // <header></header>
123
- // <h1>Hello <template x-text="userID"></template></h1>
124
- // <h2>Hello this is a h1</h1>
125
- // <h2>Hello this is a h2</h1>
126
- // <h3 x-text="message"></h3>
127
- // <counter start={4}></counter>
128
- // </div>
129
- // </page>
130
- // `, data), 200, nil
131
- // }
cmd/gromer/main.go CHANGED
@@ -276,15 +276,11 @@ func handle(router *mux.Router, method, route string, h interface{}) {
276
276
  defer func() {
277
277
  gromer.LogReq(status, r)
278
278
  }()
279
- ctx, err := context.WithContext(c.WithValue(
279
+ ctx := c.WithValue(
280
280
  c.WithValue(
281
281
  c.WithValue(r.Context(), "assetsFS", assetsFS),
282
282
  "url", r.URL),
283
- "header", r.Header))
283
+ "header", r.Header)
284
- if err != nil {
285
- gromer.RespondError(w, 500, err)
286
- return
287
- }
288
284
  status, err = gromer.PerformRequest(route, h, ctx, w, r)
289
285
  if err != nil {
290
286
  log.Error().Stack().Err(err).Msg("")
collection.go ADDED
@@ -0,0 +1,77 @@
1
+ package gromer
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "io"
7
+ "reflect"
8
+
9
+ "github.com/rs/zerolog/log"
10
+ "gocloud.dev/docstore"
11
+ _ "gocloud.dev/docstore/gcpfirestore"
12
+ )
13
+
14
+ type Collection struct {
15
+ *docstore.Collection
16
+ Type reflect.Type
17
+ }
18
+
19
+ func (c Collection) Query() *Query {
20
+ return &Query{c.Collection.Query(), c, c.Type}
21
+ }
22
+
23
+ type Query struct {
24
+ *docstore.Query
25
+ Parent Collection
26
+ Type reflect.Type
27
+ }
28
+
29
+ func (q *Query) Where(fp docstore.FieldPath, op string, value interface{}) *Query {
30
+ return &Query{q.Query.Where(fp, op, value), q.Parent, q.Type}
31
+ }
32
+
33
+ func (q *Query) Limit(n int) *Query {
34
+ return &Query{q.Query.Limit(n), q.Parent, q.Type}
35
+ }
36
+
37
+ func (q *Query) OrderBy(field, direction string) *Query {
38
+ return &Query{q.Query.OrderBy(field, direction), q.Parent, q.Type}
39
+ }
40
+
41
+ func (q *Query) One(ctx context.Context) (interface{}, int, error) {
42
+ results, err := q.All(ctx)
43
+ if err != nil {
44
+ return nil, 500, err
45
+ }
46
+ arr := reflect.ValueOf(results)
47
+ if arr.Len() == 0 {
48
+ return nil, 404, fmt.Errorf("%s not found", q.Type.Name())
49
+ }
50
+ return arr.Index(0).Interface(), 200, nil
51
+ }
52
+
53
+ func (q *Query) All(ctx context.Context) (interface{}, error) {
54
+ iter := q.Get(ctx)
55
+ defer iter.Stop()
56
+ results := reflect.New(reflect.SliceOf(reflect.PtrTo(q.Type))).Elem()
57
+ for {
58
+ v := reflect.New(q.Type)
59
+ err := iter.Next(ctx, v.Interface())
60
+ if err == io.EOF {
61
+ break
62
+ } else if err != nil {
63
+ return nil, err
64
+ } else {
65
+ results.Set(reflect.Append(results, v))
66
+ }
67
+ }
68
+ return results.Interface(), nil
69
+ }
70
+
71
+ func GetCollection(project, env, name string, t interface{}) *Collection {
72
+ coll, err := docstore.OpenCollection(context.Background(), fmt.Sprintf("firestore://projects/%s/databases/(default)/documents/%s?name_field=ID", project, env+"-"+name))
73
+ if err != nil {
74
+ log.Fatal().Stack().Err(err).Msgf("failed to GetCollection %s", name)
75
+ }
76
+ return &Collection{coll, reflect.TypeOf(t)}
77
+ }
go.mod CHANGED
@@ -4,7 +4,7 @@ go 1.16
4
4
 
5
5
  require (
6
6
  github.com/apex/gateway/v2 v2.0.0
7
- github.com/aymerick/raymond v2.0.2+incompatible
7
+ github.com/aymerick/raymond v2.0.2+incompatible // indirect
8
8
  github.com/bradleyjkemp/cupaloy v2.3.0+incompatible
9
9
  github.com/franela/goblin v0.0.0-20211003143422-0a4f594942bf
10
10
  github.com/go-playground/validator/v10 v10.9.0
@@ -13,13 +13,12 @@ require (
13
13
  github.com/gorilla/mux v1.8.0
14
14
  github.com/imdario/mergo v0.3.12
15
15
  github.com/lib/pq v1.10.4
16
- github.com/markbates/inflect v1.0.4
16
+ github.com/markbates/inflect v1.0.4 // indirect
17
17
  github.com/microcosm-cc/bluemonday v1.0.16 // indirect
18
- github.com/pkg/errors v0.9.1
19
18
  github.com/rs/zerolog v1.26.1
20
19
  github.com/segmentio/go-camelcase v0.0.0-20160726192923-7085f1e3c734
21
20
  github.com/sergi/go-diff v1.2.0 // indirect
22
- github.com/shurcooL/github_flavored_markdown v0.0.0-20210228213109-c3a9aa474629
21
+ github.com/shurcooL/github_flavored_markdown v0.0.0-20210228213109-c3a9aa474629 // indirect
23
22
  github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 // indirect
24
23
  github.com/shurcooL/go-goon v0.0.0-20210110234559-7585751d9a17 // indirect
25
24
  github.com/shurcooL/highlight_diff v0.0.0-20181222201841-111da2e7d480 // indirect
@@ -30,5 +29,5 @@ require (
30
29
  github.com/stretchr/testify v1.7.0
31
30
  gocloud.dev v0.24.0
32
31
  golang.org/x/mod v0.5.1
33
- golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
32
+ golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
34
33
  )