Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
nesthydrationjs
Advanced tools
Converts tabular data into a nested object/array structure based on a definition object or specially named columns.
Tabular data is considered to be an array of objects where each object represents a row and the properties of those objects are cell values with the keys representing the column names.
var table = [
{
id: '1', title: 'Tabular to Objects', required: '1',
teacher_id: '1', teacher_name: 'David',
lesson_id: '1', lesson_title: 'Definitions'
},
{
id: '1', title: 'Tabular to Objects', required: '1',
teacher_id: '1', teacher_name: 'David',
lesson_id: '2', lesson_title: 'Table Data'
},
{
id: '1', title: 'Tabular to Objects', required: '1',
teacher_id: '1', teacher_name: 'David',
lesson_id: '3', lesson_title: 'Objects'
},
{
id: '2', title: 'Column Names Define Structure', required: '0',
teacher_id: '2', teacher_name: 'Chris',
lesson_id: '4', lesson_title: 'Column Names'
},
{
id: '2', title: 'Column Names Define Structure', required: '0',
teacher_id: '2', teacher_name: 'Chris',
lesson_id: '2', lesson_title: 'Table Data'
},
{
id: '2', title: 'Column Names Define Structure', required: '0',
teacher_id: '2', teacher_name: 'Chris',
lesson_id: '3', lesson_title: 'Objects'
},
{
id: '3', title: 'Object On Bottom', required: '0',
teacher_id: '1', teacher_name: 'David',
lesson_id: '5', lesson_title: 'Non Array Input'
}
];
Above are 7 rows each with the cells data for the columns id
, title
, required
, teacher_id
, teacher_name
, lesson_id
, lesson_title
.
Mapping from the property keys of the tabular data to nested objects is done in accordance to the definition object.
var definition = [{
id: {column: 'id', type: 'NUMBER'},
title: 'title',
required: {column: 'required', type: 'BOOLEAN'},
teacher: {
id: {column: 'teacher_id', type: 'NUMBER'},
name: 'teacher_name'
},
lesson: [{
id: {column: 'lesson_id', type: 'NUMBER'},
title: 'lesson_title'
}]
}];
The definition object above maps:
id
to result[#].id
with a type caste to a numbertitle
to result[#].title
required
to result[#].required
with a type caste to a booleanteacher_id
to result[#].teacher.id
with a type caste to a numberteacher_name
to result[#].teacher.name
lesson_id
to result[#].lesson[#].id
with a type caste to a numberlesson_title
to result[#].lesson[#].title
var NestHydrationJS = require('nesthydrationjs')();
result = NestHydrationJS.nest(table, definition);
[
{id: 1, title: 'Tabular to Objects', required: true, teacher: {id: 1, name: 'David'}, lesson: [
{id: 1, title: 'Defintions'},
{id: 2, title: 'Table Data'},
{id: 3, title: 'Objects'}
]},
{id: 2, title: 'Column Names Define Structure', required: false, teacher: {id: 2, name: 'Chris'}, lesson: [
{id: 4, title: 'Column Names'},
{id: 2, title: 'Table Data'},
{id: 3, title: 'Objects'}
]},
{id: 3, title: 'Object On Bottom', required: false, teacher: {id: 1, name: 'David'}, lesson: [
{id: 5, title: 'Non Array Input'}
]}
]
It is common to want to define an SQL query and then just get back objects. NestHydrationJS was created with this in mind.
The following example gives same result as above but a column naming convention is used instead of a definition object.
Nesting is achieved by using a underscore (_
). A x to one relation is defined by a single underscore and a x to many relation is defined by preceeding properties of the many object with a 2nd underscore.
If a column alias ends in a triple underscore (___
) followed by either NUMBER
or BOOLEAN
then the values in those columns will be caste to the respective type unless the value is null. Triple underscore with ID
(___ID
) can be used to specify a column that is an id propery of that level of object. If an id is not specified the default is for the first column in that object to be the id property. The id specifier can be used in combination with a type caste, so either ___ID___NUMBER
, or ___NUMBER___ID
would be valid appends to a column name.
Note: that this means that almost always base level properties will be prefixed with a underscore, as this is actually a x to many relation from the variable returned from the nest
function.
var sql = ''
+ 'SELECT'
+ 'c.id AS _id___NUMBER,'
+ 'c.title AS _title,'
+ 'c.requried AS _required___BOOLEAN,'
+ 't.teacher AS _teacher_id___NUMBER,'
+ 't.name AS _teacher_name,'
+ 'l.title AS _lesson__title'
+ 'l.id AS _lesson__id___NUMBER___ID,'
+ 'FROM course AS c'
+ 'JOIN teacher AS t ON t.id = c.teacher_id'
+ 'JOIN course_lesson AS cl ON cl.course_id = c.id'
+ 'JOIN lesson AS l ON l.id = cl.lesson_id'
;
For this example the following query produces the following tabular data.
Note that this is the same cell values as the Tabular Data With Definition Object
example above but with different column names.
var table = db.fetchAll(sql);
[
{
_id: '1', _title: 'Tabular to Objects', _required: '1',
_teacher_id: '1', _teacher_name: 'David',
_lesson__title: 'Defintions', _lesson__id: '1'
},
{
_id: '1', _title: 'Tabular to Objects', _required: '1',
_teacher_id: '1', _teacher_name: 'David',
_lesson__title: 'Table Data', _lesson__id: '2'
},
{
_id: '1', _title: 'Tabular to Objects', _required: '1',
_teacher_id: '1', _teacher_name: 'David',
_lesson__title: 'Objects', _lesson__id: '3'
},
{
_id: '2', _title: 'Column Names Define Structure', _required: '0',
_teacher_id: '2', _teacher_name: 'Chris',
_lesson__title: 'Column Names', _lesson__id: '4'
},
{
_id: '2', _title: 'Column Names Define Structure', _required: '0',
_teacher_id: '2', _teacher_name: 'Chris',
_lesson__title: 'Table Data', _lesson__id: '2'
},
{
_id: '2', _title: 'Column Names Define Structure', _required: '0',
_teacher_id: '2', _teacher_name: 'Chris',
_lesson__title: 'Objects', _lesson__id: '3'
},
{
_id: '3', _title: 'Object On Bottom', _required: '0',
_teacher_id: '1', _teacher_name: 'David',
_lesson__title: 'Non Array Input', _lesson__id: '5'
}
]
var NestHydrationJS = require('nesthydrationjs')();
result = NestHydrationJS.nest(table);
Note this is the same output as the Tabular Data With Definition Object
example above.
[
{id: 1, title: 'Tabular to Objects', required: true, teacher: {id: 1, name: 'David'}, lesson: [
{id: 1, title: 'Definitions'},
{id: 2, title: 'Table Data'},
{id: 3, title: 'Objects'}
]},
{id: 2, title: 'Column Names Define Structure', required: false, teacher: {id: 2, name: 'Chris'}, lesson: [
{id: 4, title: 'Column Names'},
{id: 2, title: 'Table Data'},
{id: 3, title: 'Objects'}
]},
{id: 3, title: 'Object On Bottom', required: false, teacher: {id: 1, name: 'David'}, lesson: [
{id: 5, title: 'Non Array Input'}
]}
]
It is possible to specify an id column for mapping to objects instead of having it default to the first property of each object specified in the definition. If multiple properties for an object are specified to be ids only the first will be used.
var NestHydrationJS = require('nesthydrationjs')();
var table = [
{bookTitle: 'Anathem', bookId: 1, authorId: 1, authorName: 'Neal Stephenson'},
{bookTitle: 'Seveneves', bookId: 2, authorId: 1, authorName: 'Neal Stephenson'}
];
var definition = [{
name: {column: 'authorName'},
id: {column: 'authorId', id: true},
books: [{
title: {column: 'bookTitle'},
id: {column: 'bookId', id: true}
}]
}];
result = NestHydrationJS.nest(table, definition);
/* result would be the following:
[
{
"name": "Neal Stephenson",
"id": 1,
"books": [
{
"title": "Anathem",
"id": 1
},
{
"title": "Seveneves",
"id": 2
}
]
}
]
*/
You can specify a default value for a property by specifying the default
property in the definition object. The value of the property will be replaced with the default value when it's row data is null
.
var NestHydrationJS = require('nesthydrationjs')();
var table = [
{
id: 1, title: null
}
];
var definition = [{
id: 'id'
title: {column: 'title', default: 'my default'},
}];
result = NestHydrationJS.nest(table, definition);
/* result would be the following:
[
{id: 1, title: 'my default'}
]
*/
New types can be registered using the registerType(name, handler)
function. handler(cellValue, name, row)
is a callback function that takes the cell value, column name and the full row data.
var NestHydrationJS = require('nesthydrationjs')();
NestHydrationJS.registerType('CUSTOM_TYPE', function(value, name, row) {
return '::' + value + '::';
});
var table = [
{
id: 1, title: 'Custom Data Types'
}
];
var definition = [{
id: 'id'
title: {column: 'title', type: 'CUSTOM_TYPE'},
}];
result = NestHydrationJS.nest(table, definition);
/* result would be the following:
[
{id: 1, title: '::Custom Data Types::'}
]
*/
You can also define the type of a column in the definition object as a function and that function will be called for each value provided. The arguments passed are the same as those passed to a custom type handler. This allows formatting of a type without defining it as a global type.
var NestHydrationJS = require('nesthydrationjs')();
var table = [
{
id: 1, title: 'Custom Data Types'
}
];
var definition = [{
id: 'id'
title: {column: 'title', type: function(value, name, row) {
return '::' + value + '::';
}},
}];
result = NestHydrationJS.nest(table, definition);
/* result would be the following:
[
{id: 1, title: '::Custom Data Types::'}
]
*/
[2.0.0] - 2019-11-16
No usage changes except removal of support for deprecated javascript engines.
FAQs
Provides nested objects from tabular data.
The npm package nesthydrationjs receives a total of 682 weekly downloads. As such, nesthydrationjs popularity was classified as not popular.
We found that nesthydrationjs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.