|
|
|
@ -2,7 +2,6 @@ package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"database/sql"
|
|
|
|
|
"database/sql/driver"
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/andrew-d/go-termutil"
|
|
|
|
|
"github.com/mattn/go-colorable"
|
|
|
|
@ -19,9 +18,9 @@ import (
|
|
|
|
|
|
|
|
|
|
var out = colorable.NewColorableStdout()
|
|
|
|
|
|
|
|
|
|
// Attr holds the data fetched from a row
|
|
|
|
|
// attrStruct holds the data fetched from a row
|
|
|
|
|
// Only 1 ValueXxx field should have value, the others should be nil
|
|
|
|
|
type Attr struct {
|
|
|
|
|
type attrStruct struct {
|
|
|
|
|
// Meta
|
|
|
|
|
ID sql.NullInt64
|
|
|
|
|
ParentID sql.NullInt64
|
|
|
|
@ -39,16 +38,16 @@ type Attr struct {
|
|
|
|
|
ValueTime time.Time
|
|
|
|
|
|
|
|
|
|
// Timestamps
|
|
|
|
|
CreatedAt NullTime
|
|
|
|
|
UpdatedAt NullTime
|
|
|
|
|
AccessedAt NullTime
|
|
|
|
|
DeletedAt NullTime
|
|
|
|
|
CreatedAt nullTime
|
|
|
|
|
UpdatedAt nullTime
|
|
|
|
|
AccessedAt nullTime
|
|
|
|
|
DeletedAt nullTime
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const sqlSelect = "id, value_text, name, parent_id, alias, mark, value_blob, created_at, updated_at"
|
|
|
|
|
|
|
|
|
|
// GetID returns the int64 value of attr's ID.
|
|
|
|
|
func (attr Attr) GetID() int64 {
|
|
|
|
|
// getID returns the int64 value of attr's ID.
|
|
|
|
|
func (attr attrStruct) getID() int64 {
|
|
|
|
|
//var err error
|
|
|
|
|
if value, err := attr.ID.Value(); err == nil && value != nil {
|
|
|
|
|
return value.(int64)
|
|
|
|
@ -56,7 +55,8 @@ func (attr Attr) GetID() int64 {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) GetCreatedAt() (t time.Time) {
|
|
|
|
|
// getCreatedAt returns created_at time
|
|
|
|
|
func (attr attrStruct) getCreatedAt() (t time.Time) {
|
|
|
|
|
//var err error
|
|
|
|
|
if value, err := attr.CreatedAt.Value(); err == nil && value != nil {
|
|
|
|
|
t = value.(time.Time)
|
|
|
|
@ -65,7 +65,8 @@ func (attr Attr) GetCreatedAt() (t time.Time) {
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) GetUpdatedAt() (t time.Time) {
|
|
|
|
|
// getUpdatedAt returns updated_at time
|
|
|
|
|
func (attr attrStruct) getUpdatedAt() (t time.Time) {
|
|
|
|
|
//var err error
|
|
|
|
|
if value, err := attr.UpdatedAt.Value(); err == nil && value != nil {
|
|
|
|
|
t = value.(time.Time)
|
|
|
|
@ -74,7 +75,8 @@ func (attr Attr) GetUpdatedAt() (t time.Time) {
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) GetAccessedAt() (t time.Time) {
|
|
|
|
|
// getAccessedAt returns accessed_at time
|
|
|
|
|
func (attr attrStruct) getAccessedAt() (t time.Time) {
|
|
|
|
|
//var err error
|
|
|
|
|
if value, err := attr.AccessedAt.Value(); err == nil && value != nil {
|
|
|
|
|
t = value.(time.Time)
|
|
|
|
@ -83,7 +85,8 @@ func (attr Attr) GetAccessedAt() (t time.Time) {
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) GetDeletedAt() (t time.Time) {
|
|
|
|
|
// getDeletedAt returns deleted_at time
|
|
|
|
|
func (attr attrStruct) getDeletedAt() (t time.Time) {
|
|
|
|
|
//var err error
|
|
|
|
|
if value, err := attr.DeletedAt.Value(); err == nil && value != nil {
|
|
|
|
|
t = value.(time.Time)
|
|
|
|
@ -92,19 +95,19 @@ func (attr Attr) GetDeletedAt() (t time.Time) {
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetIDString returns the string value of attr's ID.
|
|
|
|
|
func (attr Attr) GetIDString() string {
|
|
|
|
|
// getIDString returns the string value of attr's ID.
|
|
|
|
|
func (attr attrStruct) getIDString() string {
|
|
|
|
|
var err error
|
|
|
|
|
if value, err := attr.ID.Value(); err == nil && value != nil {
|
|
|
|
|
return strconv.Itoa(int(value.(int64)))
|
|
|
|
|
}
|
|
|
|
|
log.Fatal("Attr is not loaded, has no id")
|
|
|
|
|
log.Fatal("attrStruct is not loaded, has no id")
|
|
|
|
|
check(err)
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetMark returns the int value of attr's mark
|
|
|
|
|
func (attr Attr) GetMark() int {
|
|
|
|
|
// getMark returns the int value of attr's mark
|
|
|
|
|
func (attr attrStruct) getMark() int {
|
|
|
|
|
var err error
|
|
|
|
|
if value, err := attr.Mark.Value(); err == nil && value != nil {
|
|
|
|
|
return int(value.(int64))
|
|
|
|
@ -114,30 +117,29 @@ func (attr Attr) GetMark() int {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetIdentifier returns attr's ID, or its Alias if it is not nil.
|
|
|
|
|
func (attr Attr) GetIdentifier() string {
|
|
|
|
|
alias := attr.GetAlias()
|
|
|
|
|
// getIdentifier returns attr's ID, or its Alias if it is not nil.
|
|
|
|
|
func (attr attrStruct) getIdentifier() string {
|
|
|
|
|
alias := attr.getAlias()
|
|
|
|
|
if len(alias) > 0 {
|
|
|
|
|
return alias
|
|
|
|
|
} else {
|
|
|
|
|
return attr.GetIDString()
|
|
|
|
|
}
|
|
|
|
|
return attr.getIDString()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetName is a helper to get attr's Name as string
|
|
|
|
|
func (attr Attr) GetName() string {
|
|
|
|
|
// getName is a helper to get attr's Name as string
|
|
|
|
|
func (attr attrStruct) getName() string {
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
if value, err := attr.Name.Value(); err == nil && value != nil {
|
|
|
|
|
return value.(string)
|
|
|
|
|
}
|
|
|
|
|
log.Fatal("Attr is not loaded, has no name")
|
|
|
|
|
log.Fatal("attrStruct is not loaded, has no name")
|
|
|
|
|
check(err)
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetName is a helper to get attr's Name as string
|
|
|
|
|
func (attr Attr) GetAlias() string {
|
|
|
|
|
// getAlias returns attr's alias
|
|
|
|
|
func (attr attrStruct) getAlias() string {
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
if value, err := attr.Alias.Value(); err == nil && value != nil {
|
|
|
|
@ -147,8 +149,8 @@ func (attr Attr) GetAlias() string {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetTextValue returns a string representation of attr's value, whatever type it is
|
|
|
|
|
func (attr Attr) GetTextValue() string {
|
|
|
|
|
// getTextValue returns a string representation of attr's value, whatever type it is
|
|
|
|
|
func (attr attrStruct) getTextValue() string {
|
|
|
|
|
var err error
|
|
|
|
|
if value, err := attr.ValueText.Value(); err == nil && value != nil {
|
|
|
|
|
return value.(string)
|
|
|
|
@ -157,9 +159,9 @@ func (attr Attr) GetTextValue() string {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetValue returns a string representation of attr's value, in order of
|
|
|
|
|
// getValue returns a string representation of attr's value, in order of
|
|
|
|
|
// preference: first ValueBlob, then ValueText, then ValueInt, then ValueReal
|
|
|
|
|
func (attr Attr) GetValue() string {
|
|
|
|
|
func (attr attrStruct) getValue() string {
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
// if ValueBlov exists
|
|
|
|
@ -182,13 +184,13 @@ func (attr Attr) GetValue() string {
|
|
|
|
|
}
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
log.Fatal("Attr is not loaded, has no value")
|
|
|
|
|
log.Fatal("attrStruct is not loaded, has no value")
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Print pretty-prints attr's field values.
|
|
|
|
|
func (attr Attr) Print(w *tabwriter.Writer, verbose bool, indent int, highlighteds []string, after int) {
|
|
|
|
|
// print pretty-prints attr's field values.
|
|
|
|
|
func (attr attrStruct) print(w *tabwriter.Writer, verbose bool, indent int, highlighteds []string, after int) {
|
|
|
|
|
debug := false
|
|
|
|
|
|
|
|
|
|
if debug {
|
|
|
|
@ -220,28 +222,28 @@ func (attr Attr) Print(w *tabwriter.Writer, verbose bool, indent int, highlighte
|
|
|
|
|
//fmt.Fprintf(w, "%s\t", prettyAttr("at", attr.prettyAt()))
|
|
|
|
|
|
|
|
|
|
// Name:
|
|
|
|
|
//fmt.Fprintf(w, "%s\t", prettyAttr("name", attr.GetName()))
|
|
|
|
|
//fmt.Fprintf(w, "%s\t", prettyAttr("name", attr.getName()))
|
|
|
|
|
|
|
|
|
|
// Value:
|
|
|
|
|
//fmt.Printf(strings.Repeat(" ", indent))
|
|
|
|
|
|
|
|
|
|
if attr.GetMark() == 0 {
|
|
|
|
|
fmt.Fprintf(out, "[%s] %s\n", Color(attr.GetIdentifier(), "yellow+b"), attr.Title())
|
|
|
|
|
if attr.getMark() == 0 {
|
|
|
|
|
fmt.Fprintf(out, "[%s] %s\n", color(attr.getIdentifier(), "yellow+b"), attr.title())
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(out, "%s %s\n", Color("("+attr.GetIdentifier()+")", "black+b:white"), Color(attr.Title(), "default"))
|
|
|
|
|
fmt.Fprintf(out, "%s %s\n", color("("+attr.getIdentifier()+")", "black+b:white"), color(attr.title(), "default"))
|
|
|
|
|
}
|
|
|
|
|
if len(highlighteds) > 0 {
|
|
|
|
|
fmt.Fprintln(out, attr.PrettyMatches(highlighteds, after))
|
|
|
|
|
fmt.Fprintln(out, attr.prettyMatches(highlighteds, after))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) PrettyMatches(highlighteds []string, after int) string {
|
|
|
|
|
func (attr attrStruct) prettyMatches(highlighteds []string, after int) string {
|
|
|
|
|
var valueText string
|
|
|
|
|
if len(highlighteds) == 0 {
|
|
|
|
|
valueText = attr.Title()
|
|
|
|
|
valueText = attr.title()
|
|
|
|
|
} else {
|
|
|
|
|
valueText = strings.TrimSpace(attr.GetValue())
|
|
|
|
|
valueText = strings.TrimSpace(attr.getValue())
|
|
|
|
|
|
|
|
|
|
matchinglines := make([]string, 0, 0)
|
|
|
|
|
|
|
|
|
@ -255,13 +257,13 @@ func (attr Attr) PrettyMatches(highlighteds []string, after int) string {
|
|
|
|
|
if matched {
|
|
|
|
|
lastMatchingLine = linenumber
|
|
|
|
|
if true || !isCoveredByLastMatch {
|
|
|
|
|
matchCounter += 1
|
|
|
|
|
matchCounter++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if matched || isCoveredByLastMatch {
|
|
|
|
|
//prefix := fmt.Sprintf("%s L%s:", strings.Repeat(" ", len(attr.GetIdentifier())), strconv.Itoa(linenumber+1))
|
|
|
|
|
prefix := fmt.Sprintf("%s", strings.Repeat(" ", 3+len(attr.GetIdentifier())))
|
|
|
|
|
matchinglines = append(matchinglines, Color(prefix, "black")+line)
|
|
|
|
|
//prefix := fmt.Sprintf("%s L%s:", strings.Repeat(" ", len(attr.getIdentifier())), strconv.Itoa(linenumber+1))
|
|
|
|
|
prefix := fmt.Sprintf("%s", strings.Repeat(" ", 3+len(attr.getIdentifier())))
|
|
|
|
|
matchinglines = append(matchinglines, color(prefix, "black")+line)
|
|
|
|
|
if maximumShownMatches != -1 && matchCounter >= maximumShownMatches {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
@ -273,8 +275,8 @@ func (attr Attr) PrettyMatches(highlighteds []string, after int) string {
|
|
|
|
|
return valueText + "\n"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) Title() string {
|
|
|
|
|
valueText := strings.TrimSpace(attr.GetTextValue())
|
|
|
|
|
func (attr attrStruct) title() string {
|
|
|
|
|
valueText := strings.TrimSpace(attr.getTextValue())
|
|
|
|
|
firstLineEndIndex := strings.Index(valueText, "\n")
|
|
|
|
|
|
|
|
|
|
if firstLineEndIndex >= 0 {
|
|
|
|
@ -287,37 +289,35 @@ func (attr Attr) Title() string {
|
|
|
|
|
return valueText
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) prettyAt() string {
|
|
|
|
|
if attr.GetUpdatedAt().IsZero() {
|
|
|
|
|
return attr.GetCreatedAt().Local().Format(datelayout) // + " "
|
|
|
|
|
} else {
|
|
|
|
|
return attr.GetUpdatedAt().Local().Format(datelayout) // + "*"
|
|
|
|
|
func (attr attrStruct) prettyAt() string {
|
|
|
|
|
if attr.getUpdatedAt().IsZero() {
|
|
|
|
|
return attr.getCreatedAt().Local().Format(datelayout) // + " "
|
|
|
|
|
}
|
|
|
|
|
return attr.getUpdatedAt().Local().Format(datelayout) // + "*"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) prettyCreatedAt() string {
|
|
|
|
|
return attr.GetCreatedAt().Local().Format(datelayout)
|
|
|
|
|
func (attr attrStruct) prettyCreatedAt() string {
|
|
|
|
|
return attr.getCreatedAt().Local().Format(datelayout)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) prettyUpdatedAt() string {
|
|
|
|
|
if !attr.GetUpdatedAt().IsZero() {
|
|
|
|
|
return attr.GetUpdatedAt().Local().Format(datelayout)
|
|
|
|
|
} else {
|
|
|
|
|
return ""
|
|
|
|
|
func (attr attrStruct) prettyUpdatedAt() string {
|
|
|
|
|
if !attr.getUpdatedAt().IsZero() {
|
|
|
|
|
return attr.getUpdatedAt().Local().Format(datelayout)
|
|
|
|
|
}
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) Filepath() string {
|
|
|
|
|
func (attr attrStruct) filepath() string {
|
|
|
|
|
f, err := ioutil.TempFile("", "eton-edit")
|
|
|
|
|
check(err)
|
|
|
|
|
f.Close()
|
|
|
|
|
writeToFile(f.Name(), attr.GetValue())
|
|
|
|
|
writeToFile(f.Name(), attr.getValue())
|
|
|
|
|
return f.Name()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetAlias sets attr's Alias to the given alias.
|
|
|
|
|
// setAlias sets attr's Alias to the given alias.
|
|
|
|
|
// If give alias is empty string, it will unset the alias (set it to NULL in the database).
|
|
|
|
|
func (attr Attr) SetAlias(db *sql.DB, alias string) {
|
|
|
|
|
func (attr attrStruct) setAlias(db *sql.DB, alias string) {
|
|
|
|
|
|
|
|
|
|
unset := len(alias) == 0
|
|
|
|
|
if !unset {
|
|
|
|
@ -333,28 +333,28 @@ func (attr Attr) SetAlias(db *sql.DB, alias string) {
|
|
|
|
|
|
|
|
|
|
//var result sql.Result
|
|
|
|
|
if !unset {
|
|
|
|
|
_, err = stmt.Exec(alias, attr.GetID())
|
|
|
|
|
_, err = stmt.Exec(alias, attr.getID())
|
|
|
|
|
} else {
|
|
|
|
|
_, err = stmt.Exec(nil, attr.GetID())
|
|
|
|
|
_, err = stmt.Exec(nil, attr.getID())
|
|
|
|
|
}
|
|
|
|
|
//check(err)
|
|
|
|
|
if err == nil {
|
|
|
|
|
if unset {
|
|
|
|
|
fmt.Fprintf(out, "ID:%d unaliased\n", attr.GetID())
|
|
|
|
|
fmt.Fprintf(out, "ID:%d unaliased\n", attr.getID())
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(out, "alias set: %s => %s\n", attr.GetIdentifier(), alias)
|
|
|
|
|
fmt.Fprintf(out, "alias set: %s => %s\n", attr.getIdentifier(), alias)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log.Fatalf("error while setting alias \"%s\" for ID:%d -- alias must be unique\n", alias, attr.GetID()) // , err)
|
|
|
|
|
log.Fatalf("error while setting alias \"%s\" for ID:%d -- alias must be unique\n", alias, attr.getID()) // , err)
|
|
|
|
|
}
|
|
|
|
|
//rowsAffected, err := result.RowsAffected()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) SetMark(db *sql.DB, mark int) (rowsAffected int64) {
|
|
|
|
|
func (attr attrStruct) setMark(db *sql.DB, mark int) (rowsAffected int64) {
|
|
|
|
|
stmt, err := db.Prepare("UPDATE attributes SET mark = ? WHERE id = ? AND deleted_at IS NULL")
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
result, err := stmt.Exec(mark, attr.GetID())
|
|
|
|
|
result, err := stmt.Exec(mark, attr.getID())
|
|
|
|
|
check(err)
|
|
|
|
|
rowsAffected, err = result.RowsAffected()
|
|
|
|
|
check(err)
|
|
|
|
@ -362,11 +362,11 @@ func (attr Attr) SetMark(db *sql.DB, mark int) (rowsAffected int64) {
|
|
|
|
|
return rowsAffected
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) Rm(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
func (attr attrStruct) rm(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
stmt, err := db.Prepare("UPDATE attributes SET deleted_at = CURRENT_TIMESTAMP WHERE id = ? AND deleted_at IS NULL")
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
result, err := stmt.Exec(attr.GetID())
|
|
|
|
|
result, err := stmt.Exec(attr.getID())
|
|
|
|
|
check(err)
|
|
|
|
|
rowsAffected, err = result.RowsAffected()
|
|
|
|
|
check(err)
|
|
|
|
@ -374,11 +374,11 @@ func (attr Attr) Rm(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
return rowsAffected
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) Unrm(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
func (attr attrStruct) unrm(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
stmt, err := db.Prepare("UPDATE attributes SET deleted_at = NULL WHERE id = ? AND deleted_at IS NOT NULL")
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
result, err := stmt.Exec(attr.GetID())
|
|
|
|
|
result, err := stmt.Exec(attr.getID())
|
|
|
|
|
check(err)
|
|
|
|
|
rowsAffected, err = result.RowsAffected()
|
|
|
|
|
check(err)
|
|
|
|
@ -386,11 +386,11 @@ func (attr Attr) Unrm(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
return rowsAffected
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) IncrementFrequency(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
func (attr attrStruct) incrementFrequency(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
stmt, err := db.Prepare("UPDATE attributes SET frequency = frequency + 1 WHERE id = ? AND deleted_at IS NULL")
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
result, err := stmt.Exec(attr.GetID())
|
|
|
|
|
result, err := stmt.Exec(attr.getID())
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
rowsAffected, err = result.RowsAffected()
|
|
|
|
@ -398,20 +398,20 @@ func (attr Attr) IncrementFrequency(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (attr Attr) Edit(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
filepath := attr.Filepath()
|
|
|
|
|
func (attr attrStruct) edit(db *sql.DB) (rowsAffected int64) {
|
|
|
|
|
filepath := attr.filepath()
|
|
|
|
|
|
|
|
|
|
if openEditor(filepath) == false {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value_text := readFile(filepath)
|
|
|
|
|
valueText := readFile(filepath)
|
|
|
|
|
|
|
|
|
|
if value_text != attr.GetValue() {
|
|
|
|
|
update_stmt, err := db.Prepare("UPDATE attributes SET value_text = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
|
|
|
|
if valueText != attr.getValue() {
|
|
|
|
|
updateStmt, err := db.Prepare("UPDATE attributes SET value_text = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?")
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
result, err := update_stmt.Exec(value_text, attr.GetID())
|
|
|
|
|
result, err := updateStmt.Exec(valueText, attr.getID())
|
|
|
|
|
check(err)
|
|
|
|
|
rowsAffected, err = result.RowsAffected()
|
|
|
|
|
check(err)
|
|
|
|
@ -429,7 +429,7 @@ func writeToFile(filepath string, content string) {
|
|
|
|
|
func highlightLine(line string, highlighteds []string) (string, bool) {
|
|
|
|
|
if len(highlighteds) == 0 {
|
|
|
|
|
return line, false
|
|
|
|
|
} else {
|
|
|
|
|
}
|
|
|
|
|
reFlags := "(?i)"
|
|
|
|
|
|
|
|
|
|
quotedHighlighteds := make([]string, len(highlighteds), len(highlighteds))
|
|
|
|
@ -469,11 +469,10 @@ func highlightLine(line string, highlighteds []string) (string, bool) {
|
|
|
|
|
afterStr = ellipsis
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line = re.ReplaceAllString(line[indexBegin:indexEnd], Color("$0", "black+b:green"))
|
|
|
|
|
line = re.ReplaceAllString(line[indexBegin:indexEnd], color("$0", "black+b:green"))
|
|
|
|
|
return beforeStr + line + afterStr, true
|
|
|
|
|
}
|
|
|
|
|
return line, false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func prettyAttr(name, value string) string {
|
|
|
|
@ -482,35 +481,32 @@ func prettyAttr(name, value string) string {
|
|
|
|
|
}
|
|
|
|
|
if termutil.Isatty(os.Stdout.Fd()) {
|
|
|
|
|
return ansi.Color(name, "black") + ansi.Color(value, "default")
|
|
|
|
|
} else {
|
|
|
|
|
return name + value
|
|
|
|
|
}
|
|
|
|
|
return name + value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func prettyAttr2(name, value string) string {
|
|
|
|
|
if termutil.Isatty(os.Stdout.Fd()) {
|
|
|
|
|
return ansi.Color(name+":", "black") + ansi.Color(value, "blue")
|
|
|
|
|
} else {
|
|
|
|
|
return name + ":" + value
|
|
|
|
|
}
|
|
|
|
|
return name + ":" + value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Color is the same as ansi.Color but only if STDOUT is a TTY
|
|
|
|
|
func Color(str, color string) string {
|
|
|
|
|
// color is the same as ansi.Color but only if STDOUT is a TTY
|
|
|
|
|
func color(str, color string) string {
|
|
|
|
|
if termutil.Isatty(os.Stdout.Fd()) {
|
|
|
|
|
return ansi.Color(str, color)
|
|
|
|
|
} else {
|
|
|
|
|
return str
|
|
|
|
|
}
|
|
|
|
|
return str
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func findAttributeByID(db *sql.DB, ID int64) (attr Attr) {
|
|
|
|
|
func findAttributeByID(db *sql.DB, ID int64) (attr attrStruct) {
|
|
|
|
|
var err error
|
|
|
|
|
var stmt *sql.Stmt
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
|
if err == nil {
|
|
|
|
|
attr.IncrementFrequency(db)
|
|
|
|
|
attr.incrementFrequency(db)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
@ -524,13 +520,13 @@ func findAttributeByID(db *sql.DB, ID int64) (attr Attr) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func findAttributeByAlias(db *sql.DB, alias string, exactMatchOnly bool) (attr Attr) {
|
|
|
|
|
func findAttributeByAlias(db *sql.DB, alias string, exactMatchOnly bool) (attr attrStruct) {
|
|
|
|
|
var err error
|
|
|
|
|
var stmt *sql.Stmt
|
|
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
|
if err == nil {
|
|
|
|
|
attr.IncrementFrequency(db)
|
|
|
|
|
attr.incrementFrequency(db)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
@ -572,11 +568,11 @@ func findAttributeByAlias(db *sql.DB, alias string, exactMatchOnly bool) (attr A
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func findAttributeByAliasOrID(db *sql.DB, alias_or_id string) (attr Attr) {
|
|
|
|
|
attr = findAttributeByAlias(db, alias_or_id, false)
|
|
|
|
|
if attr.GetID() <= 0 {
|
|
|
|
|
func findAttributeByAliasOrID(db *sql.DB, indentifier string) (attr attrStruct) {
|
|
|
|
|
attr = findAttributeByAlias(db, indentifier, false)
|
|
|
|
|
if attr.getID() <= 0 {
|
|
|
|
|
|
|
|
|
|
intID, err := strconv.Atoi(alias_or_id)
|
|
|
|
|
intID, err := strconv.Atoi(indentifier)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
return attr
|
|
|
|
@ -588,7 +584,7 @@ func findAttributeByAliasOrID(db *sql.DB, alias_or_id string) (attr Attr) {
|
|
|
|
|
return attr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func listWithFilters(db *sql.DB, opts Options) (attrs []Attr) {
|
|
|
|
|
func listWithFilters(db *sql.DB, opts options) (attrs []attrStruct) {
|
|
|
|
|
var stmt *sql.Stmt
|
|
|
|
|
var rows *sql.Rows
|
|
|
|
|
var nolimit = opts.Limit == -1
|
|
|
|
@ -655,17 +651,17 @@ func listWithFilters(db *sql.DB, opts Options) (attrs []Attr) {
|
|
|
|
|
check(err)
|
|
|
|
|
defer rows.Close()
|
|
|
|
|
|
|
|
|
|
attrs = make([]Attr, 0, 0)
|
|
|
|
|
attrs = make([]attrStruct, 0, 0)
|
|
|
|
|
|
|
|
|
|
for rows.Next() {
|
|
|
|
|
attr := Attr{}
|
|
|
|
|
attr := attrStruct{}
|
|
|
|
|
err = rows.Scan(&attr.ID, &attr.ValueText, &attr.Name, &attr.ParentID, &attr.Alias, &attr.Mark, &attr.ValueBlob, &attr.CreatedAt, &attr.UpdatedAt)
|
|
|
|
|
check(err)
|
|
|
|
|
attrs = append(attrs, attr)
|
|
|
|
|
|
|
|
|
|
var optsNew Options
|
|
|
|
|
var optsNew options
|
|
|
|
|
optsNew = opts
|
|
|
|
|
optsNew.RootID = attr.GetID()
|
|
|
|
|
optsNew.RootID = attr.getID()
|
|
|
|
|
optsNew.Indent += 2
|
|
|
|
|
//cmdLs(db, w, optsNew)
|
|
|
|
|
}
|
|
|
|
@ -686,20 +682,20 @@ func getLastAttrID(db *sql.DB) int64 {
|
|
|
|
|
return ID
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func saveString(db *sql.DB, value_text string) (lastInsertId int64) {
|
|
|
|
|
new_stmt, err := db.Prepare("INSERT INTO attributes (name, value_text) VALUES ('note', ?)")
|
|
|
|
|
func saveString(db *sql.DB, valueText string) (lastInsertID int64) {
|
|
|
|
|
stmt, err := db.Prepare("INSERT INTO attributes (name, value_text) VALUES ('note', ?)")
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
result, err := new_stmt.Exec(value_text)
|
|
|
|
|
result, err := stmt.Exec(valueText)
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
lastInsertId, err = result.LastInsertId()
|
|
|
|
|
lastInsertID, err = result.LastInsertId()
|
|
|
|
|
check(err)
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func InitializeDatabase(db *sql.DB) bool {
|
|
|
|
|
func initializeDatabase(db *sql.DB) bool {
|
|
|
|
|
// TODO use fts3 for faster full-text search: CREATE VIRTUAL TABLE attributes USING fts3 (...)
|
|
|
|
|
sqlStmt := `
|
|
|
|
|
DROP TABLE IF EXISTS attributes;
|
|
|
|
@ -743,23 +739,3 @@ func InitializeDatabase(db *sql.DB) bool {
|
|
|
|
|
fmt.Fprintln(out, "repository initiated")
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NullTime allows timestamps to be NULL
|
|
|
|
|
type NullTime struct {
|
|
|
|
|
Time time.Time
|
|
|
|
|
Valid bool // Valid is true if Time is not NULL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Scan implements the Scanner interface.
|
|
|
|
|
func (nt *NullTime) Scan(value interface{}) error {
|
|
|
|
|
nt.Time, nt.Valid = value.(time.Time)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Value implements the driver Valuer interface.
|
|
|
|
|
func (nt NullTime) Value() (driver.Value, error) {
|
|
|
|
|
if !nt.Valid {
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
|
return nt.Time, nil
|
|
|
|
|
}
|
|
|
|
|