Daniel Thomas dc5f6d1703 feat: let entities defer write-once fields to $setOnInsert
Upsert and UpsertMany stamped createdAt whenever the entity carried a zero
value. That guard silently inverts its meaning depending on whether the caller
read the document first: a read-modify-write caller holds the stored value and
keeps it, while a blind writer - an import feed, say - has nothing to supply and
so overwrites the stored createdAt on every re-import.

Entities can now implement EntityWithInsertOnlyFields to declare which fields
must only ever be written on insert. Those elements are routed through
$setOnInsert, so an upsert resolving to an update leaves them at their stored
value while one that inserts writes them once.

keel learns no field names in the process - the entity supplies them. That
preserves the existing property that keel only names a field in order to query
by it (id, version), never in order to write it.

UpsertUpdate and ApplyTimestamps are exported so callers driving their own bulk
writes, such as an import feed filtering on a staleness predicate, can apply the
same policy rather than restating it per call site.

Entities that do not implement the interface are written exactly as before, so
existing consumers are unaffected; TestUpsertLegacyEntityBehaviourUnchanged pins
that behaviour deliberately.

Adds the first tests to persistence/mongo, backed by a mongo testcontainer.
2026-09-15 13:42:36 +02:00
2026-07-31 19:04:08 +02:00
2025-11-07 14:15:03 +01:00
2026-07-31 19:04:08 +02:00
2026-08-06 17:16:54 +02:00
2023-09-08 12:17:23 +02:00
2026-08-06 17:16:54 +02:00
2026-08-06 17:51:05 +02:00
2026-07-29 17:35:44 +02:00
2026-07-29 17:35:44 +02:00
2025-10-02 13:52:18 +02:00
2026-08-01 22:01:43 +02:00
2025-12-15 16:38:43 +01:00
2021-11-19 14:16:09 +01:00
2026-04-22 00:04:52 +02:00
2026-02-17 13:47:18 +01:00
2026-06-17 15:04:11 +02:00
2026-03-16 16:48:45 +01:00
2026-02-24 13:59:01 +01:00
2026-08-06 17:16:54 +02:00
2026-03-03 15:41:43 +01:00
2026-06-17 14:51:52 +02:00
2024-03-15 11:01:25 +01:00
2026-06-17 14:51:52 +02:00
2026-08-06 17:16:54 +02:00
2026-08-06 17:16:54 +02:00
2023-09-08 22:24:31 +02:00
2026-06-17 14:51:52 +02:00
2026-06-22 11:57:29 +02:00
2026-07-31 12:23:37 +02:00
2021-05-18 08:34:47 +02:00
2024-11-22 09:15:21 +01:00
2026-08-06 17:16:54 +02:00
2026-07-31 19:04:08 +02:00
2026-08-05 10:05:34 +02:00
2026-06-19 09:02:45 +02:00
2026-07-31 19:04:08 +02:00
2026-05-29 16:02:02 +02:00
2026-06-19 08:50:40 +02:00
2026-06-19 08:50:40 +02:00
2026-06-19 08:50:40 +02:00

GoDoc Coverage GitHub Stars

keel

keel

Opinionated way to run services on Kubernetes

Stack

  • Zap
  • Nats
  • Viper
  • GoTSRPC
  • Temporal
  • OpenTelemetry

Examples

See the examples folder for usages

package main

import (
  "net/http"

  "github.com/foomo/keel"
  "github.com/foomo/keel/service"
)

func main() {
  svr := keel.NewServer(
    keel.WithHTTPZapService(true),
    keel.WithHTTPViperService(true),
    keel.WithHTTPPrometheusService(true),
  )

  l := svr.Logger()

  svs := newService()

  svr.AddService(
    service.NewHTTP(l, "demo", "localhost:8080", svs),
  )

  svr.Run()
}

func newService() *http.ServeMux {
  s := http.NewServeMux()
  s.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    _, _ = w.Write([]byte("OK"))
  })
  return s
}

How to Contribute

Contributions are welcome! Please read the contributing guide.

Contributors

License

Distributed under MIT License, please read the license file for more details.

Made with ♥ foomo by bestbytes

S
Description
No description provided
Readme MIT
5.2 MiB
Languages
Go 99.3%
Makefile 0.7%