Skip to content

Commit

Permalink
Adding HasRecord() call. Ensure a new record's deletion flag default …
Browse files Browse the repository at this point in the history
…to active.
  • Loading branch information
LindsayBradford committed Mar 16, 2022
1 parent a4c6348 commit aa6cee3
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 24 deletions.
35 changes: 21 additions & 14 deletions godbf/dbftable.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,11 @@ func (dt *DbfTable) addField(fieldName string, fieldType DbaseDataType, length b

slice := dt.convertToByteSlice(df.name, fieldNameByteLength)

//fmt.Printf("len slice:%v\n", len(slice))

// Field name in ASCII (max 10 chracters)
for i := 0; i < len(slice); i++ {
df.fieldStore[i] = slice[i]
//fmt.Printf("i:%s\n", string(slice[i]))
}

// Field names are terminated by 00h
df.fieldStore[fieldNameByteLength] = endOfFieldMarker

// Set field's data type
Expand Down Expand Up @@ -270,9 +266,9 @@ func (dt *DbfTable) updateHeader() {
dt.dataStore[8] = s[0]
dt.dataStore[9] = s[1]

dt.lengthOfEachRecord = lengthOfEachRecord + 1 // dont forget to add "1" for deletion marker which is 20h
dt.lengthOfEachRecord = lengthOfEachRecord + 1 // don't forget to add "1" for deletion marker which is 20h

// update the lenght of each record
// update the length of each record
s = uint32ToBytes(uint32(dt.lengthOfEachRecord))
dt.dataStore[10] = s[0]
dt.dataStore[11] = s[1]
Expand Down Expand Up @@ -322,21 +318,25 @@ func (dt *DbfTable) DecimalPlacesInField(fieldName string) (uint8, error) {
}
}

return 0, errors.New("Type of field \"" + fieldName + "\" is not Numeric or Float.")
return 0, errors.New("type of field \"" + fieldName + "\" is not Numeric or Float")
}

const recordDeletionFlagIndex = 0
const recordIsActive = blank
const recordIsDeleted = 0x2A

