Skip to content

Releases: martenframework/marten

0.5.2

24 Aug 20:27
9675b2d
Compare
Choose a tag to compare

Marten 0.5.2 fixes a couple of bugs.

Bug fixes

  • Fix text template name of emails generated through the use of the email generator.
  • Fix non-existing error when the new management command was used to generate an app structure with the --with-auth option.
  • Fix missing "emails" folder requirement in projects generated with the new management command.
  • Fix how nested routes are displayed when invoking the routes management command.
  • Fix settings namespace generation for top-level Settings settings classes.

0.5.1

27 Jul 15:44
5f79e01
Compare
Choose a tag to compare

Marten 0.5.1 fixes a couple of bugs.

Bug fixes

  • Fix duplicated #create_user spec helper method in projects generated with the authentication application.
  • Fix excessive verbosity when running management commands.
  • Fix non-working hash/array methods in templates.
  • Fix an issue where unknown variable exceptions are not raised when accessing unsupported attributes on custom template objects.
  • Make sure the cookie session store always defines an expiry when signing the session data.

0.5.0

13 Jul 21:15
4ae28f0
Compare
Choose a tag to compare

Marten 0.5 is here! This major version adds substantial enhancements to the framework like the ability to leverage pre-fetched relations in query sets, model scopes, enum fields for models and schemas, raw SQL predicates, and more!

Requirements and compatibility

  • Crystal: 1.11, 1.12, and 1.13.
  • Databases:
    • MariaDB 10.4 and higher.
    • MySQL 8.0.11 and higher.
    • PostgreSQL 12 and higher.
    • SQLite 3.27.0 and higher.

New features

Relations pre-fetching

Marten now provides the ability to prefetch relations when using query sets through the use of the new #prefetch method. When using #prefetch, the records corresponding to the specified relationships will be prefetched in single batches and each record returned by the original query set will have the corresponding related objects already selected and populated.

For example:

posts_1 = Post.all.to_a
# hits the database to retrieve the related "tags" (many-to-many relation)
puts posts_1[0].tags.to_a

posts_2 = Post.all.prefetch(:tags).to_a
# doesn't hit the database since the related "tags" relation was already prefetched
puts posts_2[0].tags.to_a

Like the existing #join method, this allows to alleviate N+1 issues commonly encountered when accessing related objects. However, unlike #join (which can only be used with single-valued relationships), #prefetch can be used with both single-valued relationships and multi-valued relationships (such as many-to-many relationships, reverse many-to-many relationships, and reverse many-to-one relationships).

Please refer to Pre-fetching relations to learn more about this new capability.

Model scopes

It is now possible to define scopes in model classes. Scopes allow to pre-define specific filtered query sets, which can be easily applied to model classes and model query sets.

Such scopes can be defined through the use of the #scope macro, which expects a scope name (string literal or symbol) as first argument and requires a block where the query set filtering logic is defined:

class Post < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :title, :string, max_size: 255
  field :is_published, :bool, default: false
  field :created_at, :date_time

  scope :published { filter(is_published: true) }
  scope :unpublished { filter(is_published: false) }
  scope :recent { filter(created_at__gt: 1.year.ago) }
end

Post.published # => Post::QuerySet [...]>

It is also possible to override the default scope through the use of the #default_scope macro. This macro requires a block where the query set filtering logic is defined:

class Post < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :title, :string, max_size: 255
  field :is_published, :bool, default: false
  field :created_at, :date_time

  default_scope { filter(is_published: true) }
end

Please refer to Scopes for more details on how to define scopes.

Enum field for models and schemas

It is now possible to define enum fields in models and schemas. For models, such fields allow you to store valid enum values, with validation enforced at the database level. When validating data with schemas, they allow you to expect valid string values that match those of the configured enum.

For example:

enum Category
  NEWS
  BLOG
end

class Article < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :category, :enum, values: Category
end

article = Article.last!
article.category # => Category::BLOG

Raw SQL predicate filtering

Marten now provides the ability to filter query sets using raw SQL predicates through the use of the #filter method. This is useful when you want to leverage the flexibility of SQL for specific conditions, but still want Marten to handle the column selection and query building for the rest of the query.

