Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Feature/notion models and commands #121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
johguentner wants to merge 82 commits into dev
base: dev
Choose a base branch
Loading
from feature/notion-models-and-commands

Conversation

Copy link
Member

@johguentner johguentner commented Feb 16, 2023

No description provided.

kasperhartwich reacted with heart emoji
johguentner and others added 12 commits February 2, 2023 14:58
- command for creating NotionModels
- add Notion Models for simple interation with Notion databases
- add NotionQueryBuilder for simple query-behaviour for Notion databases (similar to eloquent)
- add filterbags instead of collections
- some entities have parents or expose user-ids, without additional information
- by resolving these within the "endpoint" (not a real notion enpoint) ``Resolve::class``, the additional information can be easily obtained
Copy link

what-the-diff bot commented Feb 16, 2023

  • Added a new artisan command to generate Notion Models
  • Fixed the issue with Text and Title properties not being converted to text when using asText() method on them
  • Created an abstract class for all notion models that will be generated by the artisan command in step 1 above, this is so we can have some common functionality between all of our models (like caching) without having to repeat ourselves over and over again.
  • Added a new class NotionQueryBuilder
  • This is used to query the notion database and return results as collections of models or json
  • The model classes can be configured with filters, sortings etc which are then applied when querying the db
  • Results from queries are cached for configurable durations (defaults to 1 hour) using Laravel's cache system

johguentner and others added 8 commits February 16, 2023 12:51
@johguentner johguentner added this to the 🍩 1.2.0 milestone Feb 16, 2023
johguentner and others added 27 commits May 2, 2023 14:12
- remove adding query to file-name
- instead add short hash of query to file-name
- or (if given) allow user to set a specific name for upcoming query
- additionally save header, method and payload within the snapshot
- ... rebuild snapshots for comments (due to changed file-naming structure)
Copy link
Contributor

Hey,
I'm working on something similar using calebporzio/sushi so a bit different approach. It loads the whole Notion database in SQLite and makes that one usable via Eloquent.

I have tried to find the spot where you cast the page properties to model attributes but can't find it!? 🤔
In case you are interested, here's my approach:

That's the trait with all the abstracted logic to link an eloquent model to a notion database.

<?php
namespace App\Models\Concerns;
use BackedEnum;
use FiveamCode\LaravelNotionApi\Endpoints\Database;
use FiveamCode\LaravelNotionApi\Entities\Collections\PageCollection;
use FiveamCode\LaravelNotionApi\Entities\Page;
use FiveamCode\LaravelNotionApi\Entities\Properties\Checkbox;
use FiveamCode\LaravelNotionApi\Entities\Properties\MultiSelect;
use FiveamCode\LaravelNotionApi\Entities\Properties\Number;
use FiveamCode\LaravelNotionApi\Entities\Properties\Property;
use FiveamCode\LaravelNotionApi\Entities\Properties\Relation;
use FiveamCode\LaravelNotionApi\Entities\Properties\Select;
use FiveamCode\LaravelNotionApi\Entities\Properties\Text;
use FiveamCode\LaravelNotionApi\Entities\Properties\Title;
use FiveamCode\LaravelNotionApi\Entities\Properties\Url;
use FiveamCode\LaravelNotionApi\Entities\PropertyItems\SelectItem;
use FiveamCode\LaravelNotionApi\Notion;
use FiveamCode\LaravelNotionApi\Query\StartCursor;
use Generator;
use GuzzleHttp\Psr7\Uri;
use Illuminate\Support\LazyCollection;
use OutOfRangeException;
use Ramsey\Uuid\Uuid;
use Sushi\Sushi;
trait HasNotionDatabase
{
 use Sushi;
 abstract protected function getNotionDatabaseId(): string;
 abstract protected function getNotionPageData(Page $page): array;
 protected function getNotionDatabase(): Database
 {
 return app(Notion::class)->database($this->getNotionDatabaseId());
 }
 protected function queryNotionDatabase(?StartCursor $cursor = null): PageCollection
 {
 return $cursor !== null
 ? $this->getNotionDatabase()->offset($cursor)->query()
 : $this->getNotionDatabase()->query();
 }
 protected function getNotionPages(): LazyCollection
 {
 return LazyCollection::make(function (): Generator {
 $cursor = null;
 do {
 $response = $this->queryNotionDatabase($cursor);
 $cursor = $response->nextCursor();
 $pages = $response->asCollection();
 foreach ($pages as $page) {
 yield $page;
 }
 } while ($response->hasMoreEntries());
 });
 }
 protected function getNotionPropertyValue(Page $page, string $key): mixed
 {
 $property = $page->getProperty($key);
 return $property === null
 ? null
 : $this->castNotionProperty($property);
 }
 protected function castNotionProperty(Property $property): mixed
 {
 return match ($property::class) {
 Checkbox::class => $property->getContent(),
 Select::class => $property->getContent()->getName(),
 MultiSelect::class => $property->getContent()
 ->map(fn (SelectItem $item) => $item->getName())
 ->all(),
 Title::class, Text::class => $property->getContent()->getPlainText() ?: null,
 Url::class => new Uri($property->getContent()),
 Number::class => $property->getContent(),
 Relation::class => $property->getContent()
 ->pluck('id')
 ->map(fn (string $id) => Uuid::fromString($id))
 ->all(),
 default => throw new OutOfRangeException('Missing notion property cast for: '.$property::class),
 };
 }
 public function getRows(): array
 {
 return $this->getNotionPages()
 ->map($this->getNotionPageData(...))
 ->map(static function (array $attributes): array {
 return collect($attributes)
 ->map(static function (mixed $value) {
 if ($value === null) {
 return null;
 }
 if (is_array($value)) {
 return json_encode($value);
 }
 if ($value instanceof Uri) {
 return (string) $value;
 }
 if ($value instanceof BackedEnum) {
 return $value->value;
 }
 return $value;
 })
 ->all();
 })
 ->collect()
 ->all();
 }
}