// AddNewRecord adds a new empty record to the table, and returns the index number of the record.
func (dt *DbfTable) AddNewRecord() (newRecordNumber int) {
func (dt *DbfTable) AddNewRecord() (newRecordNumber int, addErr error) {
if dt.lengthOfEachRecord == 0 {
return -1, errors.New("attempted to add record with no fields defined")
}

if dt.dataEntryStarted == false {
dt.dataEntryStarted = true
}

newRecord := make([]byte, dt.lengthOfEachRecord)
// each record begins with a 1-byte "deletion" flag. If record is active the byte's value is a space (0x20)
if dt.lengthOfEachRecord > 0 {
newRecord[0] = 0x20
}
newRecord[recordDeletionFlagIndex] = recordIsActive
dt.dataStore = appendSlice(dt.dataStore, newRecord)

// since row numbers are "0" based first we set newRecordNumber
Expand All @@ -352,14 +352,21 @@ func (dt *DbfTable) AddNewRecord() (newRecordNumber int) {
dt.dataStore[7] = s[3]
//fmt.Printf("Number of rows after:%d\n", dt.numberOfRecords)

return newRecordNumber
return newRecordNumber, nil
}

// NumberOfRecords returns the number of records in the table
func (dt *DbfTable) NumberOfRecords() int {
return int(dt.numberOfRecords)
}

// HasRecord returns true if the table has a record with the given number otherwise, false is returned.
// Use this method before FieldValue() to avoid index-out-of-range errors.
func (dt *DbfTable) HasRecord(recordNumber int) bool {
recordOffset := int(dt.numberOfBytesInHeader) + recordNumber*int(dt.lengthOfEachRecord)
return len(dt.dataStore) >= recordOffset+int(dt.lengthOfEachRecord)
}

// SetFieldValueByName sets the value for the given row and field name as specified
// If the field name does not exist, or the value is incompatible with the field's type, an error is returned.
func (dt *DbfTable) SetFieldValueByName(row int, fieldName string, value string) (err error) {
Expand Down Expand Up @@ -501,7 +508,7 @@ func (dt *DbfTable) RowIsDeleted(row int) bool {
offset := int(dt.numberOfBytesInHeader)
lengthOfRecord := int(dt.lengthOfEachRecord)
offset = offset + (row * lengthOfRecord)
return dt.dataStore[offset:(offset + 1)][0] == 0x2A
return dt.dataStore[offset:(offset + 1)][recordDeletionFlagIndex] == recordIsDeleted
}

// GetRowAsSlice return the record values for the row specified as a string slice
Expand Down
31 changes: 21 additions & 10 deletions godbf/dbftable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ func TestDbfTable_GetRowAsSlice_InitiallyEmptyStrings(t *testing.T) {
floatFieldName := "floatField"
tableUnderTest.AddBooleanField(floatFieldName)

recordIndex := tableUnderTest.AddNewRecord()
recordIndex, _ := tableUnderTest.AddNewRecord()

fieldValues := tableUnderTest.GetRowAsSlice(recordIndex)

Expand Down Expand Up @@ -274,7 +274,7 @@ func TestDbfTable_GetRowAsSlice(t *testing.T) {
expectedFloatFieldValue := "640.42"
tableUnderTest.AddFloatField(floatFieldName, 6, 2)

recordIndex := tableUnderTest.AddNewRecord()
recordIndex, _ := tableUnderTest.AddNewRecord()

tableUnderTest.SetFieldValueByName(recordIndex, boolFieldName, expectedBoolFieldValue)
tableUnderTest.SetFieldValueByName(recordIndex, textFieldName, expectedTextFieldValue)
Expand Down Expand Up @@ -316,7 +316,7 @@ func TestDbfTable_FieldValueByName(t *testing.T) {
expectedFloatFieldValue := "640.42"
tableUnderTest.AddFloatField(floatFieldName, 6, 2)

recordIndex := tableUnderTest.AddNewRecord()
recordIndex, _ := tableUnderTest.AddNewRecord()

tableUnderTest.SetFieldValueByName(recordIndex, boolFieldName, expectedBoolFieldValue)
tableUnderTest.SetFieldValueByName(recordIndex, textFieldName, expectedTextFieldValue)
Expand All @@ -336,9 +336,10 @@ func TestDbfTable_FieldValueByName_NonExistentField(t *testing.T) {

tableUnderTest := New(testEncoding)

recordIndex := tableUnderTest.AddNewRecord()
textFieldName := "textField"
tableUnderTest.AddTextField(textFieldName, 10)

_, valueError := tableUnderTest.FieldValueByName(recordIndex, "missingField")
_, valueError := tableUnderTest.FieldValueByName(0, "missingField")

g.Expect(valueError).ToNot(BeNil())
t.Log(valueError)
Expand All @@ -349,14 +350,22 @@ func TestDbfTable_SetFieldValueByName_NonExistentField(t *testing.T) {

tableUnderTest := New(testEncoding)

recordIndex := tableUnderTest.AddNewRecord()

setError := tableUnderTest.SetFieldValueByName(recordIndex, "missingField", "someText")
setError := tableUnderTest.SetFieldValueByName(0, "missingField", "someText")

g.Expect(setError).ToNot(BeNil())
t.Log(setError)
}

func TestDbfTable_AddRecordWithNoFieldsDefined_Errors(t *testing.T) {
g := NewGomegaWithT(t)

tableUnderTest := New(testEncoding)

recordIndex, addErr := tableUnderTest.AddNewRecord()
g.Expect(addErr).ToNot(BeNil())
g.Expect(recordIndex).To(BeEquivalentTo(-1))
}

func TestDbfTable_Int64FieldValueByName(t *testing.T) {
g := NewGomegaWithT(t)

Expand All @@ -367,7 +376,8 @@ func TestDbfTable_Int64FieldValueByName(t *testing.T) {
expectedIntFieldValue := fmt.Sprintf("%d", expectedIntValue)
tableUnderTest.AddNumberField(intFieldName, 6, 2)

recordIndex := tableUnderTest.AddNewRecord()
recordIndex, addErr := tableUnderTest.AddNewRecord()
g.Expect(addErr).To(BeNil())

tableUnderTest.SetFieldValueByName(recordIndex, intFieldName, expectedIntFieldValue)

Expand All @@ -387,7 +397,8 @@ func TestDbfTable_Float64FieldValueByName(t *testing.T) {
expectedFloatFieldValue := fmt.Sprintf("%.2f", expectedFloatValue)
tableUnderTest.AddFloatField(floatFieldName, 10, 2)

recordIndex := tableUnderTest.AddNewRecord()
recordIndex, addErr := tableUnderTest.AddNewRecord()
g.Expect(addErr).To(BeNil())

tableUnderTest.SetFieldValueByName(recordIndex, floatFieldName, expectedFloatFieldValue)

Expand Down

0 comments on commit aa6cee3

Please sign in to comment.