For example:

Author.filter("first_name = :first_name", first_name: "John")
Author.filter("first_name = ?", "John")
Author.filter { q("first_name = :first_name", first_name: "John") }

Please refer to Filtering with raw SQL predicates to learn more about this new capability.

Minor features

Models and databases

  • A new #pks method was introduced for query sets to make it easy to retrieve the primary key values of the model records targeted by a given current query set.
  • A #count method is now available on model classes and provides the same functionality as the #count query set method.
  • A new #bulk_create method was introduced to make it easy to insert multiple model instances into the database in a single query (which can be useful when dealing with large amounts of data that need to be inserted into the database).
  • A new #average method was introduced to allow computing the average values of a specific model field at the database level for the records targeted by a specific query set.
  • A new #sum method was introduced to allow computing the sum of the values of a specific model field at the database level for the records targeted by a specific query set.
  • It is now possible to compute the minimum and maximum values of a specific field at the database level for the records targeted by a query set through the use of the #minimum and #maximum methods.
  • The in query set predicate now supports filtering on arrays of model records directly.
  • Query sets now provide a #to_sql method allowing to retrieve the corresponding SQL representation.
  • Query sets can now be combined using the AND and OR binary operators. This can be achieved through the use of the & and | query set methods.
  • Invalid record exceptions (instances of Marten::DB::Errors::InvalidRecord) now provide more details regarding the actual errors of the associated record.
  • Creations of records from many-to-one reverse relation query sets are now scoped to the related record. See Many-to-one relationships for more details.
  • A new #build method was introduced to make it possible to initialize new model instances from query sets.

Handlers and HTTP

Read more

0.4.5

06 May 00:17
6c6086e
Compare
Choose a tag to compare

Marten 0.4.5 fixes a couple of bugs.

Bug fixes

  • Fix a possible compilation error with custom settings namespace generation.
  • Ensure that the serve management command recompiles projects upon translation file changes.
  • Fix the order of asset finders to ensure that those associated with configured asset directories (via the assets.dirs setting) have priority over those associated with application directories.

0.4.4

05 Apr 01:28
fb0537c
Compare
Choose a tag to compare

Marten 0.4.4 fixes a couple of bugs.

Bug fixes

  • Fix possible SQL syntax errors occurring when using in predicates with empty arrays.

0.4.3

11 Mar 01:31
5f8a2b1
Compare
Choose a tag to compare

Marten 0.4.3 fixes a couple of bugs.

Bug fixes

  • Ensure that request query parameters can be accessed from templates.
  • Fix hidden folders being ignored by the collectassets management command.
  • Fix some ameba warnings in generated projects and applications.
  • Fix inconsistency of #using method definitions between model classes and query sets.
  • Fix missing DB-specific requirements in generated projects.

0.4.2

27 Feb 14:01
3594e89
Compare
Choose a tag to compare

Marten 0.4.2 fixes a couple of bugs.

Bug fixes

  • Fix a possible syntax error in the SQL queries generated for SQLite databases when running migrations.

0.4.1

20 Feb 13:14
2e06ba2
Compare
Choose a tag to compare

Marten 0.4.1 fixes a couple of bugs.

Bug fixes

  • Fix the position of the config/routes.cr file requirement in the src/project.cr file of generated projects.

0.4.0

13 Jan 18:04
452762c
Compare
Choose a tag to compare

Marten 0.4.0 brings substantial enhancements to the framework, including the addition of generators, multi-table inheritance, schema handler callbacks, and more!

Requirements and compatibility

Crystal 1.9, 1.10, and 1.11.

New features

Generators

Marten now provides a generator mechanism that makes it easy to create various abstractions, files, and structures within an existing project. This feature is available through the use of the gen management command and facilitates the generation of key components such as models, schemas, emails, or applications. The authentication application can now also be added easily to existing projects through the use of generators. By leveraging generators, developers can improve their workflow and speed up the development of their Marten projects while following best practices.

Below are highlighted some examples illustrating the use of the gen management command:

