question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: Make collections immutable by default in frint-data

See original GitHub issue

Currently

In frint-data, models are immutable by default. If you want any properties to be changed, you can only do it via custom defined methods:

import { Types, createModel } from 'frint-data';

const Todo = createModel({
  schema: {
    title: Types.string,
  },

  setTitle(newTitle) {
    this.title = newTitle;
  }
});

const todo = new Todo({ title: 'Hello World' });

// has no impact
todo.title = 'updated title';

// can only be done via methods
todo.setTitle('Hello Universe');

But collections on the other hand exposes methods that can mutate its models:

import { createCollection } from 'frint-data';

const Todos = createCollection({
  model: Todo,
});

const todos = new Todos([{ title: 'Hello World' }]);
todos.push(new Todo({ title: 'About us' })); 

// now `todos` has two models

Expection

Like models, we also expect Collections to be immutable by default, and not allow any changes unless the class permits it. This would avoid any unpredictable behaviour in the app later.

I request for comments from everyone, like what API would be ideal to make this happen.

Some suggestions

1: Mutating methods allowed inside custom methods only

import { createCollection } from 'frint-data';
import Todo from '../models/Todo';

const Todos = createCollection({
  model: Todo,
  
  addTodo(todo) {
    // allow access to "write/delete" methods inside custom methods only
    this.push(todo);
  },
});

2: Additional property at class level allowing mutation

import { createCollection } from 'frint-data';
import Todo from '../models/Todo';

const Todos = createCollection({
  model: Todo,

  // setting this to `true` gives access to `push` and other methods
  mutable: true,
});

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
ghostcommented, Oct 30, 2017

I would go for the first option in order to be consistent with the current Model implementation that we have. The possibility of mutating the model should be managed internally. It means that until you implemented your setters, the list is by default immutable.

An extra property could be a bit confusing from my point of view.

0reactions
fahad19commented, Nov 13, 2017

Regarding complex structures, a particular Model is never expected to have Arrays or Objects as attributes. It should rather have a Collection or another Model.

like this for example with Embedding feature:

import { Types, createModel, createCollection } from 'frint-data';

const Book = createModel({
  schema: {
    id: Types.string,
    title: Types.string,
  },
});

const Books = createCollection({
  model: Book,
});

const Address = createModel({
  schema: {
    street: Types.string,
    country: Types.string,
  },
});

const Author = createModel({
  schema: {
    id: Types.string,
    name: Types.string,
    address: Types.model.of(Address),
    books: Types.collection.of(Books),
  },
});

Further reading: https://frint.js.org/docs/packages/frint-data/#embedding

Can be instantiated like this:

const author = new Author({
  id: '123',
  name: 'Foo',
  address: {
    street: 'blah..',
  },
  books: [
    { title: 'Bar' },
  ]
});

// author.address is an instance of Address
// author.books is an instance of Books
// author.books.at(0) is an instance of Book

The events are triggered on new sets (setting/changing/removing values), and also further by bubbling up the events to the parent(s).

So a change in a particular Book will trigger another event in Books, and then to Author.

The comparison checks are not happening at the Model/Collection instance level anywhere.

If you do want that, I suggest doing it with RxJS operators:

import { map, distinctUntilChanged } from 'rxjs/operators';

author.get$()
  .pipe(
    map(model => model.name),
    distinctUntilChanged(),
  )
  // will trigger only when the Author's name has changed to another value
  .subscribe(authorName => console.log(authorName);
Read more comments on GitHub >

github_iconTop Results From Across the Web

Immutable Collections - GitHub
It is proposed to provide two families of interfaces that extend read-only collection interfaces: Immutable collections: ImmutableList , ImmutableSet , etc.
Read more >
3 Creating Immutable Lists, Sets, and Maps - Oracle Help Center
After you create an immutable instance of a collection, it holds the same data as long as a reference to it exists. If...
Read more >
Kotlin Immutable Collections - Baeldung
In this tutorial, we'll be looking at how to create immutable collections in Kotlin. First, we'll explore the types of immutability as well ......
Read more >
.NET Framework - Immutable Collections | Microsoft Learn
This simple design makes the immutable stack the simplest immutable collection. I show the differences between the mutable and immutable stacks further in...
Read more >
Immutable Collections should be Your Default
Java's standard library has utilities for creating unmodifiable copies, which are better than nothing;; VAVR works well for Java;; Guava is also ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found