And here's an example model - with working relation, casting and all we love about Eloquent:

<?php
namespace App\Models;
use App\Enums\Alignment;
use App\Enums\Race;
use App\Enums\Sex;
use App\Models\Concerns\HasNotionDatabase;
use App\Renderers\PageRenderer;
use Carbon\CarbonInterval;
use FiveamCode\LaravelNotionApi\Entities\Page;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
class Character extends Model
{
 use HasNotionDatabase;
 protected $casts = [
 'aliases' => 'array',
 'race' => Race::class,
 'sex' => Sex::class,
 'alignment' => Alignment::class,
 'is_deceased' => 'bool',
 'born_at' => 'int',
 'died_at' => 'int',
 ];
 public function partner(): BelongsTo
 {
 return $this->belongsTo(Character::class, 'partner_id', 'id');
 }
 public function getNotionDatabaseId(): string
 {
 return 'c10fea27034e4de993201eb9323cd885';
 }
 public function getNotionPageData(Page $page): array
 {
 return [
 'id' => $page->getId(),
 'name' => $page->getTitle(),
 'aliases' => Str::of($this->getNotionPropertyValue($page, 'Alias'))
 ->explode(',')
 ->map(fn (string $alias): string => trim($alias))
 ->filter()
 ->all(),
 'race' => $this->getNotionPropertyValue($page, 'Race'),
 'sex' => $this->getNotionPropertyValue($page, 'Sex'),
 'alignment' => $this->getNotionPropertyValue($page, 'Alignment'),
 'is_deceased' => $this->getNotionPropertyValue($page, 'Deceased'),
 'born_at' => (int) $this->getNotionPropertyValue($page, 'Born at'),
 'died_at' => (int) $this->getNotionPropertyValue($page, 'Died at'),
 // relations
 'partner_id' => Arr::first($this->getNotionPropertyValue($page, 'Partner')),
 // links
 '5etools_url' => $this->getNotionPropertyValue($page, '5e.tools'),
 'fandom_url' => $this->getNotionPropertyValue($page, 'Fandom'),
 // content
 'content' => Cache::remember(
 key: "{$this->getTable()}.{$page->getId()}.content",
 ttl: CarbonInterval::day(),
 callback: fn () => PageRenderer::make($page)->render()
 ),
 ];
 }
}
MasihTak reacted with heart emoji

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /