add orderby clause
Some checks failed
Go / build (1.22) (push) Failing after 1m58s
Go / build (1.21) (push) Failing after 2m1s

This commit is contained in:
saji 2024-03-06 10:48:40 -06:00
parent d90d7a0af4
commit 8e314e9303
4 changed files with 137 additions and 90 deletions

10
db.go
View file

@ -141,12 +141,20 @@ type LimitOffsetModifier struct {
Offset int Offset int
} }
func (l LimitOffsetModifier) ModifyStatement(sb *strings.Builder) error { func (l *LimitOffsetModifier) ModifyStatement(sb *strings.Builder) error {
clause := fmt.Sprintf(" LIMIT %d OFFSET %d", l.Limit, l.Offset) clause := fmt.Sprintf(" LIMIT %d OFFSET %d", l.Limit, l.Offset)
sb.WriteString(clause) sb.WriteString(clause)
return nil return nil
} }
type OrderByTimestampModifer struct {
}
func (o *OrderByTimestampModifer) ModifyStatement(sb *strings.Builder) error {
sb.WriteString(" ORDER BY ts DESC")
return nil
}
// BusEventFilter is a filter for bus events. // BusEventFilter is a filter for bus events.
type BusEventFilter struct { type BusEventFilter struct {
Names []string Names []string

View file

@ -264,12 +264,14 @@ func apiV1GetValues(db *TelemDb) http.HandlerFunc {
// override the bus event filter name option // override the bus event filter name option
bef.Names = []string{name} bef.Names = []string{name}
var order = &OrderByTimestampModifer{}
var res []Datum var res []Datum
// make the call, skip the limit modifier if it's nil. // make the call, skip the limit modifier if it's nil.
if lim == nil { if lim == nil {
res, err = db.GetValues(r.Context(), *bef, field) res, err = db.GetValues(r.Context(), *bef, field, order)
} else { } else {
res, err = db.GetValues(r.Context(), *bef, field, lim) res, err = db.GetValues(r.Context(), *bef, field, lim, order)
} }
if err != nil { if err != nil {
// 500 server error: // 500 server error:

View file

@ -68,3 +68,39 @@ Certain features, like socketCAN support, are only enabled on platforms that sup
This is handled automatically; builds will exclude the socketCAN files and This is handled automatically; builds will exclude the socketCAN files and
the additional commands and features will not be present in the CLI. the additional commands and features will not be present in the CLI.
### Lightweight Build
This doesn't include the OpenMCT files, but is simpler to build, and doesn't require Node setup.
You must install Go.
```
$ go build ./cmd/gotelem
```
### Full Build
This includes an integrated OpenMCT build, which automatically connects to the Telemetry server
for historical and live data. You must have both Go and Node.JS installed.
```
$ cd web/
$ npm install
$ npm run build
$ cd ..
$ go build -tags openmct ./cmd/gotelem
```
## Development
During development, it can be useful to have the OpenMCT sources be served separately from Gotelem,
so you don't need to rebuild everything. This case is supported:
```
$ go run ./cmd/gotelem server --db gotelem.db # in one terminal
$ npm run serve # in a separate terminal
```
When using the dev server, webpack will set the Gotelem URL to `localhost:8080`. If you're running
Gotelem using the default settings, this should work out of the box. Making changes to the OpenMCT
plugins will trigger a refresh automatically.

View file

@ -8,36 +8,36 @@ openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(openmct.plugins.Clock({ enableClockIndicator: true })); openmct.install(openmct.plugins.Clock({ enableClockIndicator: true }));
openmct.install(openmct.plugins.Timer()); openmct.install(openmct.plugins.Timer());
openmct.install(openmct.plugins.Timelist()); openmct.install(openmct.plugins.Timelist());
openmct.time.clock('local', {start: -5 * 60 * 1000, end: 0}); openmct.time.clock('local', { start: -5 * 60 * 1000, end: 0 });
openmct.time.timeSystem('utc'); openmct.time.timeSystem('utc');
openmct.install(openmct.plugins.Espresso()); openmct.install(openmct.plugins.Espresso());
openmct.install( openmct.install(
openmct.plugins.Conductor({ openmct.plugins.Conductor({
menuOptions: [ menuOptions: [
{ {
name: 'Fixed', name: 'Fixed',
timeSystem: 'utc', timeSystem: 'utc',
bounds: { bounds: {
start: Date.now() - 30000000, start: Date.now() - 30000000,
end: Date.now() end: Date.now()
}, },
}, },
{ {
name: 'Realtime', name: 'Realtime',
timeSystem: 'utc', timeSystem: 'utc',
clock: 'local', clock: 'local',
clockOffsets: { clockOffsets: {
start: -30000000, start: -30000000,
end: 30000 end: 30000
}, },
} }
] ]
}) })
); );
@ -61,73 +61,73 @@ function getSchema() {
const objectProvider = { const objectProvider = {
get: function (id) { get: function (id) {
return getSchema().then((schema) => { return getSchema().then((schema) => {
if (id.key === "car") { if (id.key === "car") {
const comp = schema.packets.map((x) => { const comp = schema.packets.map((x) => {
return { return {
key: x.name, key: x.name,
namespace: "umnsvp" namespace: "umnsvp"
}
})
return {
identifier: id,
name: "the solar car",
type: 'folder',
location: 'ROOT',
composition: comp
}
}
var pkt = schema.packets.find((x) => x.name === id.key)
if (pkt) {
// if the key matches one of the packet names,
// we know it's a field.
const comp = pkt.data.map((field) => {
return {
// we have to do this since
// we can't get the packet name otherwise.
key: `${pkt.name}.${field.name}`,
namespace: "umnsvp"
}
})
return {
identifier: id,
name: pkt.name,
type: 'folder',
composition: comp
}
}
// at this point it's definitely a field aka umnsvp-datum
var [pktName, fieldName] = id.key.split('.')
return {
identifier: id,
name: fieldName,
type: 'umnsvp-datum',
telemetry: {
values: [
{
key: "value",
source: "val",
name: "Value",
"format": "float",
hints: {
range: 1
}
},
{
key: "utc",
source: "ts",
name: "Timestamp",
format: "utc",
hints: {
domain: 1
}
} }
] })
return {
identifier: id,
name: "the solar car",
type: 'folder',
location: 'ROOT',
composition: comp
}
} }
} var pkt = schema.packets.find((x) => x.name === id.key)
if (pkt) {
// if the key matches one of the packet names,
// we know it's a field.
const comp = pkt.data.map((field) => {
return {
// we have to do this since
// we can't get the packet name otherwise.
key: `${pkt.name}.${field.name}`,
namespace: "umnsvp"
}
})
return {
identifier: id,
name: pkt.name,
type: 'folder',
composition: comp
}
}
// at this point it's definitely a field aka umnsvp-datum
var [pktName, fieldName] = id.key.split('.')
return {
identifier: id,
name: fieldName,
type: 'umnsvp-datum',
telemetry: {
values: [
{
key: "value",
source: "val",
name: "Value",
"format": "float",
hints: {
range: 1
}
},
{
key: "utc",
source: "ts",
name: "Timestamp",
format: "utc",
hints: {
domain: 1
}
}) }
]
}
}
})
} }
} }
@ -142,6 +142,7 @@ const TelemHistoryProvider = {
start: new Date(opt.start).toISOString(), start: new Date(opt.start).toISOString(),
end: new Date(opt.end).toISOString(), end: new Date(opt.end).toISOString(),
}) })
console.log((opt.end - opt.start)/opt.size)
return fetch(url + params).then((resp) => { return fetch(url + params).then((resp) => {
return resp.json() return resp.json()
}) })