# Generate a model in the admin app:
marten gen model User name:string email:string --app admin

# Generate a new TestEmail email in the blog application:
marten gen email TestEmail --app blog

# Add a new 'blogging' application to the current project:
marten gen app blogging

# Add the authentication application to the current project:
margen gen auth

You can read more about the generator mechanism in the dedicated documentation. All the available generators are also listed in the generators reference.

Multi table inheritance

It is now possible to define models that inherit from other concrete models (ie. non-abstract models). In this situation, each model can be used/queried individually and has its own associated database table. The framework automatically defines a set of "links" between each model that uses multi table inheritance and its parent models in order to ensure that the relational structure and inheritance hierarchy are maintained.

For example:

class Person < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :first_name, :string, max_size: 100
  field :last_name, :string, max_size: 100
end

class Employee < Person
  field :company_name, :string, max_size: 100
end

employee = Employee.filter(first_name: "John").first!
employee.first_name # => "John"

All the fields defined in the Person model can be accessed when interacting with records of the Employee model (despite the fact that the data itself is stored in distinct tables).

You can read more about this new kind of model inheritance in Multi table inheritance.

Schema handler callbacks

Handlers that inherit from the base schema handler - Marten::Handlers::Schema - or one of its subclasses (such as Marten::Handlers::RecordCreate or Marten::Handlers::RecordUpdate) can now define new kinds of callbacks that allow to easily manipulate the considered schema instance and to define logic to execute before the schema is validated or after (eg. when the schema validation is successful or failed):

For example, the after_successful_schema_validation callback can be used to create a flash message after a schema has been successfully validated:

class ArticleCreateHandler < Marten::Handlers::Schema
  success_route_name "home"
  template_name "articles/create.html"
  schema ArticleSchema

  after_successful_schema_validation :generate_success_flash_message

  private def generate_success_flash_message : Nil
    flash[:notice] = "Article successfully created!"
  end
end

Please head over to Schema handler callbacks to learn more about these new types of callbacks.

URL field for models and schemas

It is now possible to define url fields in models and schemas. These allow you to easily persist valid URLs in your models but also to expect valid URL values in data validated through the use of schemas.

For example:

class User < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :website_url, :url, blank: true, null: true
end

Slug field for models and schemas

It is now possible to define slug fields in models and schemas. These allow you to easily persist valid slug values (ie. strings that can only include characters, numbers, dashes, and underscores) in your models but also to expect such values in data validated through the use of schemas.

For example:

class User < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :username, :slug
end

Minor features

Models and databases

  • Support for removing records from many-to-many fields was added and many-to-many field query sets now provide a #remove helper method allowing to easily remove specific records from a specific relation. You can learn more about this capability in Many-to-many relationships.
  • Support for clearing all the references to records targeted by many-to-many fields was added. Indeed, many-to-many field query sets now provide a #clear method allowing to easily clear a specific relation. You can learn more about this capability in Many-to-many relationships.
  • It is now possible to specify arrays of records to add or remove from a many-to-many relationship query set, through the use of the #add and #remove methods. See the related documentation to learn more about interacting with records targeted by many-to-many relationships.
  • Records targeted by reverse relations that are contributed to models by one_to_one (ie. when using the related option) are now memoized when the corresponding methods are called on related model instances.
  • Relation fields that contribute methods that return query sets to models (such as many_to_one or many_to_many fields) now make sure that those query set objects are memoized at the record level. The corresponding instance variables are also reset when the considered records are reloaded. This allows to limit the number of queries involved when iterating multiple times over the records targeted by a many_to_many field for example.
  • The #order query set method can now be called directly on model classes to allow retrieving all the records of the considered model in a specific order.
  • A #pk? model method can now be leveraged to determine if a primary key value is set on a given model record.
  • The #join query set method now makes it possible to pre-select one-to-one reverse relations. This essentially ...
Read more

0.3.4

10 Jan 02:02
a6acede
Compare
Choose a tag to compare

Marten 0.3.4 fixes a couple of bugs.

Bug fixes

  • Fix compilation error with Crystal 1.11.