Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@janiscommerce/model
Advanced tools
npm install @janiscommerce/model
changeKeys
param and cannot get any items, it will return an empty object (before returns an empty array)@janiscommerce/settings
will no longer be supported. (Replaced with AWS Parameter Store Since 8.8.0)In order to use this package with a DB, you must to add the database connection settings, it can be set in service settings janiscommercerc.json
(Core model) or in session (Client Model).
databaseKey
Regardless if you use a Core or Client model you may set the databaseKey
that your model will use to get the database connection settings. Default: 'default'
.
class MyModel extends Model {
get databaseKey() {
return 'myDatabaseKey';
}
}
👀 Either in Core or Client model the databaseKey
connection settings structure is the same:
:information_source: The type
property is the only one used by this package to fetch the correct DB Driver package to use.
:warning: The rest of the connection properties depends entirely by the DB Driver that you will use.
{
myDatabaseKey: {
write: {
"type": "mongodb",
"host": "http://write-host-name.org",
// ...
},
read: {
"type": "mongodb",
"host": "http://read-host-name.org",
// ...
}
}
}
There are two different model types:
databaseKey
in your Model extended classclass MyModel extends Model {
get databaseKey() {
return 'core';
}
}
databaseKey
in database service settingsUsing Settings, with settings in file /path/to/root/.janiscommercerc.json
:
{
"database": {
"core": {
"write":{
"host": "http://my-host-name.org",
"type": "mysql",
// ...
}
}
}
}
The session injection is useful when you have a dedicated database per client.
Using the public setter session
, the session will be stored in the controller
instance.
All the controllers and models getted using that controller will have the session injected.
databaseKey
in your Model extended classclass MyModel extends Model {
get databaseKey() {
return 'myDatabaseKey';
}
}
Your client should have the config for read (optional) and/or write (required) databases.
Example of received client:
{
"name": "Some Client",
"code": "some-client",
"databases": {
"default":{
"write": {
"type": "mongodb",
"host": "http://default-host-name.org",
// ...
}
},
"myDatabaseKey": {
"write": {
"type": "mongodb",
"host": "http://write-host-name.org",
// ...
},
"read": {
"type": "mongodb",
"host": "http://read-host-name.org",
// ...
}
}
}
}
shouldCreateLogs (static getter).
Returns if the model should log the write operations. Default: true
. For more details about logging, read the logging section.
excludeFieldsInLog (static getter).
Returns the fields that will be removed from the logs as an array of strings. For example: ['password', 'super-secret']
. For more details about logging, read the logging section.
statuses (class getter).
Returns an object
with the default statuses (active
/ inactive
)
executionTime (class getter). Returns the time spent in ms on the las query.
[Boolean]
(class setter)
Set if model should use the read DB in all read/write DB operations. Default: false
.getDb()
const dbDriver = await myModel.getDb();
await myModel.dbDriver.specialMethod(myModel);
isCore()
Since 8.8.0
const myCoreModel = new MyCoreModel();
const isCore = await myCoreModel.isCore(); // true expected
const myClientModel = new MyClientModel();
const isCore = await myClientModel.isCore(); // false expected
get(params)
params
is an optional Object with filters, order, paginator.params.readonly
as true
if you want to use the Read Database.const items = await myModel.get({ filters: { status: 'active' } });
getById(id, [params])
id
is required. It can be one ID or an array of IDsparams
is an optional Object with filters, order, paginator, changeKeys.const items = await myModel.getById(123, { filters: { status: 'active' } });
getBy(field, id, [params])
field
is required. A string as a fieldvalue
is required. It can be one value or an array of valuesparams
is an optional Object with filters, order, paginator.const items = await myModel.getBy(orderId, 123, { filters: { status: 'active' } });
getPaged(params, callback)
params
See get() methodcallback
A function to be executed for each page. Receives three arguments: the items found, the current page and the page limitawait myModel.getPaged({ filters: { status: 'active' } }, (items, page, limit) => {
// items is an array with the result from DB
});
The default order when no order was received is field id
using asc
as order direction. Since 6.8.3
getTotals(filters)
filters
is an optional. Object with filters or array of filters. Since 7.1.0await myModel.get({ filters: { status: 'active' } });
const totals = await myModel.getTotals();
/**
totals content:
{
pages: 3,
page: 1,
limit: 500,
total: 1450
}
*/
const totals = await myModel.getTotals( { status: 'active' } );
/**
totals content:
{
pages: 3,
page: 1,
limit: 500,
total: 1450
}
*/
mapIdBy(field, fieldValues, [params])
field
Field to filter for (String
)fieldValues
List of values to filter for (Array<strings>
)params
See get() methodawait myModel.mapIdBy('code', ['code-123', 'code-456'], {
order: { code: 'desc' }
});
/**
{
code-456: 'the-code-456-id',
code-123: 'the-code-123-id'
}
*/
mapIdByReferenceId(referencesIds, [params])
referencesIds
List of References Ids (Array<strings>
)params
See get() methodawait myModel.mapIdByReferenceId(['some-ref-id', 'other-ref-id', 'foo-ref-id'], {
order: { date: 'asc' },
filters: { foo: 'bar' }
});
/**
{
some-ref-id: 'some-id',
foo-ref-id: 'foo-id'
}
*/
distinct(key, params)
params
is an optional Object with filters.const uniqueValues = await myModel.distinct('status');
const uniqueValues = await myModel.distinct('status', {
filters: {
type: 'some-type'
}
});
insert(item)
await myModel.insert({ foo: 'bar' });
const items = await myModel.get({ filters: { foo: 'bar' }});
/**
itemInserted content:
[
{
foo: 'bar'
}
//...
]
*/
save(item, setOnInsert)
setOnInsert
to add default values on Insert, optionalawait myModel.save({ foo: 'bar' }, { status: 'active' });
const items = await myModel.get({ filters: { foo: 'bar' }});
/**
items content:
[
{
foo: 'bar',
status: 'active'
}
//...
]
*/
update(values, filter, params)
params
optional parameters to define some behavior of the query
skipAutomaticSetModifiedData
: Boolean. When receive as true, the fields dateModified
and userModified
are not updated automatically.await myModel.update({ updated: 1 }, { status: 5 });
// will set updated = 1 for the items that has status = 5
remove(item)
await myModel.remove({ foo: 'bar' });
const items = await myModel.get({ filters: { foo: 'bar' }});
/**
items content:
[]
*/
multiInsert(items)
await myModel.multiInsert([{ foo: 1 }, { foo: 2 }]);
const items = await myModel.get();
/**
items content:
[
{ foo: 1 },
{ foo: 2 }
]
*/
multiSave(items, setOnInsert)
setOnInsert
to add default values on Insert, optionalawait myModel.multiSave([{ foo: 1 }, { foo: 2, status: 'pending' }], { status: 'active' });
const items = await myModel.get();
/**
items content:
[
{ foo: 1, status: 'active' },
{ foo: 2, status: 'pending' }
]
*/
multiRemove(filter)
await myModel.multiRemove({ status: 2 });
const items = await myModel.get({ filters: { status: 2 }});
/**
items content:
[]
*/
increment(filters, incrementData)
await myModel.increment({ uniqueIndex: 'bar' }, { increment: 1, decrement: -1 });
/**
before:
items content:
[
{
increment: 1,
decrement: 2
}
//...
]
after:
items content:
[
{
increment: 2,
decrement: 1
}
//...
]
*/
changeKeys(items, newKey)
items
The items arraynewKey
The common field in items that will be used as key for each itemconst myItems = await myModel.get();
/*
[
{ some: 'item', otherProp: false },
{ some: 'otherItem', otherProp: true }
]
*/
const myItemsByKey = MyModel.changeKeys(myItems, 'some');
/*
{
item: { some: 'item', otherProp: false },
otherItem: { some: 'otherItem', otherProp: true }
}
*/
:information_source: In get methods such as get
and getBy
you can add the changeKeys
param with the newKey
value.
const myItems = await myModel.get({ changeKeys: 'some' });
/*
{
item: { some: 'item', otherProp: false },
otherItem: { some: 'otherItem', otherProp: true }
}
*/
:information_source: Since 6.0.0: When no items were found it will return an empty object
const myItems = await myModel.get({ filters: { status: 'active' }, changeKeys: 'other' });
/*
{}
*/
dropDatabase()
await myModel.dropDatabase();
aggregate(stages)
:warning: Not supported by all database connectors
stages
An array with the aggregation stages
const results = await myModel.aggregate([
{ $match: { id: '0000000055f2255a1a8e0c54' } }, // find the document with that id
{ $unset: 'category' }, // Removes the category field
]);
/**
[
{
id: '0000000055f2255a1a8e0c54',
name: 'Product 1',
description: 'Product 1 description'
}
]
*/
multiUpdate(operations)
await myModel.multiUpdate([
{ filter: { id: [1,2] }, data: { name: 'test 1' } },
{ filter: { otherId: 3 }, data: { name: 'test 2' } }
]);
const items = await myModel.get();
/**
items content:
[
{ id: 1, name: 'test 1' },
{ id: 4, otherId: 3, name: 'test 2' }
]
*/
getIndexes()
await myModel.getIndexes();
/*
[
{ name: '_id_', key: { _id_: 1}, unique: true },
{ name: 'code', key: { code: 1} }
]
*/
createIndex(index)
await myModel.createIndex({ name: 'name', key: { name: 1}, unique: true });
createIndexes(indexes)
await myModel.createIndexes([{ name: 'name', key: { name: 1}, unique: true }, { name: 'code', key: { code: -1 }}]);
dropIndex(name)
await myModel.dropIndex('name');
dropIndexes(names)
await myModel.dropIndexes(['name', 'code']);
getIdStruct()
const idStruct = await myModel.getIdStruct();
/*
struct('objectId')
*/
This package automatically logs any write operation such as:
insert()
multiInsert()
update()
save()
multiSave()
increment()
remove()
multiRemove()
:information_source: The logs will be added using the package @janiscommerce/log.
log
The package will add automatic fields in the log
Object field.
executionTime
. Each log will have the time spent on the query. Since 6.6.0itemsBatch
. Exclusively for methods multiInsert()
and multiSave()
, will be added the quantity of items inserted or updated in the same query. Since 6.6.0static getter shouldCreateLogs
to false
.class MyModel extends Model {
static get shouldCreateLogs() {
return false;
}
}
disableLogs()
. Since 8.3.0:information_source: The logs are disabled only for the following operation
// will not save logs
await myModel.disableLogs().insert({
pet: 'roger',
animal: 'dog',
age: 8
});
// will save logs normally
await myModel.insert({
pet: 'ringo',
animal: 'dog',
age: 7
});
static getter
excludeFieldsInLog
:class MyModel extends Model {
static get excludeFieldsInLog() {
return [
'password',
'address',
'secret'
]
}
}
By setting this when you do an operation with an item like:
await myModel.insert({
user: 'johndoe',
password: 'some-password',
country: 'AR',
address: 'Fake St 123'
});
It will be logged as:
{
id: '5ea30bcbe28c55870324d9f0',
user: 'johndoe',
country: 'AR'
}
Adding a custom message:
await myModel
.setLogData('custom message!')
.insert({ foo: 'bar' });
/*
Log: {
...logData,
message: 'custom message!'
}
*/
Adding a custom object data:
await myModel
.setLogData({message:'custom message!', type:'some type'})
.insert({ foo: 'bar' });
/*
Log: {
...logData,
message: 'custom message!',
type:'some type'
}
*/
Adding a custom object data with log property name:
await myModel
.setLogData({message:'custom message!', type:'some type', log: { isTest: true }})
.insert({ foo: 'bar' });
/*
Log: {
...logData,
message: 'custom message!',
type:'some type',
log:{
...defaultModelLogData,
isTest: true
}
}
*/
⚠️ Deprecated: This configuration will no longer be supported starting from version 9.0.0. ⚠️
The package will get the secret using the JANIS_SERVICE_NAME
environment variable.
If the secret is found, the result will be merged with the settings found in the janiscommercerc.json
file or in the Client databases configuration. See Database connection settings.
The Secrets are stored in AWS Secrets Manager and obtained with the package @janiscommerce/aws-secrets-manager
{
"core": {
"write": {
"type": "mongodb",
"database": "core",
"otherDBDriverConfig": 100
}
}
}
{
"databases": {
"core": {
"write": {
"host": "mongodb+srv://some-host.mongodb.net",
"user": "secure-user",
"password": "secure-password",
}
}
}
}
{
"core": {
"write": {
"type": "mongodb",
"database": "core",
"otherDBDriverConfig": 100,
"host": "mongodb+srv://some-host.mongodb.net",
"user": "secure-user",
"password": "secure-password",
}
}
}
To skip the fetch of the credentials, it can be used the setting skipFetchCredentials
set as true.
{
"core": {
"write": {
"skipFetchCredentials": true,
"type": "mongodb",
"protocol": "mongodb+srv://",
"host": "mongodb+srv://some-host.mongodb.net",
"user": "some-user",
"password": "insecure-password"
}
}
}
FAQs
A package for managing Janis Models
The npm package @janiscommerce/model receives a total of 302 weekly downloads. As such, @janiscommerce/model popularity was classified as not popular.
We found that @janiscommerce/model demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 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.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.