Wszystko miało być zupełnie inaczej. Kilka dni temu podjąłem dość odważną decyzję, by standardowego PostgreSQL-a zamienić na technologię, wokół której kręcę się już od dłuższego czasu. Mam tutaj na myśli NoSQL-ową bazę danych RethinkDB. Dlaczego akurat tę? Kiedy myślę o modelu danych w mojej aplikacji, wydaje mi się, iż podejście z bazą NoSQL ma realny sens, ponieważ przechowywał będę luźno powiązane ze sobą (choć częściowo ustrukturyzowane) dokumenty. Dlaczego nie MongoDB, jak wszyscy? Bo mam tej bazie wiele do zarzucenia (i nie tylko ja), a RethinkDB uważam, za rozwiązanie dużo lepsze. O szczegółach pisałem już kiedyś na blogu.

Ale do rzeczy. Postanowiłem skoczyć na głęboką wodę i dołączyć Rethinka do mojego stosu technologicznego. Mam w końcu do dyspozycji elixirowego klienta, a nawet adapter do Ecto1. Znalazłem również bardzo dobry artykuł opisujący jak rozpocząć przygodę. Pierwsze przymiarki wyszły mi całkiem nieźle i właściwie byłem przekonany, że w czwartek wieczorem będę opisywał tutaj mój wielki sukces.

Tymczasem jest sobota i dopiero dzisiaj udało mi się przezwyciężyć pewne problemy, związane ze zmianą bazy. Nie ukrywam, że po drodze miałem zamiar już się poddać i wrócić do "zwykłego" RDBMS-a. Nie ukrywam że nadal nie jestem przekonany, czy tego nie zrobię, mimo trzech dni frustracji i wysiłków włożonych w doprowadzeniu obecnej wersji do życia.

Tak to bowiem jest z tymi "nowymi" technologiami (możemy je też nazywać niszowymi czy hipsterskimi; grunt że nie funkcjonują w mainstreamie). Wyglądają świetnie i już wydaje się, że rozwiążą wszystkie nasze problemy, ale... Co prawda sam RethinkDB jest production-ready, natomiast oficjalnie wspieranymi klientami/sterownikami są jedynie te w JavaScripcie, Pythonie, Rubym i ostatnio w Javie. Klient w Elixirze też istnieje i ma się dobrze (wspiera chyba wszystkie możliwości bazy), ale już adapter do Ecto niekoniecznie. W związku z tym będę miał do dyspozycji znacznie uboższy zakres funkcjonalności (na przykład nie ma w nim relacji pomiędzy modelami), a większość zapytań będę musiał pisać ręcznie.

Niekoniecznie jest to coś złego. Zwolennicy rozwiązań takich jak yesql byliby wręcz zachwyceni – w końcu według nich zapytania powinno się tworzyć wyłącznie ręcznie, bez posiłkowania się pośredniczącymi bibliotekami. Ja? Nie jestem taki pewien. Przede wszystkim może się to skończyć zbyt dużym skupieniem się na rozwiązywaniu problemów które by mnie nie dotyczyły, gdybym użył Postgresa, zamiast skupiać się na rozwoju samej aplikacji. W tym momencie jestem na etapie uważania, że podejmę to ryzyko. Więc RethinkDB pewnie zostanie.

Zmiany, o których piszę, w tym momencie nie są w masterze, ale można je podejrzeć w odpowiednim branchu.

Show us some code!

Jeśli ktoś czyta tego bloga to pewnie może się zastanawiać, czy w ogóle zamierzam tutaj wklejać jakiś kod. W końcu prawie wszyscy inni uczestnicy Daj Się Poznać to robią.

Odpowiedź brzmi: i tak, i nie. Z pewnością nie planuję, by ten blog stał się kursem Elixira. Od tego są inne, lepsze źródła, a ja nie jestem najlepszy w tłumaczeniu. Problemy tutaj opisane będą raczej średnio-zaawansowane, ponieważ moje doświadczenie z tym językiem nie jest duże, ale też nie jest tak, że dopiero się go uczę. Poza tym większość z was zapewne Elixira nie zna, więc jakieś listingi niewiele mu powiedzą (tak jak średnio dużo mi mówią te w C#).

Ale proszę bardzo: dla tych, którzy muszą mieć kod, oto mix task, który napisałem, by utworzył mi w bazie tabele wskazane w tablicy zwracanej przez metodę RethinkDatabase.tables. Jest to coś w rodzaju migracji, ponieważ RethinkDB sam tabel (oraz indeksów, ale tych na razie nie dopisałem), więc trzeba je utworzyć samodzielnie2.

defmodule Mix.Tasks.Rdb.Load do
  use Mix.Task
  import RethinkDB.Query
  alias RethinkDatabase, as: RDB

  def run(_args) do
    create_tables
  end

  def create_tables do
    RDB.start_link(Application.get_env(:erreka, :rdb))
    Enum.each(RethinkDatabase.tables, fn(table_name) ->
      query = table_list
        |> contains(table_name)
        |> branch("", do_r(fn -> table_create(table_name) end))
      case RDB.run(query) do
        %RethinkDB.Record{data: %{"tables_created" => 1}} ->
          IO.puts "Created table `#{table_name}`."
        %RethinkDB.Record{data: ""} ->
          IO.puts "Table `#{table_name}` already exists."
      end
    end)
  end
end

  1. Ecto jest czymś w rodzaju Sequela dla Phoenixa. Czy też tego waszego EntityFrameworka w .NET. 

  2. Jest to jedna z tych rzeczy, których adapter Ecto zupełnie nie ma, a moim zdaniem w jakiejś formie mieć powinien.