Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Modèle de données

docs/data_model.livemd

Modèle de données

my_app_root = Path.join(__DIR__, "..")

Mix.install(
  [
    {:my_app, path: my_app_root, env: :dev},
    {:kino, "~> 0.10.0"}
  ],
  config_path: Path.join(my_app_root, "config/config.exs"),
  lockfile: Path.join(my_app_root, "mix.lock")
)

Exploration

Au coeur du modèle du PAN il y a le dataset:

# shut down debug logging (including Ecto/SQL)
Logger.configure(level: :warning)

Ecto.Adapters.SQL.query!(
  DB.Repo,
  "SELECT id, datagouv_id, slug, custom_title FROM dataset"
)
|> Kino.DataTable.new()

L’url de chaque dataset s’appuie sur son slug (url unique fournie par data gouv):

Ecto.Adapters.SQL.query!(
  DB.Repo,
  "SELECT 'http://localhost:5000/datasets/' || slug as url FROM dataset"
)
|> Kino.DataTable.new()

À chaque dataset, sont associées une ou plusieurs ressources (avec leur format, leur url propre, leur titre etc):

Ecto.Adapters.SQL.query!(
  DB.Repo,
  """
  SELECT
    dataset.id as d_id,
    resource.id as r_id,
    'http://localhost:5000/resources/' || resource.id as r_url,
    resource.format as r_format,
    resource.title as r_title,
    dataset.datagouv_id as d_gid,
    dataset.slug as d_slug,
    dataset.custom_title as d_title

  FROM (SELECT * from dataset ORDER BY id desc limit 3) dataset

  LEFT JOIN resource resource on resource.dataset_id = dataset.id
  ORDER by dataset.id asc
  """
)
|> Kino.DataTable.new()

On va se concentrer sur un dataset en particulier:

well_known_slug = "Réseau urbain Bibus"

Ecto.Adapters.SQL.query!(
  DB.Repo,
  """
  SELECT
    resource.format as r_format,
    resource.title as r_title

  FROM (SELECT * from dataset WHERE custom_title = $1) dataset

  LEFT JOIN resource resource on resource.dataset_id = dataset.id
  ORDER by resource.title asc
  """,
  [well_known_slug]
)
|> Kino.DataTable.new()

Puis sur une ressource en particulier:

well_known_title = "Réseau urbain Bibus"

%{rows: [[gtfs_resource_id]]} =
  Ecto.Adapters.SQL.query!(
    DB.Repo,
    """
    SELECT
      resource.id as r_id

    FROM (SELECT * from dataset WHERE custom_title = $1) dataset

    LEFT JOIN resource resource on resource.dataset_id = dataset.id

    where resource.format = 'GTFS'
    """,
    [well_known_title]
  )

%{rows: [[well_known_dataset_slug, datagouv_id]]} =
  Ecto.Adapters.SQL.query!(
    DB.Repo,
    """
    SELECT dataset.slug, dataset.datagouv_id from dataset WHERE custom_title = $1
    """,
    [well_known_title]
  )

"""

La ressource avec id #{gtfs_resource_id} est visible via http://localhost:5000/resources/#{gtfs_resource_id}

Son historique est visualisé sur la page du dataset, qui est:
- http://localhost:5000/datasets/#{well_known_dataset_slug}#backed-up-resources (via le slug)
- http://localhost:5000/datasets/#{datagouv_id} (via le data gouv id)
"""
|> Kino.Markdown.new()

À chaque Resource est associée N ResourceHistory, qui représentent les versions historisées de la ressource (dont on détecte les changements). C’est ce qui est affiché sur la page du Dataset actuellement.

# this is displayed on the dataset page, not on the resource detail page
data =
  Ecto.Adapters.SQL.query!(
    DB.Repo,
    """
    SELECT * from resource_history WHERE resource_id = $1

    ORDER BY inserted_at DESC
    """,
    [gtfs_resource_id]
  )

data |> Kino.DataTable.new()

On peut obtenir la dernière version d’une Resource via Ecto au lieu de faire du SQL, comme suit:

import Ecto.Query

resource_history_query =
  from(rh in DB.ResourceHistory,
    where: rh.resource_id == ^gtfs_resource_id,
    order_by: {:desc, rh.inserted_at},
    limit: 1
  )

resource_history_query
|> DB.Repo.one()

On note les associations validations et metadata en particulier (tout en bas).

À partir de la ResourceHistory on peut obtenir les metadatas associées (DB.ResourceMetadata) qui sont en fait également liées chacune à une DB.MultiValidation (dont on voit l’id multi_validation_id ci-dessous):

resource_history_query
|> preload(:metadata)
|> DB.Repo.one()
|> Map.take([:metadata])

On peut également obtenir les validations DB.MultiValidation:

resource_history_query
|> preload(:validations)
|> DB.Repo.one()
|> Map.fetch!(:validations)
|> Kino.DataTable.new()

En utilisant la commande mix ecto.gen.erd --output-path=ecto_erd.mmd et en filtrant un peu à la main, on obtient cette vue très simplifiée de ce qui est discuté ci-dessus:

erDiagram
  dataset ||--|{ resource : ""
  multi_validation ||--o| resource_metadata : ""
  resource ||--|{ multi_validation : ""
  resource ||--|{ resource_history : ""
  resource ||--|{ resource_metadata : ""
  resource_history ||--|{ multi_validation : ""
  resource_history ||--|{ resource_metadata : ""

À suivre!