Command - import

- Implemented the import command, which only suports JSON.  It is
  the basis for all other import formats, which will be implemented
  as external scripts.
This commit is contained in:
Paul Beckingham 2011-08-07 02:10:50 -04:00
parent e8a49b3e8e
commit cdda791c84
5 changed files with 133 additions and 65 deletions

View file

@ -36,11 +36,11 @@
json::value* json::value::parse (Nibbler& nibbler) json::value* json::value::parse (Nibbler& nibbler)
{ {
json::value* v; json::value* v;
if ((v = json::object::parse (nibbler)) || if ((v = json::object::parse (nibbler)) ||
(v = json::array::parse (nibbler)) || (v = json::array::parse (nibbler)) ||
(v = json::string::parse (nibbler)) || (v = json::string::parse (nibbler)) ||
(v = json::number::parse (nibbler)) || (v = json::number::parse (nibbler)) ||
(v = json::literal::parse (nibbler))) (v = json::literal::parse (nibbler)))
return v; return v;
return NULL; return NULL;
@ -61,7 +61,7 @@ std::string json::value::dump ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
json::string::string (const std::string& other) json::string::string (const std::string& other)
{ {
*this = other; _data = other;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -71,7 +71,7 @@ json::string* json::string::parse (Nibbler& nibbler)
if (nibbler.getQuoted ('"', value, false)) if (nibbler.getQuoted ('"', value, false))
{ {
json::string* s = new json::string (); json::string* s = new json::string ();
*(std::string*)s = value; s->_data = value;
return s; return s;
} }
@ -87,7 +87,7 @@ json::jtype json::string::type ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string json::string::dump () std::string json::string::dump ()
{ {
return std::string ("\"") + (std::string) *this + "\""; return std::string ("\"") + _data + "\"";
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -165,9 +165,7 @@ std::string json::literal::dump ()
json::array::~array () json::array::~array ()
{ {
std::vector <json::value*>::iterator i; std::vector <json::value*>::iterator i;
for (i = ((std::vector <json::value*>*)this)->begin (); for (i = _data.begin (); i != _data.end (); ++i)
i != ((std::vector <json::value*>*)this)->end ();
++i)
delete *i; delete *i;
} }
@ -185,7 +183,7 @@ json::array* json::array::parse (Nibbler& nibbler)
json::value* value; json::value* value;
if ((value = json::value::parse (n))) if ((value = json::value::parse (n)))
{ {
arr->push_back (value); arr->_data.push_back (value);
value = NULL; // Not a leak. Looks like a leak. value = NULL; // Not a leak. Looks like a leak.
n.skipWS (); n.skipWS ();
while (n.skip (',')) while (n.skip (','))
@ -194,7 +192,7 @@ json::array* json::array::parse (Nibbler& nibbler)
if ((value = json::value::parse (n))) if ((value = json::value::parse (n)))
{ {
arr->push_back (value); arr->_data.push_back (value);
n.skipWS (); n.skipWS ();
} }
else else
@ -232,11 +230,11 @@ std::string json::array::dump ()
output += "["; output += "[";
std::vector <json::value*>::iterator i; std::vector <json::value*>::iterator i;
for (i = ((std::vector <json::value*>*)this)->begin (); for (i = _data.begin ();
i != ((std::vector <json::value*>*)this)->end (); i != _data.end ();
++i) ++i)
{ {
if (i != ((std::vector <json::value*>*)this)->begin ()) if (i != _data.begin ())
output += ","; output += ",";
output += (*i)->dump (); output += (*i)->dump ();
@ -250,9 +248,7 @@ std::string json::array::dump ()
json::object::~object () json::object::~object ()
{ {
std::map <std::string, json::value*>::iterator i; std::map <std::string, json::value*>::iterator i;
for (i = ((std::map <std::string, json::value*>*)this)->begin (); for (i = _data.begin (); i != _data.end (); ++i)
i != ((std::map <std::string, json::value*>*)this)->end ();
++i)
delete i->second; delete i->second;
} }
@ -271,7 +267,7 @@ json::object* json::object::parse (Nibbler& nibbler)
json::value* value; json::value* value;
if (json::object::parse_pair (n, name, value)) if (json::object::parse_pair (n, name, value))
{ {
obj->insert (std::pair <std::string, json::value*> (name, value)); obj->_data.insert (std::pair <std::string, json::value*> (name, value));
value = NULL; // Not a leak. Looks like a leak. value = NULL; // Not a leak. Looks like a leak.
n.skipWS (); n.skipWS ();
@ -281,7 +277,7 @@ json::object* json::object::parse (Nibbler& nibbler)
if (json::object::parse_pair (n, name, value)) if (json::object::parse_pair (n, name, value))
{ {
obj->insert (std::pair <std::string, json::value*> (name, value)); obj->_data.insert (std::pair <std::string, json::value*> (name, value));
n.skipWS (); n.skipWS ();
} }
else else
@ -348,11 +344,9 @@ std::string json::object::dump ()
output += "{"; output += "{";
std::map <std::string, json::value*>::iterator i; std::map <std::string, json::value*>::iterator i;
for (i = ((std::map <std::string, json::value*>*)this)->begin (); for (i = _data.begin (); i != _data.end (); ++i)
i != ((std::map <std::string, json::value*>*)this)->end ();
++i)
{ {
if (i != ((std::map <std::string, json::value*>*)this)->begin ()) if (i != _data.begin ())
output += ","; output += ",";
output += "\"" + i->first + "\":"; output += "\"" + i->first + "\":";

View file

@ -38,12 +38,12 @@ namespace json
{ {
enum jtype enum jtype
{ {
j_value, j_value, // 0
j_object, j_object, // 1
j_array, j_array, // 2
j_string, j_string, // 3
j_number, j_number, // 4
j_literal j_literal // 5
}; };
class value class value
@ -56,7 +56,7 @@ namespace json
virtual std::string dump (); virtual std::string dump ();
}; };
class string : public value, public std::string class string : public value
{ {
public: public:
string () {} string () {}
@ -65,9 +65,12 @@ namespace json
static string* parse (Nibbler&); static string* parse (Nibbler&);
jtype type (); jtype type ();
std::string dump (); std::string dump ();
public:
std::string _data;
}; };
class number : public value, public std::string class number : public value
{ {
public: public:
number () : _dvalue (0.0) {} number () : _dvalue (0.0) {}
@ -77,6 +80,7 @@ namespace json
std::string dump (); std::string dump ();
operator double () const; operator double () const;
public:
double _dvalue; double _dvalue;
}; };
@ -89,11 +93,12 @@ namespace json
jtype type (); jtype type ();
std::string dump (); std::string dump ();
public:
enum literal_value {none, nullvalue, falsevalue, truevalue}; enum literal_value {none, nullvalue, falsevalue, truevalue};
literal_value _lvalue; literal_value _lvalue;
}; };
class array : public value, public std::vector <value*> class array : public value
{ {
public: public:
array () {} array () {}
@ -101,9 +106,12 @@ namespace json
static array* parse (Nibbler&); static array* parse (Nibbler&);
jtype type (); jtype type ();
std::string dump (); std::string dump ();
public:
std::vector <value*> _data;
}; };
class object : public value, public std::map <std::string, value*> class object : public value
{ {
public: public:
object () {} object () {}
@ -112,6 +120,9 @@ namespace json
static bool parse_pair (Nibbler&, std::string&, value*&); static bool parse_pair (Nibbler&, std::string&, value*&);
jtype type (); jtype type ();
std::string dump (); std::string dump ();
public:
std::map <std::string, value*> _data;
}; };
// Parser entry point. // Parser entry point.
@ -122,9 +133,6 @@ namespace json
std::string decode (const std::string&); std::string decode (const std::string&);
} }
typedef std::vector<json::value*> json_array;
typedef std::map<std::string, json::value*> json_object;
typedef std::vector <json::value*>::iterator json_array_iter; typedef std::vector <json::value*>::iterator json_array_iter;
typedef std::map <std::string, json::value*>::iterator json_object_iter; typedef std::map <std::string, json::value*>::iterator json_object_iter;

View file

@ -121,11 +121,11 @@ Task::status Task::textToStatus (const std::string& input)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string Task::statusToText (Task::status s) std::string Task::statusToText (Task::status s)
{ {
if (s == Task::pending) return "pending"; // TODO i18n if (s == Task::pending) return "pending";
else if (s == Task::completed) return "completed"; // TODO i18n else if (s == Task::completed) return "completed";
else if (s == Task::deleted) return "deleted"; // TODO i18n else if (s == Task::deleted) return "deleted";
else if (s == Task::recurring) return "recurring"; // TODO i18n else if (s == Task::recurring) return "recurring";
else if (s == Task::waiting) return "waiting"; // TODO i18n else if (s == Task::waiting) return "waiting";
return "pending"; return "pending";
} }

View file

@ -32,6 +32,7 @@
#include <JSON.h> #include <JSON.h>
#include <text.h> #include <text.h>
#include <util.h> #include <util.h>
#include <i18n.h>
#include <main.h> #include <main.h>
#include <CmdImport.h> #include <CmdImport.h>
@ -42,7 +43,7 @@ CmdImport::CmdImport ()
{ {
_keyword = "import"; _keyword = "import";
_usage = "task import <file> [<file> ...]"; _usage = "task import <file> [<file> ...]";
_description = "Imports JSON files."; _description = STRING_CMD_IMPORT_USAGE;
_read_only = false; _read_only = false;
_displays_id = false; _displays_id = false;
} }
@ -94,36 +95,100 @@ int CmdImport::execute (std::string& output)
// Parse the whole thing. // Parse the whole thing.
json::value* root = json::parse (object); json::value* root = json::parse (object);
std::cout << root->dump () if (root->type () == json::j_object)
<< "\n";
// For each object element...
json_object_iter i;
for (i = ((json_object*)root)->begin ();
i != ((json_object*)root)->end ();
++i)
{
std::cout << "!!!\n";
}
/*
std::map <std::string, json::value*>::iterator i;
for (i = ((std::map <std::string, json::value*>*)root)->begin ();
i != ((std::map <std::string, json::value*>*)root)->end ();
++i)
{ {
json::object* root_obj = (json::object*)root;
Task task; Task task;
std::cout << "!!!\n"; task.set ("uuid", uuid ());
// TODO Navigate each object. // For each object element...
json_object_iter i;
for (i = root_obj->_data.begin ();
i != root_obj->_data.end ();
++i)
{
// If the attribute is a recognized column.
Column* col = context.columns[i->first];
if (col)
{
// Any specified id is ignored.
if (i->first == "id")
;
// Dates are converted from ISO to epoch.
else if (col->type () == "date")
{
Date d (unquoteText (i->second->dump ()));
task.set (i->first, d.toEpochString ());
}
// Other types are simply added.
else
task.set (i->first, unquoteText (i->second->dump ()));
}
// Several attributes do not have columns.
// mask
// imask
// parent
else
{
// Annotations are an array of JSON objects with 'entry' and
// 'description' values and must be converted.
if (i->first == "annotations")
{
std::vector <Att> annos;
json::array* atts = (json::array*)i->second;
json_array_iter annotations;
for (annotations = atts->_data.begin ();
annotations != atts->_data.end ();
++annotations)
{
json::object* annotation = (json::object*)*annotations;
json::string* when = (json::string*)annotation->_data["entry"];
json::string* what = (json::string*)annotation->_data["description"];
std::string name = "annotation_" + Date (when->_data).toEpochString ();
annos.push_back (Att (name, what->_data));
}
task.setAnnotations (annos);
}
// These must be imported, but are not represented by Column
// objects.
else if (i->first == "mask" ||
i->first == "imask" ||
i->first == "parent")
{
task.set (i->first, unquoteText (i->second->dump ()));
}
else
throw std::string ("Unrecognized attribute '") + i->first + "'";
}
}
task.validate ();
// TODO Verify uuid is unique, to prevent double-import.
std::cout << " "
<< task.get ("uuid")
<< " "
<< task.get ("description")
<< "\n";
context.tdb2.add (task);
} }
*/ else
throw std::string ("Not a JSON object: ") + *line;
delete root; delete root;
root = NULL;
} }
} }
context.tdb2.commit ();
return rc; return rc;
} }

View file

@ -308,6 +308,7 @@
#define STRING_CMD_DENO_NONE "The specified task has no annotations that can be deleted." #define STRING_CMD_DENO_NONE "The specified task has no annotations that can be deleted."
#define STRING_CMD_DENO_FOUND "Found annotation '{1}' and deleted it." #define STRING_CMD_DENO_FOUND "Found annotation '{1}' and deleted it."
#define STRING_CMD_DENO_NOMATCH "Did not find any matching annotation to be deleted for '{1}'." #define STRING_CMD_DENO_NOMATCH "Did not find any matching annotation to be deleted for '{1}'."
#define STRING_CMD_IMPORT_USAGE "Imports JSON files."
// Config // Config
#define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake." #define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake."