New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

mythix-orm

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mythix-orm - npm Package Compare versions

Comparing version 1.8.2 to 1.8.3

3

lib/connection/query-generator-base.js

@@ -10,2 +10,5 @@ 'use strict';

/// The base query generator class.
///
/// Alias: QueryGenerator
class QueryGeneratorBase {

@@ -12,0 +15,0 @@ constructor(connection) {

8

lib/query-engine/query-engine-base.js

@@ -110,6 +110,6 @@ 'use strict';

_newQueryEngineScope() {
const QueryEngine = this.getQueryEngineClass();
let context = this.currentContext;
let newContext = this._inheritContext(context, 'queryEngine');
let newScope = new QueryEngine(newContext);
const QueryEngineClass = this.getQueryEngineClass();
let context = this.currentContext;
let newContext = this._inheritContext(context, 'queryEngine');
let newScope = new QueryEngineClass(newContext);

@@ -116,0 +116,0 @@ return newScope;

@@ -182,3 +182,3 @@ 'use strict';

/// connection is serializing it for storage in the database.
/// In this case, <see>connection.convertDateToDBTime</see> is
/// In this case, <see>Connection.convertDateToDBTime</see> is
/// called and provided the `value` for the connection to turn

@@ -200,3 +200,3 @@ /// the date into a proper value for the underlying database.

/// proxy serialization to the underlying database connection
/// via the <see>connection.convertDateToDBTime</see> method.
/// via the <see>Connection.convertDateToDBTime</see> method.
serialize(_value, connection) {

@@ -203,0 +203,0 @@ let value = _value;

@@ -184,3 +184,3 @@ 'use strict';

/// connection is serializing it for storage in the database.
/// In this case, <see>connection.convertDateToDBTime</see> is
/// In this case, <see>Connection.convertDateToDBTime</see> is
/// called and provided the `value` for the connection to turn

@@ -202,3 +202,3 @@ /// the date into a proper value for the underlying database.

/// proxy serialization to the underlying database connection
/// via the <see>connection.convertDateToDBTime</see> method.
/// via the <see>Connection.convertDateToDBTime</see> method.
serialize(_value, connection) {

@@ -205,0 +205,0 @@ let value = _value;

@@ -15,3 +15,3 @@ 'use strict';

/// Foreign keys are one of the ways Mythix ORM knows that models
/// are related, along with the `Model` and `Models` virtual types.
/// are related, along with the <see>ModelType</see> and <see>ModelsType</see> virtual types.
/// The "target" field must be a fully qualified field name. A

@@ -288,3 +288,3 @@ /// fully qualified field name is a name that is also prefixed by

/// because the type class can modify the model it
/// exists on. For example, the `Model` and `Models` type
/// exists on. For example, the <see>ModelType</see> and <see>ModelsType</see> types
/// inject custom relational methods onto each model instance.

@@ -291,0 +291,0 @@ ///

@@ -247,3 +247,3 @@ 'use strict';

/// because the type class can modify the model it
/// exists on. For example, the `Model` and `Models` type
/// exists on. For example, the <see>ModelType</see> and <see>ModelsType</see> types
/// inject custom relational methods onto each model instance.

@@ -250,0 +250,0 @@ ///

@@ -125,2 +125,124 @@ 'use strict';

/// A "virtual" field `type` that defines a one to one
/// relationship with another model.
///
/// Relationships (also known as "associations") in Mythix ORM
/// are defined by virtual fields that return a "relationship query"
/// from a method known as a "query generator" that is defined along
/// with the type definition.
/// This "relationship query" itself defines the model relationship, no matter
/// how complicated. Other ORMs require that you define relationships
/// via their "through table", matching foreign key, type, etc...
/// In Mythix ORM, everything is simply defined as a query for the
/// relationship.
///
/// This field `type` can be used to define a virtual field
/// that defines a relationship to another model. When your
/// model is instantiated into an instance, then this type will
/// inject the following methods into your model instance to
/// assist you in interacting with the relationship. The "injected methods"
/// listed below are "prefixes". The full names of these methods are
/// always postfixed with the actual name of your field that defines
/// the relationship. For example, if you had a `primaryRole` field
/// that defined this type of relationship, then the methods injected
/// would be `model.getPrimaryRole`, `model.destroyPrimaryRole`, `model.pluckPrimaryRole`, etc...
/// | Injected Method Prefix | Full Method Name | Signature | Description |
/// | ---------------------- | ---------------- | ----------- | --------- |
/// | `create` | `create${fieldName}` | `create(modelInstanceOrAttributes: Model \| object, options?: object, ...args: Array<any>): Promise<Model>` | Create the model defined by the relationship. Returns the newly created model. |
/// | `destroy` | `destroy${fieldName}` | `destroy(options?: object, ...args: Array<any>): Promise<number>` | Destroy the model defined by the relationship. Returns the number of models destroyed. |
/// | `get` | `get${fieldName}` | `get(userQuery?: QueryEngine, options?: object, ...args: Array<any>): Promise<Model>` | Get the model specified by the relationship, if one is found. Returned the related model (if there is any). |
/// | `has` | `has${fieldName}` | `has(options?: object, ...args: Array<any>): Promise<boolean>` | Check if the model defined by the relationship exists. |
/// | `pluck` | `pluck${fieldName}` | `pluck(fields: Field \| string \| Array<Field \| string>, options?: object, ...args: Array<any>): Promise<Array<any>>` | Pluck specific fields from the related model. |
/// | `queryFor` | `queryFor${fieldName}` | `queryFor(userQuery?: QueryEngine, options?: object, ...args: Array<any>): Promise<QueryEngine>` | Get the raw relationship query defined by this field type (returned by the "query generator"). |
/// | `update` | `update${fieldName}` | `update(modelInstanceOrAttributes: Model \| object, options?: object, ...args: Array<any>): Promise<Model>` | Update the model specified by the relationship. Return the updated model. |
///
/// The `...args` provided for each injected method are pass-through args for the user, that allow
/// the user to pass any arguments they desire to the "relational query generator" method defined
/// by the field (the `...userArgs` as seen in the example below). One minor exception to this is
/// any method that has a `userQuery` argument. The `userQuery` argument will always also be passed as the
/// first argument to the `...userArgs` of the "query generator" method. The `userQuery` argument
/// is to allow the user to define an extra query to merge into the primary/root query of the relationship.
/// For example, in the example provided below, we could call `await user.getPrimaryRole(Role.where.name.EQ('admin'))`
/// to only get the primary role if it also had a `name` attribute with the value `'admin'`.
///
/// This type also injects duplicates of each of these relational methods with an underscore prefix, i.e.
/// `_getPrimaryRole`. These are known as "root methods". They are provided so the user can overload the
/// default implementations. For example, you could define a `getPrimaryRole` method on your model class,
/// and from that call the "super" method simply by calling `this._getPrimaryRole`. This is required because
/// with method injection `super` doesn't actually exist, because the method was injected, instead of being
/// defined on the model class's prototype.
///
/// Example:
/// class User extends Model {
/// static fields = {
/// ...,
/// // Target primary role ID
/// // as a foreign key
/// primaryRoleID: {
/// type: Types.FOREIGN_KEY('Role:id', {
/// // When the role is deleted then
/// // clear this attribute by setting it to NULL
/// onDelete: 'SET NULL',
/// onUpdate: 'CASCADE',
/// }),
/// allowNull: true,
/// index: true,
/// },
/// // Add a virtual relationship field, which creates a
/// // one to one relationship with the Role model.
/// //
/// // Notice how a "type" can always be used directly as
/// // the field definition, instead of defining an object
/// // with a "type" property.
/// primaryRole: Types.Model(
/// // Specify the target/root model.
/// 'Role',
/// // Define our "query generator" method that
/// // will return our "relationship query".
/// (context, connectionModels, ...userArgs) => {
/// // Get the model we need from the connection,
/// // which is conveniently passed to us as the
/// // `connectionModels` argument here.
/// let { Role } = connectionModels;
///
/// // Get the "self", which is the model instance
/// // calling this method
/// // (i.e. with `model.getPrimaryRole()`, "self" would be "model")
/// let { self } = context;
///
/// // Now return a relationship query
/// return Role.where
/// .id
/// .EQ(self.primaryRoleID)
/// .AND
/// .MERGE(userArgs[0]); // Apply the `userQuery` (will do nothing if nullish)
/// },
/// ),
/// };
/// }
///
/// // ... later on
/// // get the "primary role" for the first user in the database
/// let user = await User.first();
/// // Call relationship method injected by the `Types.Model` type.
/// let primaryRole = await user.getPrimaryRole();
///
/// Note:
/// See the [Associations](./Associations) article for a more in-depth discussion
/// of Mythix ORM model relationship/associations.
///
/// Note:
/// The "query generator" method defined with the type can be an asynchronous method.
///
/// Note:
/// Relational methods **will not** be injected into the model instance if a method of
/// the same name already exists on the model instance. For example, if you define a
/// `getPrimaryRole` method on your model class, then the default `get` relational method
/// (`getPrimaryRole` in our example) won't be injected. However, the "root method" `_getPrimaryRole`
/// will still be injected, allowing you to call that as the `super` method instead.
///
/// Note:
/// Behind the scenes the relationship methods provided always apply a `LIMIT(1)` to
/// any query used. This is because this relationship type is singular, so it is expected
/// that only a single model can ever be returned.
class ModelType extends RelationalTypeBase {

@@ -131,2 +253,19 @@ isManyRelation() {

/// Internal method used to generate injected method names.
///
/// This method likely should never be called by the user.
/// It is used to generate the injected method names.
///
/// Return: string
/// The method name to inject into the model instance.
///
/// Arguments:
/// field: <see>Field</see>
/// The parent field defining this relationship.
/// operation: string
/// The operation being injected into the model instance, which is one of
/// the prefixes listed above, i.e. `update`, `get`, `destroy`, etc...
/// rootMethod: boolean
/// If `true`, then return a generated "root method" name, instead of a "user method".
/// The only difference is that the "root method" name is prefixed with an underscore `_`.
fieldNameToOperationName(field, operation, rootMethod) {

@@ -139,2 +278,14 @@ if (rootMethod)

/// Inject type methods into the model instance.
///
/// The <see>Type.initialize</see> method is always called
/// for each model that is instantiated. For this type, this
/// is used to inject the relational methods into the model
/// instance.
///
/// Arguments:
/// connection: <see>Connection</see>
/// The connection for the model being instantiated.
/// self: <see>Model</see>
/// The model instance the type is being initialized for.
initialize(connection, self) {

@@ -141,0 +292,0 @@ return super.initialize(connection, self, TYPE_OPERATIONS);

@@ -242,2 +242,120 @@ 'use strict';

/// A "virtual" field `type` that defines a one to many,
/// or many to many relationship with other model(s).
///
/// Many to many relationships interact with "sets", which in
/// Mythix ORM is the term used to define an "array of models",
/// in our N to many relationship.
///
/// Relationships (also known as "associations") in Mythix ORM
/// are defined by virtual fields that return a "relationship query"
/// from a method known as a "query generator" that is defined along
/// with the type definition.
/// This "relationship query" itself defines the model relationship, no matter
/// how complicated. Other ORMs require that you define relationships
/// via their "through table", matching foreign key, type, etc...
/// In Mythix ORM, everything is simply defined as a query for the
/// relationship.
///
/// This field `type` can be used to define a virtual field
/// that defines a relationship to other models. When your
/// model is instantiated into an instance, then this type will
/// inject the following methods into your model instance to
/// assist you in interacting with the relationship set. The "injected methods"
/// listed below are "prefixes". The full names of these methods are
/// always postfixed with the actual name of your field that defines
/// the relationship. For example, if you had a `roles` field
/// that defined this type of relationship, then the methods injected
/// would be `model.getRoles`, `model.destroyRoles`, `model.pluckRoles`, etc...
/// | Injected Method Prefix | Full Method Name | Signature | Description |
/// | ---------------------- | ---------------- | ----------- | --------- |
/// | `addTo` | `addTo${fieldName}` | `addTo(models: Array<Model \| object>, options?: object): Promise<Array<Model>>` | Create the models defined by the relationship, and add them to the set. Returns the newly created models. |
/// | `count` | `count${fieldName}` | `count(userQuery?: QueryEngine, options?: object, ...args: Array<any>): Promise<number>` | Count the number of models in the set. |
/// | `destroy` | `destroy${fieldName}` | `destroy(options?: object, ...args: Array<any>): Promise<number>` | Destroy the models defined by the relationship set. Returns the number of models destroyed. Note that this not only destroys the target models, but also any through-table relationships involved. |
/// | `get` | `get${fieldName}` | `get(userQuery?: QueryEngine, options?: object, ...args: Array<any>): Promise<Array<Model>>` | Get the models specified by the relationship set. Return the entire model set. |
/// | `has` | `has${fieldName}` | `has(userQuery?: QueryEngine, options?: object, ...args: Array<any>): Promise<boolean>` | Check if the relationship set contains any models. |
/// | `pluck` | `pluck${fieldName}` | `pluck(userQuery?: QueryEngine, fields: Field \| string \| Array<Field \| string>, options?: object, ...args: Array<any>): Promise<Array<any>>` | Pluck specific fields from the related models (set). |
/// | `queryFor` | `queryFor${fieldName}` | `queryFor(userQuery?: QueryEngine, options?: object, ...args: Array<any>): Promise<QueryEngine>` | Get the raw relationship query defined by this field type (returned by the "query generator"). |
/// | `removeFrom` | `removeFrom${fieldName}` | `removeFrom(models: Array<Model>, options?: object): Promise<number>` | Remove the specified models from the relationship set without destroying the target models (destroy only the through-table linking models). Returns the number of models remaining in the set after the operation. |
/// | `set` | `set${fieldName}` | `set(models: Array<Model \| object>, options?: object): Promise<Array<Model>>` | Overwrite the model set with the models specified, destroying models outside the specified set of models. Returns the new models. |
///
/// The `...args` provided for each injected method are pass-through args for the user, that allow
/// the user to pass any arguments they desire to the "relational query generator" method defined
/// by the field (the `...userArgs` as seen in the example below). One minor exception to this is
/// any method that has a `userQuery` argument. The `userQuery` argument will always also be passed as the
/// first argument to the `...userArgs` of the "query generator" method. The `userQuery` argument
/// is to allow the user to define an extra query to merge into the primary/root query of the relationship.
/// For example, in the example provided below, we could call `await user.getRoles(Role.where.name.EQ('admin'))`
/// to only get the related roles where each role also has a `name` attribute with the value `'admin'`.
///
/// This type also injects duplicates of each of these relational methods with an underscore prefix, i.e.
/// `_getRoles`. These are known as "root methods". They are provided so the user can overload the
/// default implementations. For example, you could define a `getRoles` method on your model class,
/// and from that call the "super" method simply by calling `this._getRoles`. This is required because
/// with method injection `super` doesn't actually exist, because the method was injected, instead of being
/// defined on the model class's prototype.
///
/// Example:
/// class User extends Model {
/// static fields = {
/// ...,
/// // Add a virtual relationship field, which creates a
/// // one to many relationship with the Role model.
/// //
/// // Notice how a "type" can always be used directly as
/// // the field definition, instead of defining an object
/// // with a "type" property.
/// roles: Types.Models(
/// // Specify the target/root model.
/// 'Role',
/// // Define our "query generator" method that
/// // will return our "relationship query".
/// (context, connectionModels, ...userArgs) => {
/// // Get the model we need from the connection,
/// // which is conveniently passed to us as the
/// // `connectionModels` argument here.
/// let { Role } = connectionModels;
///
/// // Get the "self", which is the model instance
/// // calling this method
/// // (i.e. with `model.getRoles()`, "self" would be "model")
/// let { self } = context;
///
/// // Now return a relationship query
/// return Role.where
/// .userID
/// .EQ(self.id)
/// .AND
/// .MERGE(userArgs[0]); // Apply the `userQuery` (will do nothing if nullish)
/// },
/// ),
/// };
/// }
///
/// // ... later on
/// // get the "roles" for the first user in the database
/// let user = await User.first();
/// // Call relationship method injected by the `Types.Models` type.
/// let allUserRoles = await user.getRoles();
///
/// Note:
/// See the [Associations](./Associations) article for a more in-depth discussion
/// of Mythix ORM model relationship/associations.
///
/// Note:
/// The "query generator" method defined with the type can be an asynchronous method.
///
/// Note:
/// Relational methods **will not** be injected into the model instance if a method of
/// the same name already exists on the model instance. For example, if you define a
/// `getRoles` method on your model class, then the default `get` relational method
/// (`getRoles` in our example) won't be injected. However, the "root method" `_getRoles`
/// will still be injected, allowing you to call that as the `super` method instead.
///
/// Note:
/// This field type will not be "exposed" to models. This means that your model will not
/// have an attribute with the name provided by the field defining this type. The only
/// thing that will exist on your model will be the relational methods injected by this type.
/// Said another way, and using the examples provided, there will be no "roles" attribute
/// on your `User` model.
class ModelsType extends RelationalTypeBase {

@@ -252,2 +370,19 @@ static exposeToModel() {

/// Internal method used to generate injected method names.
///
/// This method likely should never be called by the user.
/// It is used to generate the injected method names.
///
/// Return: string
/// The method name to inject into the model instance.
///
/// Arguments:
/// field: <see>Field</see>
/// The parent field defining this relationship.
/// operation: string
/// The operation being injected into the model instance, which is one of
/// the prefixes listed above, i.e. `addTo`, `get`, `destroy`, etc...
/// rootMethod: boolean
/// If `true`, then return a generated "root method" name, instead of a "user method".
/// The only difference is that the "root method" name is prefixed with an underscore `_`.
fieldNameToOperationName(field, operation, rootMethod) {

@@ -264,2 +399,14 @@ let fieldName = field.pluralName;

/// Inject type methods into the model instance.
///
/// The <see>Type.initialize</see> method is always called
/// for each model that is instantiated. For this type, this
/// is used to inject the relational methods into the model
/// instance.
///
/// Arguments:
/// connection: <see>Connection</see>
/// The connection for the model being instantiated.
/// self: <see>Model</see>
/// The model instance the type is being initialized for.
initialize(connection, self) {

@@ -266,0 +413,0 @@ return super.initialize(connection, self, TYPE_OPERATIONS);

@@ -20,12 +20,2 @@ 'use strict';

// Model types work by specifying a "target"
// and a "value provider" (source).
// These are fully qualified names, meaning
// they also point to the model as well as the field.
// If no model is specified, then it always defaults to
// "this" model. If no field is specified, then it always
// defaults to "this PK" of the model.
// Mythix ORM will recursively walk all models and fields
// defined until it has the full relationships between
// all fields.
constructor(_targetModelName, queryFactory, _options) {

@@ -32,0 +22,0 @@ let options = _options || {};

@@ -0,1 +1,3 @@

///! DocScope: ModelUtils
'use strict';

@@ -14,2 +16,44 @@

/// Parse a fully qualified field name.
///
/// A fully qualified field name is a field name that
/// is prefixed by its parent model. For example,
/// `'User:email'` is a fully qualified field name,
/// whereas just `'email'` is not.
///
/// This method will actually parse both formats however.
/// It will parse fully qualified field names, and short-hand
/// field names (just the field name). If just a field name
/// is provided with no model name prefix, then the resulting
/// `modelName` property of the returned object will be `undefined`.
///
/// Field names themselves can be deeply nested. For example,
/// `'User:metadata.ipAddress'`. Field nesting was designed into
/// the Mythix ORM framework, and is partially supported in some
/// areas of the framework. However, field nesting likely won't work
/// in many places without further support being added. This feature
/// was left in-place for now, because it will likely be expanded upon
/// in the future.
/// Because of this "field nesting", instead of just one field name being
/// returned, an array of field names is *always* returned. Generally,
/// to get the field name you are looking for you would just get the first
/// index (`fieldNames[0]`) on the returned object.
///
/// This method can and will also parse just a model name, so long as the provided
/// name starts with an upper-case letter. If no colon is found (meaning no model
/// prefix is present), then the provided value will be assumed to be a model name
/// only if it starts with an upper-case letter. Otherwise, it is treated as a field
/// name, and returned in the `fieldNames` array.
///
/// Arguments:
/// fieldName: string
/// A model name, field name, or fully qualified field name to parse.
///
/// Return: object
/// An object with the shape `{ modelName: string | undefined; fieldNames: Array<string> }`.
/// The `modelName` property will contain the name of the model for the field, if it is known,
/// which will only be the case for a fully qualified name (i.e. `'User:email'`), or a
/// model name alone (i.e. `'User'`). `fieldNames` will always be an array of field names
/// parsed, which will generally only be one. It can be empty if no field name was provided,
/// for example if only a model name was provided (i.e. `'User'`).
function parseQualifiedName(str) {

@@ -16,0 +60,0 @@ let fieldNames = [];

@@ -65,7 +65,7 @@ 'use strict';

'*': (Model, fieldName, query, value) => {
return query.LIKE(value);
return query.AND[fieldName].LIKE(value);
},
// NOT Like
'!*': (Model, fieldName, query, value) => {
return query.NOT_LIKE(value);
return query.AND[fieldName].NOT_LIKE(value);
},

@@ -72,0 +72,0 @@ };

{
"name": "mythix-orm",
"version": "1.8.2",
"version": "1.8.3",
"description": "ORM for Mythix framework",

@@ -5,0 +5,0 @@ "main": "lib/index",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc