# Overview

This a CLI tool for bootstrapping the development process of a catalog-like
service. It generates a Postgres database schema together with corresponding
PostGraphile Smart Tags from an array of content type publish format schemas.

This tool will output two files:

```bash
${YOUR_PROJECT}
├── migrations
│   └── current.sql
└── src
    └── plugins
        └── smart-tags-plugin.ts
```

**NOTE:** These files will be overwritten each time you run this tool.

# Usage

Example:

```bash
yarn mosaic publish-schema-to-db -i '/path/to/schemas/**/*-published-event.json' -o '/path/to/your/service/root'
```

# Assumptions and terminology

**Content metadata schema** - JSON schema describing the publish format for
content metadata (movie, collection, TV show etc.).

When mapping the publish message JSON schema to a Postgres schema the following
conventions are used (this applies for each defined content type).

**Content metadata schema** is decomposed into:

- **Content entity** - root entity of content metadata.
- An array of **primitive properties**.
- An array of **object properties**.
- A _relations_ table linking the content to other **content entities** (e.g.
  related items, genres).

## Customizing output

In addition to the general assumptions described above it is also possible to
customize schema generation per content type via postprocessors, see
`src/postprocessors`.

## Limitations

This tool assumes at most one level of nested objects in the input JSON schema.

SUPPORTED

```json
{
  "$schema": "http://json-schema.org/draft-04/schema",
  "properties": {
    "object_prop": {
      "type": "object",
      "properties": {
        "a": {
          "type": "string"
        },
        "b": {
          "type": "number"
        }
      }
    }
  }
}
```

NOT SUPPORTED

```json
{
  "$schema": "http://json-schema.org/draft-04/schema",
  "properties": {
    "object_prop": {
      "type": "object",
      "properties": {
        "a": {
          "type": "string"
        },
        "nested_object_prop": {
          "type": "object",
          "properties": {
            "b": {
              "type": "number"
            }
          }
        }
      }
    }
  }
}
```

Mapping of supported property types to DB constructs:

- primitive (string, int etc.) - primitive type field
- primitive array - array of primitive type
- object - 1-to-1
- object array - 1-to-many

# TODO

- Named indexes.
- Generate migrations.
  - https://github.com/michaelsogos/pg-diff
  - https://www.npmjs.com/package/pg-compare
  - https://databaseci.com/docs/migra
- Test table generators.
- Better logging.
- Support nullable (required/not required)
- Improve property exclusion logic

  Frank's comment:

  > Checked a bit on the implementation. The "ignored properties" seems to be
  > just a flat string list. So it is not possible to exclude propertyA from
  > movie but keep propertyB on TV show - right? In the used env variable I see
  > $schema,related_items. The schema part I understand (and I would even hard-code that potentially - or even exclude anything starting with $).
  > But for "related_items" I am very unsure about. The name can be custom, it
  > can change over time etc. I would rather say to hard code the \$ part. And
  > then have some callback function that you can implement in code that would
  > get the content type (and for objects also that type). And then this could
  > be customized to exclude if it is needed.
