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

View file

@ -38,12 +38,12 @@ namespace json
{
enum jtype
{
j_value,
j_object,
j_array,
j_string,
j_number,
j_literal
j_value, // 0
j_object, // 1
j_array, // 2
j_string, // 3
j_number, // 4
j_literal // 5
};
class value
@ -56,7 +56,7 @@ namespace json
virtual std::string dump ();
};
class string : public value, public std::string
class string : public value
{
public:
string () {}
@ -65,9 +65,12 @@ namespace json
static string* parse (Nibbler&);
jtype type ();
std::string dump ();
public:
std::string _data;
};
class number : public value, public std::string
class number : public value
{
public:
number () : _dvalue (0.0) {}
@ -77,6 +80,7 @@ namespace json
std::string dump ();
operator double () const;
public:
double _dvalue;
};
@ -89,11 +93,12 @@ namespace json
jtype type ();
std::string dump ();
public:
enum literal_value {none, nullvalue, falsevalue, truevalue};
literal_value _lvalue;
};
class array : public value, public std::vector <value*>
class array : public value
{
public:
array () {}
@ -101,9 +106,12 @@ namespace json
static array* parse (Nibbler&);
jtype type ();
std::string dump ();
public:
std::vector <value*> _data;
};
class object : public value, public std::map <std::string, value*>
class object : public value
{
public:
object () {}
@ -112,6 +120,9 @@ namespace json
static bool parse_pair (Nibbler&, std::string&, value*&);
jtype type ();
std::string dump ();
public:
std::map <std::string, value*> _data;
};
// Parser entry point.
@ -122,9 +133,6 @@ namespace json
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::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)
{
if (s == Task::pending) return "pending"; // TODO i18n
else if (s == Task::completed) return "completed"; // TODO i18n
else if (s == Task::deleted) return "deleted"; // TODO i18n
else if (s == Task::recurring) return "recurring"; // TODO i18n
else if (s == Task::waiting) return "waiting"; // TODO i18n
if (s == Task::pending) return "pending";
else if (s == Task::completed) return "completed";
else if (s == Task::deleted) return "deleted";
else if (s == Task::recurring) return "recurring";
else if (s == Task::waiting) return "waiting";
return "pending";
}

View file

@ -32,6 +32,7 @@
#include <JSON.h>
#include <text.h>
#include <util.h>
#include <i18n.h>
#include <main.h>
#include <CmdImport.h>
@ -42,7 +43,7 @@ CmdImport::CmdImport ()
{
_keyword = "import";
_usage = "task import <file> [<file> ...]";
_description = "Imports JSON files.";
_description = STRING_CMD_IMPORT_USAGE;
_read_only = false;
_displays_id = false;
}
@ -94,36 +95,100 @@ int CmdImport::execute (std::string& output)
// Parse the whole thing.
json::value* root = json::parse (object);
std::cout << root->dump ()
<< "\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)
if (root->type () == json::j_object)
{
json::object* root_obj = (json::object*)root;
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;
root = NULL;
}
}
context.tdb2.commit ();
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_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_IMPORT_USAGE "Imports JSON files."
// Config
#define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake."