Change expr/stmt in examples to untyped (#6734)
This commit is contained in:
parent
5e66a7ce59
commit
ac5dff2e04
16 changed files with 56 additions and 119 deletions
|
|
@ -85,7 +85,7 @@
|
||||||
<int key="IBUITag">2</int>
|
<int key="IBUITag">2</int>
|
||||||
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
<bool key="IBUIUserInteractionEnabled">NO</bool>
|
||||||
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
|
||||||
<string key="IBUIText">Nimrod Crossplatform Calculator</string>
|
<string key="IBUIText">Nim Crossplatform Calculator</string>
|
||||||
<object class="NSColor" key="IBUITextColor" id="128895179">
|
<object class="NSColor" key="IBUITextColor" id="128895179">
|
||||||
<int key="NSColorSpace">1</int>
|
<int key="NSColorSpace">1</int>
|
||||||
<bytes key="NSRGB">MCAwIDAAA</bytes>
|
<bytes key="NSRGB">MCAwIDAAA</bytes>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ function myAdd(x, y: longint): longint; cdecl; external;
|
||||||
|
|
||||||
procedure TForm1.FormCreate(Sender: TObject);
|
procedure TForm1.FormCreate(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
// we initialize the Nimrod data structures here:
|
// we initialize the Nim data structures here:
|
||||||
NimMain();
|
NimMain();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Nimrod configuration file.
|
# Nim configuration file.
|
||||||
# The file is used only to add the path of the backend to the compiler options.
|
# The file is used only to add the path of the backend to the compiler options.
|
||||||
|
|
||||||
path="../nim_backend"
|
path="../nim_backend"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ The cross platform calculator illustrates how to use Nim to create a backend
|
||||||
called by different native user interfaces.
|
called by different native user interfaces.
|
||||||
|
|
||||||
Since the purpose of the example is to show how the cross platform code
|
Since the purpose of the example is to show how the cross platform code
|
||||||
interacts with Nimrod the actual backend code is just a simple addition proc.
|
interacts with Nim the actual backend code is just a simple addition proc.
|
||||||
By keeping your program logic in Nim you can easily reuse it in different
|
By keeping your program logic in Nim you can easily reuse it in different
|
||||||
platforms.
|
platforms.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@
|
||||||
|
|
||||||
import db_sqlite, parseutils, strutils, times
|
import db_sqlite, parseutils, strutils, times
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TTodo* = object
|
Todo* = object
|
||||||
## A todo object holding the information serialized to the database.
|
## A todo object holding the information serialized to the database.
|
||||||
id: int64 ## Unique identifier of the object in the
|
id: int64 ## Unique identifier of the object in the
|
||||||
## database, use the getId() accessor to read it.
|
## database, use the getId() accessor to read it.
|
||||||
|
|
@ -17,7 +16,7 @@ type
|
||||||
## outside of this module, use the
|
## outside of this module, use the
|
||||||
## getModificationDate accessor.
|
## getModificationDate accessor.
|
||||||
|
|
||||||
TPagedParams* = object
|
PagedParams* = object
|
||||||
## Contains parameters for a query, initialize default values with
|
## Contains parameters for a query, initialize default values with
|
||||||
## initDefaults().
|
## initDefaults().
|
||||||
pageSize*: int64 ## Lines per returned query page, -1 for
|
pageSize*: int64 ## Lines per returned query page, -1 for
|
||||||
|
|
@ -27,11 +26,10 @@ type
|
||||||
showUnchecked*: bool ## Get unchecked objects.
|
showUnchecked*: bool ## Get unchecked objects.
|
||||||
showChecked*: bool ## Get checked objects.
|
showChecked*: bool ## Get checked objects.
|
||||||
|
|
||||||
|
|
||||||
# - General procs
|
# - General procs
|
||||||
#
|
|
||||||
proc initDefaults*(params: var TPagedParams) =
|
proc initDefaults*(params: var PagedParams) =
|
||||||
## Sets sane defaults for a TPagedParams object.
|
## Sets sane defaults for a PagedParams object.
|
||||||
##
|
##
|
||||||
## Note that you should always provide a non zero pageSize, either a specific
|
## Note that you should always provide a non zero pageSize, either a specific
|
||||||
## positive value or negative for unbounded query results.
|
## positive value or negative for unbounded query results.
|
||||||
|
|
@ -41,7 +39,6 @@ proc initDefaults*(params: var TPagedParams) =
|
||||||
params.showUnchecked = true
|
params.showUnchecked = true
|
||||||
params.showChecked = false
|
params.showChecked = false
|
||||||
|
|
||||||
|
|
||||||
proc openDatabase*(path: string): DbConn =
|
proc openDatabase*(path: string): DbConn =
|
||||||
## Creates or opens the sqlite3 database.
|
## Creates or opens the sqlite3 database.
|
||||||
##
|
##
|
||||||
|
|
@ -56,16 +53,14 @@ proc openDatabase*(path: string): DbConn =
|
||||||
desc TEXT NOT NULL,
|
desc TEXT NOT NULL,
|
||||||
modification_date INTEGER NOT NULL,
|
modification_date INTEGER NOT NULL,
|
||||||
CONSTRAINT Todos UNIQUE (id))"""
|
CONSTRAINT Todos UNIQUE (id))"""
|
||||||
|
|
||||||
db_sqlite.exec(conn, query)
|
db_sqlite.exec(conn, query)
|
||||||
result = conn
|
result = conn
|
||||||
|
|
||||||
|
# - Procs related to Todo objects
|
||||||
|
|
||||||
# - Procs related to TTodo objects
|
|
||||||
#
|
|
||||||
proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
|
proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
|
||||||
modificationDate: Time): TTodo =
|
modificationDate: Time): Todo =
|
||||||
## Returns an initialized TTodo object created from database parameters.
|
## Returns an initialized Todo object created from database parameters.
|
||||||
##
|
##
|
||||||
## The proc assumes all values are right. Note this proc is NOT exported.
|
## The proc assumes all values are right. Note this proc is NOT exported.
|
||||||
assert(id >= 0, "Identity identifiers should not be negative")
|
assert(id >= 0, "Identity identifiers should not be negative")
|
||||||
|
|
@ -75,29 +70,25 @@ proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
|
||||||
result.isDone = isDone
|
result.isDone = isDone
|
||||||
result.modificationDate = modificationDate
|
result.modificationDate = modificationDate
|
||||||
|
|
||||||
|
proc getId*(todo: Todo): int64 =
|
||||||
proc getId*(todo: TTodo): int64 =
|
|
||||||
## Accessor returning the value of the private id property.
|
## Accessor returning the value of the private id property.
|
||||||
return todo.id
|
return todo.id
|
||||||
|
|
||||||
|
proc getModificationDate*(todo: Todo): Time =
|
||||||
proc getModificationDate*(todo: TTodo): Time =
|
## Returns the last modification date of a Todo entry.
|
||||||
## Returns the last modification date of a TTodo entry.
|
|
||||||
return todo.modificationDate
|
return todo.modificationDate
|
||||||
|
|
||||||
|
proc update*(todo: var Todo; conn: DbConn): bool =
|
||||||
proc update*(todo: var TTodo; conn: DbConn): bool =
|
|
||||||
## Checks the database for the object and refreshes its variables.
|
## Checks the database for the object and refreshes its variables.
|
||||||
##
|
##
|
||||||
## Use this method if you (or another entity) have modified the database and
|
## Use this method if you (or another entity) have modified the database and
|
||||||
## want to update the object you have with whatever the database has stored.
|
## want to update the object you have with whatever the database has stored.
|
||||||
## Returns true if the update succeeded, or false if the object was not found
|
## Returns true if the update succeeded, or false if the object was not found
|
||||||
## in the database any more, in which case you should probably get rid of the
|
## in the database any more, in which case you should probably get rid of the
|
||||||
## TTodo object.
|
## Todo object.
|
||||||
assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
|
assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
|
||||||
let query = sql"""SELECT desc, priority, is_done, modification_date
|
let query = sql"""SELECT desc, priority, is_done, modification_date
|
||||||
FROM Todos WHERE id = ?"""
|
FROM Todos WHERE id = ?"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let rows = conn.getAllRows(query, $todo.id)
|
let rows = conn.getAllRows(query, $todo.id)
|
||||||
if len(rows) < 1:
|
if len(rows) < 1:
|
||||||
|
|
@ -111,8 +102,7 @@ proc update*(todo: var TTodo; conn: DbConn): bool =
|
||||||
except:
|
except:
|
||||||
echo("Something went wrong selecting for id " & $todo.id)
|
echo("Something went wrong selecting for id " & $todo.id)
|
||||||
|
|
||||||
|
proc save*(todo: var Todo; conn: DbConn): bool =
|
||||||
proc save*(todo: var TTodo; conn: DbConn): bool =
|
|
||||||
## Saves the current state of text, priority and isDone to the database.
|
## Saves the current state of text, priority and isDone to the database.
|
||||||
##
|
##
|
||||||
## Returns true if the database object was updated (in which case the
|
## Returns true if the database object was updated (in which case the
|
||||||
|
|
@ -127,15 +117,13 @@ proc save*(todo: var TTodo; conn: DbConn): bool =
|
||||||
WHERE id = ?"""
|
WHERE id = ?"""
|
||||||
rowsUpdated = conn.execAffectedRows(query, $todo.text,
|
rowsUpdated = conn.execAffectedRows(query, $todo.text,
|
||||||
$todo.priority, $todo.isDone, $int(currentDate), $todo.id)
|
$todo.priority, $todo.isDone, $int(currentDate), $todo.id)
|
||||||
|
|
||||||
if 1 == rowsUpdated:
|
if 1 == rowsUpdated:
|
||||||
todo.modificationDate = currentDate
|
todo.modificationDate = currentDate
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
|
|
||||||
# - Procs dealing directly with the database
|
# - Procs dealing directly with the database
|
||||||
#
|
|
||||||
proc addTodo*(conn: DbConn; priority: int; text: string): TTodo =
|
proc addTodo*(conn: DbConn; priority: int; text: string): Todo =
|
||||||
## Inserts a new todo into the database.
|
## Inserts a new todo into the database.
|
||||||
##
|
##
|
||||||
## Returns the generated todo object. If there is an error EDb will be raised.
|
## Returns the generated todo object. If there is an error EDb will be raised.
|
||||||
|
|
@ -145,10 +133,8 @@ proc addTodo*(conn: DbConn; priority: int; text: string): TTodo =
|
||||||
(priority, is_done, desc, modification_date)
|
(priority, is_done, desc, modification_date)
|
||||||
VALUES (?, 'false', ?, ?)"""
|
VALUES (?, 'false', ?, ?)"""
|
||||||
todoId = conn.insertId(query, priority, text, $int(currentDate))
|
todoId = conn.insertId(query, priority, text, $int(currentDate))
|
||||||
|
|
||||||
result = initFromDB(todoId, text, priority, false, currentDate)
|
result = initFromDB(todoId, text, priority, false, currentDate)
|
||||||
|
|
||||||
|
|
||||||
proc deleteTodo*(conn: DbConn; todoId: int64): int64 {.discardable.} =
|
proc deleteTodo*(conn: DbConn; todoId: int64): int64 {.discardable.} =
|
||||||
## Deletes the specified todo identifier.
|
## Deletes the specified todo identifier.
|
||||||
##
|
##
|
||||||
|
|
@ -156,7 +142,6 @@ proc deleteTodo*(conn: DbConn; todoId: int64): int64 {.discardable.} =
|
||||||
let query = sql"""DELETE FROM Todos WHERE id = ?"""
|
let query = sql"""DELETE FROM Todos WHERE id = ?"""
|
||||||
result = conn.execAffectedRows(query, $todoId)
|
result = conn.execAffectedRows(query, $todoId)
|
||||||
|
|
||||||
|
|
||||||
proc getNumEntries*(conn: DbConn): int =
|
proc getNumEntries*(conn: DbConn): int =
|
||||||
## Returns the number of entries in the Todos table.
|
## Returns the number of entries in the Todos table.
|
||||||
##
|
##
|
||||||
|
|
@ -170,38 +155,30 @@ proc getNumEntries*(conn: DbConn): int =
|
||||||
echo("Something went wrong retrieving number of Todos entries")
|
echo("Something went wrong retrieving number of Todos entries")
|
||||||
result = -1
|
result = -1
|
||||||
|
|
||||||
|
proc getPagedTodos*(conn: DbConn; params: PagedParams; page = 0'i64): seq[Todo] =
|
||||||
proc getPagedTodos*(conn: DbConn; params: TPagedParams;
|
|
||||||
page = 0'i64): seq[TTodo] =
|
|
||||||
## Returns the todo entries for a specific page.
|
## Returns the todo entries for a specific page.
|
||||||
##
|
##
|
||||||
## Pages are calculated based on the params.pageSize parameter, which can be
|
## Pages are calculated based on the params.pageSize parameter, which can be
|
||||||
## set to a negative value to specify no limit at all. The query will be
|
## set to a negative value to specify no limit at all. The query will be
|
||||||
## affected by the TPagedParams, which should have sane values (call
|
## affected by the PagedParams, which should have sane values (call
|
||||||
## initDefaults).
|
## initDefaults).
|
||||||
assert(page >= 0, "You should request a page zero or bigger than zero")
|
assert(page >= 0, "You should request a page zero or bigger than zero")
|
||||||
result = @[]
|
result = @[]
|
||||||
|
|
||||||
# Well, if you don't want to see anything, there's no point in asking the db.
|
# Well, if you don't want to see anything, there's no point in asking the db.
|
||||||
if not params.showUnchecked and not params.showChecked: return
|
if not params.showUnchecked and not params.showChecked: return
|
||||||
|
|
||||||
let
|
let
|
||||||
order_by = [
|
order_by = [
|
||||||
if params.priorityAscending: "ASC" else: "DESC",
|
if params.priorityAscending: "ASC" else: "DESC",
|
||||||
if params.dateAscending: "ASC" else: "DESC"]
|
if params.dateAscending: "ASC" else: "DESC"]
|
||||||
|
|
||||||
query = sql("""SELECT id, desc, priority, is_done, modification_date
|
query = sql("""SELECT id, desc, priority, is_done, modification_date
|
||||||
FROM Todos
|
FROM Todos
|
||||||
WHERE is_done = ? OR is_done = ?
|
WHERE is_done = ? OR is_done = ?
|
||||||
ORDER BY priority $1, modification_date $2, id DESC
|
ORDER BY priority $1, modification_date $2, id DESC
|
||||||
LIMIT ? * ?,?""" % order_by)
|
LIMIT ? * ?,?""" % order_by)
|
||||||
|
|
||||||
args = @[$params.showChecked, $(not params.showUnchecked),
|
args = @[$params.showChecked, $(not params.showUnchecked),
|
||||||
$params.pageSize, $page, $params.pageSize]
|
$params.pageSize, $page, $params.pageSize]
|
||||||
|
|
||||||
#echo("Query " & string(query))
|
#echo("Query " & string(query))
|
||||||
#echo("args: " & args.join(", "))
|
#echo("args: " & args.join(", "))
|
||||||
|
|
||||||
var newId: BiggestInt
|
var newId: BiggestInt
|
||||||
for row in conn.fastRows(query, args):
|
for row in conn.fastRows(query, args):
|
||||||
let numChars = row[0].parseBiggestInt(newId)
|
let numChars = row[0].parseBiggestInt(newId)
|
||||||
|
|
@ -209,10 +186,9 @@ proc getPagedTodos*(conn: DbConn; params: TPagedParams;
|
||||||
result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
|
result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
|
||||||
row[3].parseBool, Time(row[4].parseInt)))
|
row[3].parseBool, Time(row[4].parseInt)))
|
||||||
|
|
||||||
|
proc getTodo*(conn: DbConn; todoId: int64): ref Todo =
|
||||||
proc getTodo*(conn: DbConn; todoId: int64): ref TTodo =
|
## Returns a reference to a Todo or nil if the todo could not be found.
|
||||||
## Returns a reference to a TTodo or nil if the todo could not be found.
|
var tempTodo: Todo
|
||||||
var tempTodo: TTodo
|
|
||||||
tempTodo.id = todoId
|
tempTodo.id = todoId
|
||||||
if tempTodo.update(conn):
|
if tempTodo.update(conn):
|
||||||
new(result)
|
new(result)
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
import backend, db_sqlite, strutils, times
|
import backend, db_sqlite, strutils, times
|
||||||
|
|
||||||
|
proc showPagedResults(conn: DbConn; params: PagedParams) =
|
||||||
proc showPagedResults(conn: DbConn; params: TPagedParams) =
|
|
||||||
## Shows the contents of the database in pages of specified size.
|
## Shows the contents of the database in pages of specified size.
|
||||||
##
|
##
|
||||||
## Hmm... I guess this is more of a debug proc which should be moved outside,
|
## Hmm... I guess this is more of a debug proc which should be moved outside,
|
||||||
|
|
@ -11,7 +10,6 @@ proc showPagedResults(conn: DbConn; params: TPagedParams) =
|
||||||
var
|
var
|
||||||
page = 0'i64
|
page = 0'i64
|
||||||
rows = conn.getPagedTodos(params)
|
rows = conn.getPagedTodos(params)
|
||||||
|
|
||||||
while rows.len > 0:
|
while rows.len > 0:
|
||||||
echo("page " & $page)
|
echo("page " & $page)
|
||||||
for row in rows:
|
for row in rows:
|
||||||
|
|
@ -25,7 +23,6 @@ proc showPagedResults(conn: DbConn; params: TPagedParams) =
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
proc dumTest() =
|
proc dumTest() =
|
||||||
let conn = openDatabase("todo.sqlite3")
|
let conn = openDatabase("todo.sqlite3")
|
||||||
try:
|
try:
|
||||||
|
|
@ -35,10 +32,8 @@ proc dumTest() =
|
||||||
# Fill some dummy rows if there are not many entries yet.
|
# Fill some dummy rows if there are not many entries yet.
|
||||||
discard conn.addTodo(3, "Filler1")
|
discard conn.addTodo(3, "Filler1")
|
||||||
discard conn.addTodo(4, "Filler2")
|
discard conn.addTodo(4, "Filler2")
|
||||||
|
|
||||||
var todo = conn.addTodo(2, "Testing")
|
var todo = conn.addTodo(2, "Testing")
|
||||||
echo("New todo added with id " & $todo.getId)
|
echo("New todo added with id " & $todo.getId)
|
||||||
|
|
||||||
# Try changing it and updating the database.
|
# Try changing it and updating the database.
|
||||||
var clonedTodo = conn.getTodo(todo.getId)[]
|
var clonedTodo = conn.getTodo(todo.getId)[]
|
||||||
assert(clonedTodo.text == todo.text, "Should be equal")
|
assert(clonedTodo.text == todo.text, "Should be equal")
|
||||||
|
|
@ -49,13 +44,11 @@ proc dumTest() =
|
||||||
echo("Updated priority $1, done $2" % [$todo.priority, $todo.isDone])
|
echo("Updated priority $1, done $2" % [$todo.priority, $todo.isDone])
|
||||||
else:
|
else:
|
||||||
assert(false, "Uh oh, I wasn't expecting that!")
|
assert(false, "Uh oh, I wasn't expecting that!")
|
||||||
|
|
||||||
# Verify our cloned copy is different but can be updated.
|
# Verify our cloned copy is different but can be updated.
|
||||||
assert(clonedTodo.text != todo.text, "Should be different")
|
assert(clonedTodo.text != todo.text, "Should be different")
|
||||||
discard clonedTodo.update(conn)
|
discard clonedTodo.update(conn)
|
||||||
assert(clonedTodo.text == todo.text, "Should be equal")
|
assert(clonedTodo.text == todo.text, "Should be equal")
|
||||||
|
var params: PagedParams
|
||||||
var params: TPagedParams
|
|
||||||
params.initDefaults
|
params.initDefaults
|
||||||
conn.showPagedResults(params)
|
conn.showPagedResults(params)
|
||||||
conn.deleteTodo(todo.getId)
|
conn.deleteTodo(todo.getId)
|
||||||
|
|
@ -66,7 +59,6 @@ proc dumTest() =
|
||||||
echo("Later priority $1, done $2" % [$todo.priority, $todo.isDone])
|
echo("Later priority $1, done $2" % [$todo.priority, $todo.isDone])
|
||||||
else:
|
else:
|
||||||
echo("Can't update object $1 from db!" % $todo.getId)
|
echo("Can't update object $1 from db!" % $todo.getId)
|
||||||
|
|
||||||
# Try to list content in a different way.
|
# Try to list content in a different way.
|
||||||
params.pageSize = 5
|
params.pageSize = 5
|
||||||
params.priorityAscending = true
|
params.priorityAscending = true
|
||||||
|
|
@ -77,7 +69,6 @@ proc dumTest() =
|
||||||
conn.close
|
conn.close
|
||||||
echo("Database closed")
|
echo("Database closed")
|
||||||
|
|
||||||
|
|
||||||
# Code that will be run only on the commandline.
|
# Code that will be run only on the commandline.
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
dumTest()
|
dumTest()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Nimrod configuration file.
|
# Nim configuration file.
|
||||||
# The file is used only to add the path of the backend to the compiler options.
|
# The file is used only to add the path of the backend to the compiler options.
|
||||||
|
|
||||||
path="../nim_backend"
|
path="../nim_backend"
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ Commands:
|
||||||
-h, --help shows this help
|
-h, --help shows this help
|
||||||
|
|
||||||
List options (optional):
|
List options (optional):
|
||||||
-p=+|- Sorts list by ascending|desdencing priority. Default:desdencing.
|
-p=+|- Sorts list by ascending|descending priority. Default:descending.
|
||||||
-m=+|- Sorts list by ascending|desdencing date. Default:desdencing.
|
-m=+|- Sorts list by ascending|descending date. Default:descending.
|
||||||
-t Show checked entries. By default they are not shown.
|
-t Show checked entries. By default they are not shown.
|
||||||
-z Hide unchecked entries. By default they are shown.
|
-z Hide unchecked entries. By default they are shown.
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ Examples:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
TCommand = enum # The possible types of commands
|
Command = enum # The possible types of commands
|
||||||
cmdAdd # The user wants to add a new todo entry.
|
cmdAdd # The user wants to add a new todo entry.
|
||||||
cmdCheck # User wants to check a todo entry.
|
cmdCheck # User wants to check a todo entry.
|
||||||
cmdUncheck # User wants to uncheck a todo entry.
|
cmdUncheck # User wants to uncheck a todo entry.
|
||||||
|
|
@ -42,30 +42,27 @@ type
|
||||||
cmdGenerate # Add random rows to the database, for testing.
|
cmdGenerate # Add random rows to the database, for testing.
|
||||||
cmdList # User wants to list contents.
|
cmdList # User wants to list contents.
|
||||||
|
|
||||||
TParamConfig = object
|
ParamConfig = object
|
||||||
# Structure containing the parsed options from the commandline.
|
# Structure containing the parsed options from the commandline.
|
||||||
command: TCommand # Store the type of operation
|
command: Command # Store the type of operation
|
||||||
addPriority: int # Only valid with cmdAdd, stores priority.
|
addPriority: int # Only valid with cmdAdd, stores priority.
|
||||||
addText: seq[string] # Only valid with cmdAdd, stores todo text.
|
addText: seq[string] # Only valid with cmdAdd, stores todo text.
|
||||||
todoId: int64 # The todo id for operations like check or delete.
|
todoId: int64 # The todo id for operations like check or delete.
|
||||||
listParams: TPagedParams # Uses the backend structure directly for params.
|
listParams: PagedParams # Uses the backend structure directly for params.
|
||||||
|
|
||||||
|
proc initDefaults(params: var ParamConfig) =
|
||||||
proc initDefaults(params: var TParamConfig) =
|
|
||||||
## Initialises defaults value in the structure.
|
## Initialises defaults value in the structure.
|
||||||
##
|
##
|
||||||
## Most importantly we want to have an empty list for addText.
|
## Most importantly we want to have an empty list for addText.
|
||||||
params.listParams.initDefaults
|
params.listParams.initDefaults
|
||||||
params.addText = @[]
|
params.addText = @[]
|
||||||
|
|
||||||
|
|
||||||
proc abort(message: string, value: int) =
|
proc abort(message: string, value: int) =
|
||||||
# Simple wrapper to abort also displaying the help to the user.
|
# Simple wrapper to abort also displaying the help to the user.
|
||||||
stdout.write(USAGE)
|
stdout.write(USAGE)
|
||||||
quit(message, value)
|
quit(message, value)
|
||||||
|
|
||||||
|
template parseTodoIdAndSetCommand(newCommand: Command): untyped =
|
||||||
template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
|
|
||||||
## Helper to parse a big todo identifier into todoId and set command.
|
## Helper to parse a big todo identifier into todoId and set command.
|
||||||
try:
|
try:
|
||||||
let numChars = val.parseBiggestInt(newId)
|
let numChars = val.parseBiggestInt(newId)
|
||||||
|
|
@ -75,8 +72,7 @@ template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
|
||||||
except OverflowError:
|
except OverflowError:
|
||||||
raise newException(ValueError, "Value $1 too big" % val)
|
raise newException(ValueError, "Value $1 too big" % val)
|
||||||
|
|
||||||
|
template verifySingleCommand(actions: typed): typed =
|
||||||
template verifySingleCommand(actions: stmt): stmt =
|
|
||||||
## Helper to make sure only one command has been specified so far.
|
## Helper to make sure only one command has been specified so far.
|
||||||
if specifiedCommand:
|
if specifiedCommand:
|
||||||
abort("Only one command can be specified at a time! (extra:$1)" % [key], 2)
|
abort("Only one command can be specified at a time! (extra:$1)" % [key], 2)
|
||||||
|
|
@ -84,7 +80,6 @@ template verifySingleCommand(actions: stmt): stmt =
|
||||||
actions
|
actions
|
||||||
specifiedCommand = true
|
specifiedCommand = true
|
||||||
|
|
||||||
|
|
||||||
proc parsePlusMinus(val: string, debugText: string): bool =
|
proc parsePlusMinus(val: string, debugText: string): bool =
|
||||||
## Helper to process a plus or minus character from the commandline.
|
## Helper to process a plus or minus character from the commandline.
|
||||||
##
|
##
|
||||||
|
|
@ -100,11 +95,10 @@ proc parsePlusMinus(val: string, debugText: string): bool =
|
||||||
else:
|
else:
|
||||||
abort("$1 parameter should be + or - but was '$2'." % [debugText, val], 4)
|
abort("$1 parameter should be + or - but was '$2'." % [debugText, val], 4)
|
||||||
|
|
||||||
|
proc parseCmdLine(): ParamConfig =
|
||||||
proc parseCmdLine(): TParamConfig =
|
|
||||||
## Parses the commandline.
|
## Parses the commandline.
|
||||||
##
|
##
|
||||||
## Returns a TParamConfig structure filled with the proper values or directly
|
## Returns a ParamConfig structure filled with the proper values or directly
|
||||||
## calls quit() with the appropriate error message.
|
## calls quit() with the appropriate error message.
|
||||||
var
|
var
|
||||||
specifiedCommand = false
|
specifiedCommand = false
|
||||||
|
|
@ -112,15 +106,12 @@ proc parseCmdLine(): TParamConfig =
|
||||||
p = initOptParser()
|
p = initOptParser()
|
||||||
key, val: TaintedString
|
key, val: TaintedString
|
||||||
newId: BiggestInt
|
newId: BiggestInt
|
||||||
|
|
||||||
result.initDefaults
|
result.initDefaults
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while true:
|
while true:
|
||||||
next(p)
|
next(p)
|
||||||
key = p.key
|
key = p.key
|
||||||
val = p.val
|
val = p.val
|
||||||
|
|
||||||
case p.kind
|
case p.kind
|
||||||
of cmdArgument:
|
of cmdArgument:
|
||||||
if specifiedCommand and cmdAdd == result.command:
|
if specifiedCommand and cmdAdd == result.command:
|
||||||
|
|
@ -180,17 +171,13 @@ proc parseCmdLine(): TParamConfig =
|
||||||
break
|
break
|
||||||
except ValueError:
|
except ValueError:
|
||||||
abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
|
abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
|
||||||
|
|
||||||
if not specifiedCommand:
|
if not specifiedCommand:
|
||||||
abort("Didn't specify any command.", 8)
|
abort("Didn't specify any command.", 8)
|
||||||
|
|
||||||
if cmdAdd == result.command and result.addText.len < 1:
|
if cmdAdd == result.command and result.addText.len < 1:
|
||||||
abort("Used the add command, but provided no text/description.", 9)
|
abort("Used the add command, but provided no text/description.", 9)
|
||||||
|
|
||||||
if usesListParams and cmdList != result.command:
|
if usesListParams and cmdList != result.command:
|
||||||
abort("Used list options, but didn't specify the list command.", 10)
|
abort("Used list options, but didn't specify the list command.", 10)
|
||||||
|
|
||||||
|
|
||||||
proc generateDatabaseRows(conn: DbConn) =
|
proc generateDatabaseRows(conn: DbConn) =
|
||||||
## Adds some rows to the database ignoring errors.
|
## Adds some rows to the database ignoring errors.
|
||||||
discard conn.addTodo(1, "Watch another random youtube video")
|
discard conn.addTodo(1, "Watch another random youtube video")
|
||||||
|
|
@ -208,19 +195,16 @@ proc generateDatabaseRows(conn: DbConn) =
|
||||||
discard conn.addTodo(6, "Learn a functional programming language")
|
discard conn.addTodo(6, "Learn a functional programming language")
|
||||||
echo("Generated some entries, they were added to your database.")
|
echo("Generated some entries, they were added to your database.")
|
||||||
|
|
||||||
|
proc listDatabaseContents(conn: DbConn; listParams: PagedParams) =
|
||||||
proc listDatabaseContents(conn: DbConn; listParams: TPagedParams) =
|
|
||||||
## Dumps the database contents formatted to the standard output.
|
## Dumps the database contents formatted to the standard output.
|
||||||
##
|
##
|
||||||
## Pass the list/filter parameters parsed from the commandline.
|
## Pass the list/filter parameters parsed from the commandline.
|
||||||
var params = listParams
|
var params = listParams
|
||||||
params.pageSize = -1
|
params.pageSize = -1
|
||||||
|
|
||||||
let todos = conn.getPagedTodos(params)
|
let todos = conn.getPagedTodos(params)
|
||||||
if todos.len < 1:
|
if todos.len < 1:
|
||||||
echo("Database empty")
|
echo("Database empty")
|
||||||
return
|
return
|
||||||
|
|
||||||
echo("Todo id, is done, priority, last modification date, text:")
|
echo("Todo id, is done, priority, last modification date, text:")
|
||||||
# First detect how long should be our columns for formatting.
|
# First detect how long should be our columns for formatting.
|
||||||
var cols: array[0..2, int]
|
var cols: array[0..2, int]
|
||||||
|
|
@ -228,7 +212,6 @@ proc listDatabaseContents(conn: DbConn; listParams: TPagedParams) =
|
||||||
cols[0] = max(cols[0], ($todo.getId).len)
|
cols[0] = max(cols[0], ($todo.getId).len)
|
||||||
cols[1] = max(cols[1], ($todo.priority).len)
|
cols[1] = max(cols[1], ($todo.priority).len)
|
||||||
cols[2] = max(cols[2], ($todo.getModificationDate).len)
|
cols[2] = max(cols[2], ($todo.getModificationDate).len)
|
||||||
|
|
||||||
# Now dump all the rows using the calculated alignment sizes.
|
# Now dump all the rows using the calculated alignment sizes.
|
||||||
for todo in todos:
|
for todo in todos:
|
||||||
echo("$1 $2 $3, $4, $5" % [
|
echo("$1 $2 $3, $4, $5" % [
|
||||||
|
|
@ -238,7 +221,6 @@ proc listDatabaseContents(conn: DbConn; listParams: TPagedParams) =
|
||||||
($todo.getModificationDate).align(cols[2]),
|
($todo.getModificationDate).align(cols[2]),
|
||||||
todo.text])
|
todo.text])
|
||||||
|
|
||||||
|
|
||||||
proc deleteOneTodo(conn: DbConn; todoId: int64) =
|
proc deleteOneTodo(conn: DbConn; todoId: int64) =
|
||||||
## Deletes a single todo entry from the database.
|
## Deletes a single todo entry from the database.
|
||||||
let numDeleted = conn.deleteTodo(todoId)
|
let numDeleted = conn.deleteTodo(todoId)
|
||||||
|
|
@ -247,7 +229,6 @@ proc deleteOneTodo(conn: DbConn; todoId: int64) =
|
||||||
else:
|
else:
|
||||||
quit("Couldn't delete todo id " & $todoId, 11)
|
quit("Couldn't delete todo id " & $todoId, 11)
|
||||||
|
|
||||||
|
|
||||||
proc deleteAllTodos(conn: DbConn) =
|
proc deleteAllTodos(conn: DbConn) =
|
||||||
## Deletes all the contents from the database.
|
## Deletes all the contents from the database.
|
||||||
##
|
##
|
||||||
|
|
@ -256,43 +237,35 @@ proc deleteAllTodos(conn: DbConn) =
|
||||||
## ourselfves to the API exported by backend.
|
## ourselfves to the API exported by backend.
|
||||||
var
|
var
|
||||||
counter: int64
|
counter: int64
|
||||||
params: TPagedParams
|
params: PagedParams
|
||||||
|
|
||||||
params.initDefaults
|
params.initDefaults
|
||||||
params.pageSize = -1
|
params.pageSize = -1
|
||||||
params.showUnchecked = true
|
params.showUnchecked = true
|
||||||
params.showChecked = true
|
params.showChecked = true
|
||||||
|
|
||||||
let todos = conn.getPagedTodos(params)
|
let todos = conn.getPagedTodos(params)
|
||||||
for todo in todos:
|
for todo in todos:
|
||||||
if conn.deleteTodo(todo.getId) > 0:
|
if conn.deleteTodo(todo.getId) > 0:
|
||||||
counter += 1
|
counter += 1
|
||||||
else:
|
else:
|
||||||
quit("Couldn't delete todo id " & $todo.getId, 12)
|
quit("Couldn't delete todo id " & $todo.getId, 12)
|
||||||
|
|
||||||
echo("Deleted $1 todo entries from database." % $counter)
|
echo("Deleted $1 todo entries from database." % $counter)
|
||||||
|
|
||||||
|
|
||||||
proc setTodoCheck(conn: DbConn; todoId: int64; value: bool) =
|
proc setTodoCheck(conn: DbConn; todoId: int64; value: bool) =
|
||||||
## Changes the check state of a todo entry to the specified value.
|
## Changes the check state of a todo entry to the specified value.
|
||||||
let
|
let
|
||||||
newState = if value: "checked" else: "unchecked"
|
newState = if value: "checked" else: "unchecked"
|
||||||
todo = conn.getTodo(todoId)
|
todo = conn.getTodo(todoId)
|
||||||
|
|
||||||
if todo == nil:
|
if todo == nil:
|
||||||
quit("Can't modify todo id $1, its not in the database." % $todoId, 13)
|
quit("Can't modify todo id $1, its not in the database." % $todoId, 13)
|
||||||
|
|
||||||
if todo[].isDone == value:
|
if todo[].isDone == value:
|
||||||
echo("Todo id $1 was already set to $2." % [$todoId, newState])
|
echo("Todo id $1 was already set to $2." % [$todoId, newState])
|
||||||
return
|
return
|
||||||
|
|
||||||
todo[].isDone = value
|
todo[].isDone = value
|
||||||
if todo[].save(conn):
|
if todo[].save(conn):
|
||||||
echo("Todo id $1 set to $2." % [$todoId, newState])
|
echo("Todo id $1 set to $2." % [$todoId, newState])
|
||||||
else:
|
else:
|
||||||
quit("Error updating todo id $1 to $2." % [$todoId, newState])
|
quit("Error updating todo id $1 to $2." % [$todoId, newState])
|
||||||
|
|
||||||
|
|
||||||
proc addTodo(conn: DbConn; priority: int; tokens: seq[string]) =
|
proc addTodo(conn: DbConn; priority: int; tokens: seq[string]) =
|
||||||
## Adds to the database a todo with the specified priority.
|
## Adds to the database a todo with the specified priority.
|
||||||
##
|
##
|
||||||
|
|
@ -302,17 +275,14 @@ proc addTodo(conn: DbConn; priority: int; tokens: seq[string]) =
|
||||||
echo("Created todo entry with id:$1 for priority $2 and text '$3'." % [
|
echo("Created todo entry with id:$1 for priority $2 and text '$3'." % [
|
||||||
$todo.getId, $todo.priority, todo.text])
|
$todo.getId, $todo.priority, todo.text])
|
||||||
|
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
## Main entry point.
|
## Main entry point.
|
||||||
let
|
let
|
||||||
opt = parseCmdLine()
|
opt = parseCmdLine()
|
||||||
dbPath = getConfigDir() / "nimtodo.sqlite3"
|
dbPath = getConfigDir() / "nimtodo.sqlite3"
|
||||||
|
|
||||||
if not dbPath.existsFile:
|
if not dbPath.existsFile:
|
||||||
createDir(getConfigDir())
|
createDir(getConfigDir())
|
||||||
echo("No database found at $1, it will be created for you." % dbPath)
|
echo("No database found at $1, it will be created for you." % dbPath)
|
||||||
|
|
||||||
let conn = openDatabase(dbPath)
|
let conn = openDatabase(dbPath)
|
||||||
try:
|
try:
|
||||||
case opt.command
|
case opt.command
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,6 @@ generation switch can be used to fill the database with some basic todo entries
|
||||||
you can play with.
|
you can play with.
|
||||||
|
|
||||||
Compilation is fairly easy despite having the source split in different
|
Compilation is fairly easy despite having the source split in different
|
||||||
directories. Thanks to the Nim.cfg file, which adds the ../Nim_backend
|
directories. Thanks to the nim.cfg file, which adds the ../Nim_backend
|
||||||
directory as a search path, you can compile and run the example just fine from
|
directory as a search path, you can compile and run the example just fine from
|
||||||
the command line with 'nim c -r nimtodo.nim'.
|
the command line with 'nim c -r nimtodo.nim'.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
The cross platform todo illustrates how to use Nim to create a backend
|
This cross platform todo illustrates how to use Nim to create a backend
|
||||||
called by different native user interfaces.
|
called by different native user interfaces.
|
||||||
|
|
||||||
This example builds on the knowledge learned from the cross_calculator example.
|
This example builds on the knowledge learned from the cross_calculator example.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import re
|
||||||
|
|
||||||
for x in lines("myfile.txt"):
|
for x in lines("myfile.txt"):
|
||||||
if x =~ re"(\w+)=(.*)":
|
if x =~ re"(\w+)=(.*)":
|
||||||
echo "Key: ", matches[0],
|
echo "Key: ", matches[0], " Value: ", matches[1]
|
||||||
" Value: ", matches[1]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
In this directory you will find several examples for how to use the Nimrod
|
In this directory you will find several examples for how to use the Nim
|
||||||
library.
|
library.
|
||||||
|
|
||||||
Copyright (c) 2004-2012 Andreas Rumpf.
|
Copyright (c) 2004-2012 Andreas Rumpf.
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
|
|
||||||
import strutils
|
import strutils
|
||||||
|
|
||||||
template html(name: expr, matter: stmt) {.immediate.} =
|
template html(name, matter: untyped) =
|
||||||
proc name(): string =
|
proc name(): string =
|
||||||
result = "<html>"
|
result = "<html>"
|
||||||
matter
|
matter
|
||||||
result.add("</html>")
|
result.add("</html>")
|
||||||
|
|
||||||
template nestedTag(tag: expr) {.immediate.} =
|
template nestedTag(tag: untyped) =
|
||||||
template tag(matter: stmt) {.immediate.} =
|
template tag(matter: typed) =
|
||||||
result.add("<" & astToStr(tag) & ">")
|
result.add("<" & astToStr(tag) & ">")
|
||||||
matter
|
matter
|
||||||
result.add("</" & astToStr(tag) & ">")
|
result.add("</" & astToStr(tag) & ">")
|
||||||
|
|
||||||
template simpleTag(tag: expr) {.immediate.} =
|
template simpleTag(tag: untyped) =
|
||||||
template tag(matter: expr) {.immediate.} =
|
template tag(matter: untyped) =
|
||||||
result.add("<$1>$2</$1>" % [astToStr(tag), matter])
|
result.add("<$1>$2</$1>" % [astToStr(tag), matter])
|
||||||
|
|
||||||
nestedTag body
|
nestedTag body
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import macros
|
||||||
proc invalidFormatString() =
|
proc invalidFormatString() =
|
||||||
echo "invalidFormatString"
|
echo "invalidFormatString"
|
||||||
|
|
||||||
template formatImpl(handleChar: expr) =
|
template formatImpl(handleChar: untyped) =
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < f.len:
|
while i < f.len:
|
||||||
if f[i] == '$':
|
if f[i] == '$':
|
||||||
|
|
@ -24,11 +24,11 @@ template formatImpl(handleChar: expr) =
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
proc `%`*(f: string, a: openArray[string]): string =
|
proc `%`*(f: string, a: openArray[string]): string =
|
||||||
template identity(x: expr): expr = x
|
template identity(x: untyped): untyped = x
|
||||||
result = ""
|
result = ""
|
||||||
formatImpl(identity)
|
formatImpl(identity)
|
||||||
|
|
||||||
macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): expr =
|
macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped =
|
||||||
result = newNimNode(nnkBracket)
|
result = newNimNode(nnkBracket)
|
||||||
#newCall("&")
|
#newCall("&")
|
||||||
let f = f.strVal
|
let f = f.strVal
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
macro check(ex: expr): stmt =
|
macro check(ex: untyped): typed =
|
||||||
var info = ex.lineinfo
|
var info = ex.lineinfo
|
||||||
var expString = ex.toStrLit
|
var expString = ex.toStrLit
|
||||||
result = quote do:
|
result = quote do:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
|
|
||||||
template htmlTag(tag: expr) {.immediate.} =
|
template htmlTag(tag: untyped) =
|
||||||
proc tag(): string = "<" & astToStr(tag) & ">"
|
proc tag(): string = "<" & astToStr(tag) & ">"
|
||||||
|
|
||||||
htmlTag(br)
|
htmlTag(br)
|
||||||
htmlTag(html)
|
htmlTag(html)
|
||||||
|
|
||||||
echo br()
|
echo br()
|
||||||
|
echo html()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue