aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2017-11-01 18:46:56 +0200
committerOskari Timperi <oskari.timperi@iki.fi>2017-11-01 18:46:56 +0200
commitfecdbdffdcfcf7b86f7e836ade6157b21c000be0 (patch)
treea9586aa1ebe3d3d7df1cec5ed896b4ee989adb81
parent557f9e77cfb0eceb353e582bb73787acbd402b7d (diff)
downloadnimrec-fecdbdffdcfcf7b86f7e836ade6157b21c000be0.tar.gz
nimrec-fecdbdffdcfcf7b86f7e836ade6157b21c000be0.zip
Add simple support for integer fields and integer validation
-rw-r--r--nimrec/recordset.nim40
-rw-r--r--tests/test.nim23
2 files changed, 63 insertions, 0 deletions
diff --git a/nimrec/recordset.nim b/nimrec/recordset.nim
index 9e6d90c..29422e9 100644
--- a/nimrec/recordset.nim
+++ b/nimrec/recordset.nim
@@ -2,6 +2,7 @@ import parser
import record
import utils
+import pegs
import sequtils
import sets
import streams
@@ -10,15 +11,29 @@ import tables
import times
type
+ FieldKind* {.pure.} = enum
+ Integer
+ String
+
+ FieldDescriptor* = ref object
+ kind*: FieldKind
+
RecordSet* = ref object
kind*: string
doc*: string
+ fields*: TableRef[string, FieldDescriptor]
mandatory*: HashSet[string]
allowed*: HashSet[string]
prohibited*: HashSet[string]
IntegrityError* = object of Exception
+proc addFieldDescriptor(recordSet: RecordSet, name: string): FieldDescriptor =
+ if name in recordSet.fields:
+ return recordSet.fields[name]
+ new(result)
+ recordSet.fields[name] = result
+
proc newRecordSet*(record: Record): RecordSet =
new(result)
@@ -31,6 +46,8 @@ proc newRecordSet*(record: Record): RecordSet =
if "%doc" in record:
result.doc = record["%doc"]
+ result.fields = newTable[string, FieldDescriptor]()
+
for value in values(record, "%mandatory"):
for field in split(value):
incl(result.mandatory, field)
@@ -52,6 +69,17 @@ proc newRecordSet*(record: Record): RecordSet =
raise newException(Exception, "a field cannot be allowed and prohibited at the same time")
incl(result.allowed, field)
+ for value in values(record, "%type"):
+ let parts = split(value)
+ let label = parts[0]
+ let kind = parts[1]
+ let desc = addFieldDescriptor(result, label)
+ case kind
+ of "int": desc.kind = FieldKind.Integer
+ else: desc.kind = FieldKind.String
+
+let integerPeg = peg"^ '-'? ('0' / ([1-9] \d*)) $"
+
proc validate*(record: Record, recordSet: RecordSet) =
let labels = toSet(toSeq(labels(record)))
@@ -68,6 +96,18 @@ proc validate*(record: Record, recordSet: RecordSet) =
raise newException(IntegrityError, format("mandatory: $1",
mandatoryLabel))
+ for label, value in record:
+ if label notin recordSet.fields:
+ continue
+
+ let desc = recordSet.fields[label]
+
+ case desc.kind
+ of FieldKind.Integer:
+ if not (value =~ integerPeg):
+ raise newException(IntegrityError, format("integer expected"))
+ else: discard
+
iterator recordsInSet*(stream: Stream, kind: string): Record =
var
currentSet: RecordSet = nil
diff --git a/tests/test.nim b/tests/test.nim
index 9721fb0..3eda4eb 100644
--- a/tests/test.nim
+++ b/tests/test.nim
@@ -410,3 +410,26 @@ Address: 10 Foobar Way
records = toSeq(records(ss))
expect(Exception):
discard newRecordSet(records[0])
+
+suite "type basics: integers":
+ const prologue = """
+%rec: Entry
+%type: Value int
+
+"""
+
+ test "valid integers":
+ const values = ["0", "1", "123456789", "987654321", "-123456789",
+ "-987654321", "-0"]
+
+ for value in values:
+ let data = prologue & "Value: " & value & "\n"
+ discard toSeq(recordsInSet(newStringStream(data), "Entry"))
+
+ test "invalid integers":
+ const values = ["0.0", "foobar", "01", "1-"]
+
+ for value in values:
+ let data = prologue & "Value: " & value & "\n"
+ expect(Exception):
+ discard toSeq(recordsInSet(newStringStream(data), "Entry"))