From b8687b18856ca711756aa2c703ebb2327982f2c5 Mon Sep 17 00:00:00 2001 From: Takahiro Sato Date: Wed, 30 Oct 2024 22:25:35 +0900 Subject: [PATCH 1/2] Revert "Revert "Update e2e test"" --- .github/workflows/test.yml | 32 +- .gitignore | 3 + .tool-versions | 2 +- .../20241012091142_create_tables.sql | 28 +- backend/db/postgresql/query.sql | 2 +- backend/db/postgresql/schema.sql | 335 ++++++ .../20241012091142_create_tables.sql | 74 ++ backend/db/sqlite/query.sql | 195 +++ backend/db/sqlite/schema.sql | 61 + backend/go.mod | 1 + backend/go.sum | 2 + backend/gqlgen.yml | 4 +- backend/internal/app/app.go | 7 +- backend/internal/app/wire.go | 26 + backend/internal/app/wire_gen.go | 36 + backend/internal/config/config.go | 44 +- backend/internal/context/values/db_tx..go | 22 + backend/internal/context/values/db_tx.go | 22 - .../internal/context/values/postgres_tx.go | 22 + backend/internal/db/{ => postgres}/db.go | 2 +- backend/internal/db/{ => postgres}/models.go | 30 +- .../internal/db/{ => postgres}/query.sql.go | 50 +- backend/internal/db/sqlite/db.go | 31 + backend/internal/db/sqlite/models.go | 69 ++ backend/internal/db/sqlite/query.sql.go | 597 +++++++++ backend/internal/db/tx.go | 37 +- .../infra/postgres/item/diagramitem.go | 34 +- .../internal/infra/postgres/item/gistitem.go | 34 +- .../infra/postgres/settings/settings.go | 82 +- .../internal/infra/postgres/share/share.go | 24 +- backend/internal/infra/sqlite/db.go | 64 + .../internal/infra/sqlite/item/diagramitem.go | 178 +++ .../internal/infra/sqlite/item/gistitem.go | 161 +++ .../infra/sqlite/settings/settings.go | 130 ++ backend/internal/infra/sqlite/share/share.go | 145 +++ .../presentation/graphql/generated.go | 1062 ++++++++++++----- .../internal/presentation/graphql/query.go | 4 - backend/justfile | 27 +- backend/sqlc.yaml | 13 +- frontend/e2e/textusm.spec.ts | 59 +- frontend/package-lock.json | 30 +- frontend/package.json | 8 +- frontend/playwright.config.ts | 6 +- frontend/src/elm/Main.elm | 104 +- frontend/tsconfig.json | 5 +- 45 files changed, 3347 insertions(+), 557 deletions(-) create mode 100644 backend/db/postgresql/schema.sql create mode 100644 backend/db/sqlite/migrations/20241012091142_create_tables.sql create mode 100644 backend/db/sqlite/query.sql create mode 100644 backend/db/sqlite/schema.sql create mode 100644 backend/internal/context/values/db_tx..go delete mode 100644 backend/internal/context/values/db_tx.go create mode 100644 backend/internal/context/values/postgres_tx.go rename backend/internal/db/{ => postgres}/db.go (97%) rename backend/internal/db/{ => postgres}/models.go (89%) rename backend/internal/db/{ => postgres}/query.sql.go (92%) create mode 100644 backend/internal/db/sqlite/db.go create mode 100644 backend/internal/db/sqlite/models.go create mode 100644 backend/internal/db/sqlite/query.sql.go create mode 100644 backend/internal/infra/sqlite/db.go create mode 100644 backend/internal/infra/sqlite/item/diagramitem.go create mode 100644 backend/internal/infra/sqlite/item/gistitem.go create mode 100644 backend/internal/infra/sqlite/settings/settings.go create mode 100644 backend/internal/infra/sqlite/share/share.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b12945bf6..88de20062 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -41,6 +41,10 @@ jobs: - uses: actions/setup-node@v4 with: node-version-file: ".tool-versions" + - uses: extractions/setup-just@v2 + - uses: actions/setup-go@v5 + with: + go-version-file: "backend/go.mod" - uses: actions/labeler@v5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" @@ -79,6 +83,14 @@ jobs: - name: Run Tests working-directory: frontend run: npm run test + - name: Migrate database + run: | + go install github.com/amacneil/dbmate@latest + just migrate + working-directory: backend + env: + DB_TYPE: sqlite + DATABASE_URL: sqlite3:textusm.db - name: Setup E2E run: npm run test:e2e:init working-directory: frontend @@ -89,12 +101,15 @@ jobs: API_ROOT: ${{ secrets.API_ROOT }} WEB_ROOT: ${{ secrets.WEB_ROOT }} APP_VERSION: "" - FIREBASE_API_KEY: ${{ secrets.FIREBASE_API_KEY }} - FIREBASE_AUTH_DOMAIN: ${{ secrets.FIREBASE_AUTH_DOMAIN }} - FIREBASE_PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }} - FIREBASE_STORAGE_BUCKET: ${{ secrets.FIREBASE_STORAGE_BUCKET }} - FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }} - FIREBASE_AUTH_EMULATOR_HOST: "" + FIREBASE_API_KEY: textusm + FIREBASE_AUTH_DOMAIN: textusm + FIRESTORE_EMULATOR_HOST: "localhost:8082" + FIREBASE_PROJECT_ID: textusm + FIREBASE_STORAGE_BUKET: textusm.appspot.com + FIREBASE_STORAGE_EMULATOR_HOST: "localhost:9199" + FIREBASE_AUTH_EMULATOR_HOST: "localhost:9099" + FIREBASE_APP_ID: dev + STORAGE_BUCKET_NAME: textusm.appspot.com SENTRY_ENABLE: "0" SENTRY_DSN: ${{ secrets.SENTRY_DSN }} SENTRY_RELEASE: ${{ steps.package-version.outputs.current-version}} @@ -104,6 +119,11 @@ jobs: MONITOR_ENABLE: "0" USE_HTTPS: "0" REPO_BUTTON_URL: "" + API_VERSION: v0.14.8 + PORT: 8081 + GO_ENV: development + DATABASE_URL: textusm.db + DB_TYPE: sqlite backend-test: name: backend_test diff --git a/.gitignore b/.gitignore index 9c0130a21..cfe1369a2 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,6 @@ certs/* backend/tmp/ data firebase-export-* + +*.sqlite3 +*.db diff --git a/.tool-versions b/.tool-versions index 778aa680f..8f2c6ad0a 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ -nodejs 22.2.0 +nodejs 20.18.0 golang 1.23.0 elm 0.19.1 just 1.36.0 diff --git a/backend/db/postgresql/migrations/20241012091142_create_tables.sql b/backend/db/postgresql/migrations/20241012091142_create_tables.sql index 2e3d1d54e..4d66ef0c6 100644 --- a/backend/db/postgresql/migrations/20241012091142_create_tables.sql +++ b/backend/db/postgresql/migrations/20241012091142_create_tables.sql @@ -59,27 +59,27 @@ CREATE TABLE settings ( id bigserial PRIMARY KEY, uid varchar NOT NULL, - activity_color varchar, - activity_background_color varchar, - background_color varchar, + activity_color varchar NOT NULL, + activity_background_color varchar NOT NULL, + background_color varchar NOT NULL, diagram diagram NOT NULL, - height int, - font varchar, - line_color varchar, - label_color varchar, + height int NOT NULL, + font varchar NOT NULL, + line_color varchar NOT NULL, + label_color varchar NOT NULL, lock_editing boolean, text_color varchar, toolbar boolean, scale real, show_grid boolean, - story_color varchar, - story_background_color varchar, - task_color varchar, - task_background_color varchar, - width int, + story_color varchar NOT NULL, + story_background_color varchar NOT NULL, + task_color varchar NOT NULL, + task_background_color varchar NOT NULL, + width int NOT NULL, zoom_control boolean, - created_at timestamp DEFAULT NOW(), - updated_at timestamp DEFAULT NOW() + created_at timestamp DEFAULT NOW() NOT NULL, + updated_at timestamp DEFAULT NOW() NOT NULL ); CREATE UNIQUE INDEX items_uid_location_diagram_id_idx ON items (uid, location, diagram_id); diff --git a/backend/db/postgresql/query.sql b/backend/db/postgresql/query.sql index 5778f4db9..92b890383 100644 --- a/backend/db/postgresql/query.sql +++ b/backend/db/postgresql/query.sql @@ -175,4 +175,4 @@ SET width = $16, zoom_control = $17 WHERE - diagram = $2; + diagram = $18; diff --git a/backend/db/postgresql/schema.sql b/backend/db/postgresql/schema.sql new file mode 100644 index 000000000..aa6a1d9ee --- /dev/null +++ b/backend/db/postgresql/schema.sql @@ -0,0 +1,335 @@ +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET transaction_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: diagram; Type: TYPE; Schema: public; Owner: - +-- + +CREATE TYPE public.diagram AS ENUM ( + 'USER_STORY_MAP', + 'OPPORTUNITY_CANVAS', + 'BUSINESS_MODEL_CANVAS', + 'FOURLS', + 'START_STOP_CONTINUE', + 'KPT', + 'USER_PERSONA', + 'MIND_MAP', + 'EMPATHY_MAP', + 'SITE_MAP', + 'GANTT_CHART', + 'IMPACT_MAP', + 'ER_DIAGRAM', + 'KANBAN', + 'TABLE', + 'SEQUENCE_DIAGRAM', + 'FREEFORM', + 'USE_CASE_DIAGRAM', + 'KEYBOARD_LAYOUT' +); + + +-- +-- Name: location; Type: TYPE; Schema: public; Owner: - +-- + +CREATE TYPE public.location AS ENUM ( + 'SYSTEM', + 'GIST' +); + + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: items; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.items ( + id bigint NOT NULL, + uid character varying NOT NULL, + diagram_id uuid, + location public.location NOT NULL, + diagram public.diagram NOT NULL, + is_bookmark boolean, + is_public boolean, + title character varying, + text text NOT NULL, + thumbnail text, + created_at timestamp without time zone DEFAULT now(), + updated_at timestamp without time zone DEFAULT now() +); + +ALTER TABLE ONLY public.items FORCE ROW LEVEL SECURITY; + + +-- +-- Name: items_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.items_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.items_id_seq OWNED BY public.items.id; + + +-- +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.schema_migrations ( + version character varying(128) NOT NULL +); + + +-- +-- Name: settings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.settings ( + id bigint NOT NULL, + uid character varying NOT NULL, + activity_color character varying NOT NULL, + activity_background_color character varying NOT NULL, + background_color character varying NOT NULL, + diagram public.diagram NOT NULL, + height integer NOT NULL, + font character varying NOT NULL, + line_color character varying NOT NULL, + label_color character varying NOT NULL, + lock_editing boolean, + text_color character varying, + toolbar boolean, + scale real, + show_grid boolean, + story_color character varying NOT NULL, + story_background_color character varying NOT NULL, + task_color character varying NOT NULL, + task_background_color character varying NOT NULL, + width integer NOT NULL, + zoom_control boolean, + created_at timestamp without time zone DEFAULT now() NOT NULL, + updated_at timestamp without time zone DEFAULT now() NOT NULL +); + +ALTER TABLE ONLY public.settings FORCE ROW LEVEL SECURITY; + + +-- +-- Name: settings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.settings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.settings_id_seq OWNED BY public.settings.id; + + +-- +-- Name: share_conditions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.share_conditions ( + id bigint NOT NULL, + hashkey character varying NOT NULL, + uid character varying NOT NULL, + diagram_id uuid, + location public.location NOT NULL, + allow_ip_list character varying[], + allow_email_list character varying[], + expire_time bigint, + password character varying, + token character varying NOT NULL, + created_at timestamp without time zone DEFAULT now(), + updated_at timestamp without time zone DEFAULT now() +); + +ALTER TABLE ONLY public.share_conditions FORCE ROW LEVEL SECURITY; + + +-- +-- Name: share_conditions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.share_conditions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: share_conditions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.share_conditions_id_seq OWNED BY public.share_conditions.id; + + +-- +-- Name: items id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.items ALTER COLUMN id SET DEFAULT nextval('public.items_id_seq'::regclass); + + +-- +-- Name: settings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.settings ALTER COLUMN id SET DEFAULT nextval('public.settings_id_seq'::regclass); + + +-- +-- Name: share_conditions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.share_conditions ALTER COLUMN id SET DEFAULT nextval('public.share_conditions_id_seq'::regclass); + + +-- +-- Name: items items_diagram_id_key; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.items + ADD CONSTRAINT items_diagram_id_key UNIQUE (diagram_id); + + +-- +-- Name: items items_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.items + ADD CONSTRAINT items_pkey PRIMARY KEY (id); + + +-- +-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.schema_migrations + ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); + + +-- +-- Name: settings settings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.settings + ADD CONSTRAINT settings_pkey PRIMARY KEY (id); + + +-- +-- Name: share_conditions share_conditions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.share_conditions + ADD CONSTRAINT share_conditions_pkey PRIMARY KEY (id); + + +-- +-- Name: items_uid_location_diagram_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX items_uid_location_diagram_id_idx ON public.items USING btree (uid, location, diagram_id); + + +-- +-- Name: settings_uid_diagram_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX settings_uid_diagram_idx ON public.settings USING btree (uid, diagram); + + +-- +-- Name: share_hashkey_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX share_hashkey_idx ON public.share_conditions USING btree (hashkey); + + +-- +-- Name: share_uid_location_diagram_id_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX share_uid_location_diagram_id_idx ON public.share_conditions USING btree (uid, location, diagram_id); + + +-- +-- Name: items; Type: ROW SECURITY; Schema: public; Owner: - +-- + +ALTER TABLE public.items ENABLE ROW LEVEL SECURITY; + +-- +-- Name: items items_uid_policy; Type: POLICY; Schema: public; Owner: - +-- + +CREATE POLICY items_uid_policy ON public.items USING (((uid)::text = current_setting(('app.uid'::character varying)::text))); + + +-- +-- Name: settings; Type: ROW SECURITY; Schema: public; Owner: - +-- + +ALTER TABLE public.settings ENABLE ROW LEVEL SECURITY; + +-- +-- Name: settings settings_uid_policy; Type: POLICY; Schema: public; Owner: - +-- + +CREATE POLICY settings_uid_policy ON public.settings USING (((uid)::text = current_setting(('app.uid'::character varying)::text))); + + +-- +-- Name: share_conditions; Type: ROW SECURITY; Schema: public; Owner: - +-- + +ALTER TABLE public.share_conditions ENABLE ROW LEVEL SECURITY; + +-- +-- Name: share_conditions share_conditions_uid_policy; Type: POLICY; Schema: public; Owner: - +-- + +CREATE POLICY share_conditions_uid_policy ON public.share_conditions USING (((uid)::text = current_setting(('app.uid'::character varying)::text))); + + +-- +-- PostgreSQL database dump complete +-- + + +-- +-- Dbmate schema migrations +-- + +INSERT INTO public.schema_migrations (version) VALUES + ('20241012091142'); diff --git a/backend/db/sqlite/migrations/20241012091142_create_tables.sql b/backend/db/sqlite/migrations/20241012091142_create_tables.sql new file mode 100644 index 000000000..0b99cd269 --- /dev/null +++ b/backend/db/sqlite/migrations/20241012091142_create_tables.sql @@ -0,0 +1,74 @@ +-- migrate:up +CREATE TABLE + items ( + id integer PRIMARY KEY, + uid text NOT NULL, + diagram_id text NOT NULL, + location text NOT NULL, + diagram text NOT NULL, + is_bookmark integer NOT NULL, + is_public integer NOT NULL, + title text, + text text NOT NULL, + thumbnail text, + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL + ); + +CREATE TABLE + share_conditions ( + id integer PRIMARY KEY, + hashkey text NOT NULL, + uid text NOT NULL, + diagram_id text NOT NULL, + location text NOT NULL, + allow_ip_list text, + allow_email_list text, + expire_time bigint, + password text, + token text NOT NULL, + created_at integer NOT NULL, + updated_at integer NOT NULL + ); + +CREATE TABLE + settings ( + id integer PRIMARY KEY, + uid text NOT NULL, + activity_color text NOT NULL, + activity_background_color text NOT NULL, + background_color text NOT NULL, + diagram text NOT NULL, + height integer NOT NULL, + font text NOT NULL, + line_color text NOT NULL, + label_color text NOT NULL, + lock_editing integer, + text_color text, + toolbar integer, + scale real NOT NULL, + show_grid integer, + story_color text NOT NULL, + story_background_color text NOT NULL, + task_color text NOT NULL, + task_background_color text NOT NULL, + width integer NOT NULL, + zoom_control integer, + created_at integer NOT NULL, + updated_at integer NOT NULL + ); + +CREATE UNIQUE INDEX items_uid_location_diagram_id_idx ON items (uid, location, diagram_id); + +CREATE UNIQUE INDEX settings_uid_diagram_idx ON settings (uid, diagram); + +CREATE UNIQUE INDEX share_hashkey_idx ON share_conditions (hashkey); + +CREATE UNIQUE INDEX share_uid_location_diagram_id_idx ON share_conditions (uid, location, diagram_id); + +-- migrate:down +DROP TABLE items; + +DROP TABLE share_conditions; + +DROP TABLE settings; diff --git a/backend/db/sqlite/query.sql b/backend/db/sqlite/query.sql new file mode 100644 index 000000000..921b7d7c8 --- /dev/null +++ b/backend/db/sqlite/query.sql @@ -0,0 +1,195 @@ +-- name: GetItem :one +SELECT + * +FROM + items +WHERE + uid = ? + AND location = ? + AND diagram_id = ?; + +-- name: ListItems :many +SELECT + * +FROM + items +WHERE + uid = ? + AND location = ? + AND is_public = ? + AND is_bookmark = ? +LIMIT + ? +OFFSET + ?; + +-- name: CreateItem :exec +INSERT INTO + items ( + uid, + diagram, + diagram_id, + is_bookmark, + is_public, + title, + text, + thumbnail, + location, + created_at, + updated_at + ) +VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: UpdateItem :exec +UPDATE items +SET + diagram = ?, + is_bookmark = ?, + is_public = ?, + title = ?, + text = ?, + thumbnail = ?, + location = ?, + updated_at = ? +WHERE + uid = ? + AND diagram_id = ?; + +-- name: DeleteItem :exec +DELETE FROM items +WHERE + uid = ? + AND diagram_id = ?; + +-- name: GetShareCondition :one +SELECT + * +FROM + share_conditions +WHERE + hashkey = ?; + +-- name: GetShareConditionItem :one +SELECT + * +FROM + share_conditions +WHERE + uid = ? + AND location = ? + AND diagram_id = ?; + +-- name: CreateShareCondition :exec +INSERT INTO + share_conditions ( + uid, + hashkey, + diagram_id, + location, + allow_ip_list, + allow_email_list, + expire_time, + password, + token, + created_at, + updated_at + ) +VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + +-- name: DeleteShareCondition :exec +DELETE FROM share_conditions +WHERE + hashkey = ?; + +-- name: DeleteShareConditionItem :exec +DELETE FROM share_conditions +WHERE + uid = ? + AND location = ? + AND diagram_id = ?; + +-- name: GetSettings :one +SELECT + * +FROM + settings +WHERE + uid = ? + AND diagram = ?; + +-- name: CreateSettings :exec +INSERT INTO + settings ( + uid, + activity_color, + activity_background_color, + background_color, + height, + diagram, + line_color, + label_color, + lock_editing, + text_color, + toolbar, + scale, + show_grid, + story_color, + story_background_color, + task_color, + task_background_color, + width, + zoom_control, + created_at, + updated_at + ) +VALUES + ( + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ? + ); + +-- name: UpdateSettings :exec +UPDATE settings +SET + activity_color = ?, + activity_background_color = ?, + background_color = ?, + height = ?, + line_color = ?, + label_color = ?, + lock_editing = ?, + text_color = ?, + toolbar = ?, + scale = ?, + show_grid = ?, + story_color = ?, + story_background_color = ?, + task_color = ?, + task_background_color = ?, + width = ?, + zoom_control = ?, + updated_at = ? +WHERE + uid = ? + AND diagram = ?; diff --git a/backend/db/sqlite/schema.sql b/backend/db/sqlite/schema.sql new file mode 100644 index 000000000..7de07958f --- /dev/null +++ b/backend/db/sqlite/schema.sql @@ -0,0 +1,61 @@ +CREATE TABLE IF NOT EXISTS "schema_migrations" (version varchar(255) primary key); +CREATE TABLE items ( + id integer PRIMARY KEY, + uid text NOT NULL, + diagram_id text NOT NULL, + location text NOT NULL, + diagram text NOT NULL, + is_bookmark integer NOT NULL, + is_public integer NOT NULL, + title text, + text text NOT NULL, + thumbnail text, + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL + ); +CREATE TABLE share_conditions ( + id integer PRIMARY KEY, + hashkey text NOT NULL, + uid text NOT NULL, + diagram_id text NOT NULL, + location text NOT NULL, + allow_ip_list text, + allow_email_list text, + expire_time bigint, + password text, + token text NOT NULL, + created_at integer NOT NULL, + updated_at integer NOT NULL + ); +CREATE TABLE settings ( + id integer PRIMARY KEY, + uid text NOT NULL, + activity_color text NOT NULL, + activity_background_color text NOT NULL, + background_color text NOT NULL, + diagram text NOT NULL, + height integer NOT NULL, + font text NOT NULL, + line_color text NOT NULL, + label_color text NOT NULL, + lock_editing integer, + text_color text, + toolbar integer, + scale real NOT NULL, + show_grid integer, + story_color text NOT NULL, + story_background_color text NOT NULL, + task_color text NOT NULL, + task_background_color text NOT NULL, + width integer NOT NULL, + zoom_control integer, + created_at integer NOT NULL, + updated_at integer NOT NULL + ); +CREATE UNIQUE INDEX items_uid_location_diagram_id_idx ON items (uid, location, diagram_id); +CREATE UNIQUE INDEX settings_uid_diagram_idx ON settings (uid, diagram); +CREATE UNIQUE INDEX share_hashkey_idx ON share_conditions (hashkey); +CREATE UNIQUE INDEX share_uid_location_diagram_id_idx ON share_conditions (uid, location, diagram_id); +-- Dbmate schema migrations +INSERT INTO "schema_migrations" (version) VALUES + ('20241012091142'); diff --git a/backend/go.mod b/backend/go.mod index 6647ff98f..66dcd1acb 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -15,6 +15,7 @@ require ( github.com/google/wire v0.6.0 github.com/jackc/pgx/v5 v5.7.1 github.com/kelseyhightower/envconfig v1.4.0 + github.com/mattn/go-sqlite3 v1.14.24 github.com/samber/lo v1.47.0 github.com/samber/mo v1.13.0 github.com/satori/go.uuid v1.2.0 diff --git a/backend/go.sum b/backend/go.sum index 70b5164bd..dcfe5d372 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -142,6 +142,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= diff --git a/backend/gqlgen.yml b/backend/gqlgen.yml index e8d80d12e..357f54a2b 100644 --- a/backend/gqlgen.yml +++ b/backend/gqlgen.yml @@ -6,9 +6,6 @@ exec: model: filename: internal/presentation/graphql/models.go package: graphql -resolver: - filename: internal/presentation/graphql/resolver.go - package: graphql autobind: [] models: Item: @@ -27,3 +24,4 @@ models: model: github.com/harehare/textusm/internal/presentation/graphql/union.DiagramItem Node: model: github.com/harehare/textusm/internal/presentation/graphql/interface.Node +omit_root_models: true diff --git a/backend/internal/app/app.go b/backend/internal/app/app.go index f25917327..c91008644 100644 --- a/backend/internal/app/app.go +++ b/backend/internal/app/app.go @@ -19,9 +19,12 @@ func Server() (server *http.Server, cleanup func(), err error) { DBType := os.Getenv("DB_TYPE") - if strings.ToLower(DBType) == "postgres" { + switch strings.ToLower(DBType) { + case "postgres": server, cleanup, err = InitializePostgresServer() - } else { + case "sqlite": + server, cleanup, err = InitializeSqliteServer() + default: server, cleanup, err = InitializeFirebaseServer() } diff --git a/backend/internal/app/wire.go b/backend/internal/app/wire.go index 10c7374eb..d8872c9ef 100644 --- a/backend/internal/app/wire.go +++ b/backend/internal/app/wire.go @@ -1,3 +1,4 @@ +//go:generate go install github.com/google/wire/cmd/wire@latest //go:build wireinject // +build wireinject @@ -20,6 +21,9 @@ import ( postgresItemRepo "github.com/harehare/textusm/internal/infra/postgres/item" postgresSettingsRepo "github.com/harehare/textusm/internal/infra/postgres/settings" postgresShareRepo "github.com/harehare/textusm/internal/infra/postgres/share" + sqliteItemRepo "github.com/harehare/textusm/internal/infra/sqlite/item" + sqliteSettingsRepo "github.com/harehare/textusm/internal/infra/sqlite/settings" + sqliteShareRepo "github.com/harehare/textusm/internal/infra/sqlite/share" "github.com/harehare/textusm/internal/presentation/api" resolver "github.com/harehare/textusm/internal/presentation/graphql" ) @@ -75,3 +79,25 @@ func InitializePostgresServer() (*http.Server, func(), error) { ) return &http.Server{}, func() {}, nil } + +func InitializeSqliteServer() (*http.Server, func(), error) { + wire.Build( + config.Set, + provideGithubClientID, + provideGithubClientSecret, + db.NewDBTx, + sqliteItemRepo.NewSqliteItemRepository, + sqliteItemRepo.NewSqliteGistItemRepository, + sqliteSettingsRepo.NewSqliteSettingsRepository, + sqliteShareRepo.NewSqliteShareRepository, + userRepo.NewFirebaseUserRepository, + service.NewService, + service.NewGistService, + service.NewSettingsService, + resolver.New, + api.New, + handler.NewHandler, + server.NewServer, + ) + return &http.Server{}, func() {}, nil +} diff --git a/backend/internal/app/wire_gen.go b/backend/internal/app/wire_gen.go index 5227bd657..bad68048e 100644 --- a/backend/internal/app/wire_gen.go +++ b/backend/internal/app/wire_gen.go @@ -20,6 +20,9 @@ import ( item2 "github.com/harehare/textusm/internal/infra/postgres/item" settings2 "github.com/harehare/textusm/internal/infra/postgres/settings" share2 "github.com/harehare/textusm/internal/infra/postgres/share" + item3 "github.com/harehare/textusm/internal/infra/sqlite/item" + settings3 "github.com/harehare/textusm/internal/infra/sqlite/settings" + share3 "github.com/harehare/textusm/internal/infra/sqlite/share" "github.com/harehare/textusm/internal/presentation/api" "github.com/harehare/textusm/internal/presentation/graphql" "net/http" @@ -93,6 +96,39 @@ func InitializePostgresServer() (*http.Server, func(), error) { }, nil } +func InitializeSqliteServer() (*http.Server, func(), error) { + env, err := config.NewEnv() + if err != nil { + return nil, nil, err + } + configConfig, err := config.NewConfig(env) + if err != nil { + return nil, nil, err + } + itemRepository := item3.NewSqliteItemRepository(configConfig) + shareRepository := share3.NewSqliteShareRepository(configConfig) + userRepository := user.NewFirebaseUserRepository(configConfig) + transaction := db.NewDBTx(configConfig) + clientID := provideGithubClientID(env) + clientSecret := provideGithubClientSecret(env) + serviceService := service.NewService(itemRepository, shareRepository, userRepository, transaction, clientID, clientSecret) + gistItemRepository := item3.NewSqliteGistItemRepository(configConfig) + gistService := service.NewGistService(gistItemRepository, transaction, clientID, clientSecret) + settingsRepository := settings3.NewSqliteSettingsRepository(configConfig) + settingsService := service.NewSettingsService(settingsRepository, transaction, clientID, clientSecret) + resolver := graphql.New(serviceService, gistService, settingsService, configConfig) + apiApi := api.New(serviceService, gistService, settingsService) + logger := config.NewLogger(env) + mux, err := handler.NewHandler(env, configConfig, resolver, apiApi, logger) + if err != nil { + return nil, nil, err + } + httpServer, cleanup := server.NewServer(mux, env, configConfig) + return httpServer, func() { + cleanup() + }, nil +} + // wire.go: func provideGithubClientID(env *config.Env) github.ClientID { diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index cfdf830da..a62c761de 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -2,6 +2,7 @@ package config import ( "context" + "database/sql" "encoding/base64" "log/slog" @@ -11,6 +12,7 @@ import ( "github.com/google/wire" "github.com/jackc/pgx/v5/pgxpool" + _ "github.com/mattn/go-sqlite3" "google.golang.org/api/option" ) @@ -18,6 +20,7 @@ type Config struct { FirebaseApp *firebase.App FirestoreClient *firestore.Client PostgresConn *pgxpool.Pool + SqlConn *sql.Conn StorageClient *storage.Client } @@ -116,18 +119,36 @@ func NewConfig(env *Env) (*Config, error) { return nil, err } - var conn *pgxpool.Pool + var ( + pgConn *pgxpool.Pool + sqlConn *sql.Conn + ) if env.DatabaseURL != "" { - cfg, err := pgxpool.ParseConfig(env.DatabaseURL) - if err != nil { - return nil, err - } - - conn, err = pgxpool.NewWithConfig(ctx, cfg) - - if err != nil { - return nil, err + if env.DBType == "sqlite" { + db, err := sql.Open("sqlite3", env.DatabaseURL) + + if err != nil { + return nil, err + } + + conn, err := db.Conn(ctx) + + if err != nil { + return nil, err + } + sqlConn = conn + } else { + cfg, err := pgxpool.ParseConfig(env.DatabaseURL) + if err != nil { + return nil, err + } + + pgConn, err = pgxpool.NewWithConfig(ctx, cfg) + + if err != nil { + return nil, err + } } } @@ -135,7 +156,8 @@ func NewConfig(env *Env) (*Config, error) { FirebaseApp: app, FirestoreClient: firestore, StorageClient: storage, - PostgresConn: conn, + PostgresConn: pgConn, + SqlConn: sqlConn, } return &config, nil diff --git a/backend/internal/context/values/db_tx..go b/backend/internal/context/values/db_tx..go new file mode 100644 index 000000000..e2876634d --- /dev/null +++ b/backend/internal/context/values/db_tx..go @@ -0,0 +1,22 @@ +package values + +import ( + "context" + "database/sql" + + "github.com/samber/mo" +) + +type dbTxKey struct{} + +func GetDBTx(ctx context.Context) mo.Option[*sql.Tx] { + v := ctx.Value(dbTxKey{}) + if v == nil { + return mo.None[*sql.Tx]() + } + return mo.Some(v.(*sql.Tx)) +} + +func WithDBTx(ctx context.Context, tx *sql.Tx) context.Context { + return context.WithValue(ctx, dbTxKey{}, tx) +} diff --git a/backend/internal/context/values/db_tx.go b/backend/internal/context/values/db_tx.go deleted file mode 100644 index 5015b0291..000000000 --- a/backend/internal/context/values/db_tx.go +++ /dev/null @@ -1,22 +0,0 @@ -package values - -import ( - "context" - - "github.com/jackc/pgx/v5" - "github.com/samber/mo" -) - -type dbTxKey struct{} - -func GetDBTx(ctx context.Context) mo.Option[*pgx.Tx] { - v := ctx.Value(dbTxKey{}) - if v == nil { - return mo.None[*pgx.Tx]() - } - return mo.Some(v.(*pgx.Tx)) -} - -func WithDBTx(ctx context.Context, tx *pgx.Tx) context.Context { - return context.WithValue(ctx, dbTxKey{}, tx) -} diff --git a/backend/internal/context/values/postgres_tx.go b/backend/internal/context/values/postgres_tx.go new file mode 100644 index 000000000..32564acd9 --- /dev/null +++ b/backend/internal/context/values/postgres_tx.go @@ -0,0 +1,22 @@ +package values + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/samber/mo" +) + +type postgresTxKey struct{} + +func GetPostgresTx(ctx context.Context) mo.Option[*pgx.Tx] { + v := ctx.Value(postgresTxKey{}) + if v == nil { + return mo.None[*pgx.Tx]() + } + return mo.Some(v.(*pgx.Tx)) +} + +func WithPostgresTx(ctx context.Context, tx *pgx.Tx) context.Context { + return context.WithValue(ctx, postgresTxKey{}, tx) +} diff --git a/backend/internal/db/db.go b/backend/internal/db/postgres/db.go similarity index 97% rename from backend/internal/db/db.go rename to backend/internal/db/postgres/db.go index b4a3b78a3..46317d305 100644 --- a/backend/internal/db/db.go +++ b/backend/internal/db/postgres/db.go @@ -2,7 +2,7 @@ // versions: // sqlc v1.27.0 -package db +package postgres import ( "context" diff --git a/backend/internal/db/models.go b/backend/internal/db/postgres/models.go similarity index 89% rename from backend/internal/db/models.go rename to backend/internal/db/postgres/models.go index f6e375b23..aaa706ac0 100644 --- a/backend/internal/db/models.go +++ b/backend/internal/db/postgres/models.go @@ -2,7 +2,7 @@ // versions: // sqlc v1.27.0 -package db +package postgres import ( "database/sql/driver" @@ -127,27 +127,31 @@ type Item struct { UpdatedAt pgtype.Timestamp } +type SchemaMigration struct { + Version string +} + type Setting struct { ID int64 Uid string - ActivityColor *string - ActivityBackgroundColor *string - BackgroundColor *string + ActivityColor string + ActivityBackgroundColor string + BackgroundColor string Diagram Diagram - Height *int32 - Font *string - LineColor *string - LabelColor *string + Height int32 + Font string + LineColor string + LabelColor string LockEditing *bool TextColor *string Toolbar *bool Scale *float32 ShowGrid *bool - StoryColor *string - StoryBackgroundColor *string - TaskColor *string - TaskBackgroundColor *string - Width *int32 + StoryColor string + StoryBackgroundColor string + TaskColor string + TaskBackgroundColor string + Width int32 ZoomControl *bool CreatedAt pgtype.Timestamp UpdatedAt pgtype.Timestamp diff --git a/backend/internal/db/query.sql.go b/backend/internal/db/postgres/query.sql.go similarity index 92% rename from backend/internal/db/query.sql.go rename to backend/internal/db/postgres/query.sql.go index 043c9a243..ccf2691d5 100644 --- a/backend/internal/db/query.sql.go +++ b/backend/internal/db/postgres/query.sql.go @@ -3,7 +3,7 @@ // sqlc v1.27.0 // source: query.sql -package db +package postgres import ( "context" @@ -104,23 +104,23 @@ VALUES type CreateSettingsParams struct { Uid string - ActivityColor *string - ActivityBackgroundColor *string - BackgroundColor *string - Height *int32 + ActivityColor string + ActivityBackgroundColor string + BackgroundColor string + Height int32 Diagram Diagram - LineColor *string - LabelColor *string + LineColor string + LabelColor string LockEditing *bool TextColor *string Toolbar *bool Scale *float32 ShowGrid *bool - StoryColor *string - StoryBackgroundColor *string - TaskColor *string - TaskBackgroundColor *string - Width *int32 + StoryColor string + StoryBackgroundColor string + TaskColor string + TaskBackgroundColor string + Width int32 ZoomControl *bool } @@ -494,27 +494,28 @@ SET width = $16, zoom_control = $17 WHERE - diagram = $2 + diagram = $18 ` type UpdateSettingsParams struct { - ActivityColor *string - ActivityBackgroundColor *string - BackgroundColor *string - Height *int32 - LineColor *string - LabelColor *string + ActivityColor string + ActivityBackgroundColor string + BackgroundColor string + Height int32 + LineColor string + LabelColor string LockEditing *bool TextColor *string Toolbar *bool Scale *float32 ShowGrid *bool - StoryColor *string - StoryBackgroundColor *string - TaskColor *string - TaskBackgroundColor *string - Width *int32 + StoryColor string + StoryBackgroundColor string + TaskColor string + TaskBackgroundColor string + Width int32 ZoomControl *bool + Diagram Diagram } func (q *Queries) UpdateSettings(ctx context.Context, arg UpdateSettingsParams) error { @@ -536,6 +537,7 @@ func (q *Queries) UpdateSettings(ctx context.Context, arg UpdateSettingsParams) arg.TaskBackgroundColor, arg.Width, arg.ZoomControl, + arg.Diagram, ) return err } diff --git a/backend/internal/db/sqlite/db.go b/backend/internal/db/sqlite/db.go new file mode 100644 index 000000000..daca62a3a --- /dev/null +++ b/backend/internal/db/sqlite/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +package sqlite + +import ( + "context" + "database/sql" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/backend/internal/db/sqlite/models.go b/backend/internal/db/sqlite/models.go new file mode 100644 index 000000000..0a07ce7e3 --- /dev/null +++ b/backend/internal/db/sqlite/models.go @@ -0,0 +1,69 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 + +package sqlite + +import ( + "database/sql" +) + +type Item struct { + ID int64 + Uid string + DiagramID string + Location string + Diagram string + IsBookmark int64 + IsPublic int64 + Title sql.NullString + Text string + Thumbnail sql.NullString + CreatedAt int64 + UpdatedAt int64 +} + +type SchemaMigrations struct { + Version string +} + +type Setting struct { + ID int64 + Uid string + ActivityColor string + ActivityBackgroundColor string + BackgroundColor string + Diagram string + Height int64 + Font string + LineColor string + LabelColor string + LockEditing sql.NullInt64 + TextColor sql.NullString + Toolbar sql.NullInt64 + Scale float64 + ShowGrid sql.NullInt64 + StoryColor string + StoryBackgroundColor string + TaskColor string + TaskBackgroundColor string + Width int64 + ZoomControl sql.NullInt64 + CreatedAt int64 + UpdatedAt int64 +} + +type ShareCondition struct { + ID int64 + Hashkey string + Uid string + DiagramID string + Location string + AllowIpList sql.NullString + AllowEmailList sql.NullString + ExpireTime sql.NullInt64 + Password sql.NullString + Token string + CreatedAt int64 + UpdatedAt int64 +} diff --git a/backend/internal/db/sqlite/query.sql.go b/backend/internal/db/sqlite/query.sql.go new file mode 100644 index 000000000..3a9fe8240 --- /dev/null +++ b/backend/internal/db/sqlite/query.sql.go @@ -0,0 +1,597 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.27.0 +// source: query.sql + +package sqlite + +import ( + "context" + "database/sql" +) + +const createItem = `-- name: CreateItem :exec +INSERT INTO + items ( + uid, + diagram, + diagram_id, + is_bookmark, + is_public, + title, + text, + thumbnail, + location, + created_at, + updated_at + ) +VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateItemParams struct { + Uid string + Diagram string + DiagramID string + IsBookmark int64 + IsPublic int64 + Title sql.NullString + Text string + Thumbnail sql.NullString + Location string + CreatedAt int64 + UpdatedAt int64 +} + +func (q *Queries) CreateItem(ctx context.Context, arg CreateItemParams) error { + _, err := q.db.ExecContext(ctx, createItem, + arg.Uid, + arg.Diagram, + arg.DiagramID, + arg.IsBookmark, + arg.IsPublic, + arg.Title, + arg.Text, + arg.Thumbnail, + arg.Location, + arg.CreatedAt, + arg.UpdatedAt, + ) + return err +} + +const createSettings = `-- name: CreateSettings :exec +INSERT INTO + settings ( + uid, + activity_color, + activity_background_color, + background_color, + height, + diagram, + line_color, + label_color, + lock_editing, + text_color, + toolbar, + scale, + show_grid, + story_color, + story_background_color, + task_color, + task_background_color, + width, + zoom_control, + created_at, + updated_at + ) +VALUES + ( + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ?, + ? + ) +` + +type CreateSettingsParams struct { + Uid string + ActivityColor string + ActivityBackgroundColor string + BackgroundColor string + Height int64 + Diagram string + LineColor string + LabelColor string + LockEditing sql.NullInt64 + TextColor sql.NullString + Toolbar sql.NullInt64 + Scale float64 + ShowGrid sql.NullInt64 + StoryColor string + StoryBackgroundColor string + TaskColor string + TaskBackgroundColor string + Width int64 + ZoomControl sql.NullInt64 + CreatedAt int64 + UpdatedAt int64 +} + +func (q *Queries) CreateSettings(ctx context.Context, arg CreateSettingsParams) error { + _, err := q.db.ExecContext(ctx, createSettings, + arg.Uid, + arg.ActivityColor, + arg.ActivityBackgroundColor, + arg.BackgroundColor, + arg.Height, + arg.Diagram, + arg.LineColor, + arg.LabelColor, + arg.LockEditing, + arg.TextColor, + arg.Toolbar, + arg.Scale, + arg.ShowGrid, + arg.StoryColor, + arg.StoryBackgroundColor, + arg.TaskColor, + arg.TaskBackgroundColor, + arg.Width, + arg.ZoomControl, + arg.CreatedAt, + arg.UpdatedAt, + ) + return err +} + +const createShareCondition = `-- name: CreateShareCondition :exec +INSERT INTO + share_conditions ( + uid, + hashkey, + diagram_id, + location, + allow_ip_list, + allow_email_list, + expire_time, + password, + token, + created_at, + updated_at + ) +VALUES + (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +` + +type CreateShareConditionParams struct { + Uid string + Hashkey string + DiagramID string + Location string + AllowIpList sql.NullString + AllowEmailList sql.NullString + ExpireTime sql.NullInt64 + Password sql.NullString + Token string + CreatedAt int64 + UpdatedAt int64 +} + +func (q *Queries) CreateShareCondition(ctx context.Context, arg CreateShareConditionParams) error { + _, err := q.db.ExecContext(ctx, createShareCondition, + arg.Uid, + arg.Hashkey, + arg.DiagramID, + arg.Location, + arg.AllowIpList, + arg.AllowEmailList, + arg.ExpireTime, + arg.Password, + arg.Token, + arg.CreatedAt, + arg.UpdatedAt, + ) + return err +} + +const deleteItem = `-- name: DeleteItem :exec +DELETE FROM items +WHERE + uid = ? + AND diagram_id = ? +` + +type DeleteItemParams struct { + Uid string + DiagramID string +} + +func (q *Queries) DeleteItem(ctx context.Context, arg DeleteItemParams) error { + _, err := q.db.ExecContext(ctx, deleteItem, arg.Uid, arg.DiagramID) + return err +} + +const deleteShareCondition = `-- name: DeleteShareCondition :exec +DELETE FROM share_conditions +WHERE + hashkey = ? +` + +func (q *Queries) DeleteShareCondition(ctx context.Context, hashkey string) error { + _, err := q.db.ExecContext(ctx, deleteShareCondition, hashkey) + return err +} + +const deleteShareConditionItem = `-- name: DeleteShareConditionItem :exec +DELETE FROM share_conditions +WHERE + uid = ? + AND location = ? + AND diagram_id = ? +` + +type DeleteShareConditionItemParams struct { + Uid string + Location string + DiagramID string +} + +func (q *Queries) DeleteShareConditionItem(ctx context.Context, arg DeleteShareConditionItemParams) error { + _, err := q.db.ExecContext(ctx, deleteShareConditionItem, arg.Uid, arg.Location, arg.DiagramID) + return err +} + +const getItem = `-- name: GetItem :one +SELECT + id, uid, diagram_id, location, diagram, is_bookmark, is_public, title, text, thumbnail, created_at, updated_at +FROM + items +WHERE + uid = ? + AND location = ? + AND diagram_id = ? +` + +type GetItemParams struct { + Uid string + Location string + DiagramID string +} + +func (q *Queries) GetItem(ctx context.Context, arg GetItemParams) (Item, error) { + row := q.db.QueryRowContext(ctx, getItem, arg.Uid, arg.Location, arg.DiagramID) + var i Item + err := row.Scan( + &i.ID, + &i.Uid, + &i.DiagramID, + &i.Location, + &i.Diagram, + &i.IsBookmark, + &i.IsPublic, + &i.Title, + &i.Text, + &i.Thumbnail, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getSettings = `-- name: GetSettings :one +SELECT + id, uid, activity_color, activity_background_color, background_color, diagram, height, font, line_color, label_color, lock_editing, text_color, toolbar, scale, show_grid, story_color, story_background_color, task_color, task_background_color, width, zoom_control, created_at, updated_at +FROM + settings +WHERE + uid = ? + AND diagram = ? +` + +type GetSettingsParams struct { + Uid string + Diagram string +} + +func (q *Queries) GetSettings(ctx context.Context, arg GetSettingsParams) (Setting, error) { + row := q.db.QueryRowContext(ctx, getSettings, arg.Uid, arg.Diagram) + var i Setting + err := row.Scan( + &i.ID, + &i.Uid, + &i.ActivityColor, + &i.ActivityBackgroundColor, + &i.BackgroundColor, + &i.Diagram, + &i.Height, + &i.Font, + &i.LineColor, + &i.LabelColor, + &i.LockEditing, + &i.TextColor, + &i.Toolbar, + &i.Scale, + &i.ShowGrid, + &i.StoryColor, + &i.StoryBackgroundColor, + &i.TaskColor, + &i.TaskBackgroundColor, + &i.Width, + &i.ZoomControl, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getShareCondition = `-- name: GetShareCondition :one +SELECT + id, hashkey, uid, diagram_id, location, allow_ip_list, allow_email_list, expire_time, password, token, created_at, updated_at +FROM + share_conditions +WHERE + hashkey = ? +` + +func (q *Queries) GetShareCondition(ctx context.Context, hashkey string) (ShareCondition, error) { + row := q.db.QueryRowContext(ctx, getShareCondition, hashkey) + var i ShareCondition + err := row.Scan( + &i.ID, + &i.Hashkey, + &i.Uid, + &i.DiagramID, + &i.Location, + &i.AllowIpList, + &i.AllowEmailList, + &i.ExpireTime, + &i.Password, + &i.Token, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getShareConditionItem = `-- name: GetShareConditionItem :one +SELECT + id, hashkey, uid, diagram_id, location, allow_ip_list, allow_email_list, expire_time, password, token, created_at, updated_at +FROM + share_conditions +WHERE + uid = ? + AND location = ? + AND diagram_id = ? +` + +type GetShareConditionItemParams struct { + Uid string + Location string + DiagramID string +} + +func (q *Queries) GetShareConditionItem(ctx context.Context, arg GetShareConditionItemParams) (ShareCondition, error) { + row := q.db.QueryRowContext(ctx, getShareConditionItem, arg.Uid, arg.Location, arg.DiagramID) + var i ShareCondition + err := row.Scan( + &i.ID, + &i.Hashkey, + &i.Uid, + &i.DiagramID, + &i.Location, + &i.AllowIpList, + &i.AllowEmailList, + &i.ExpireTime, + &i.Password, + &i.Token, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const listItems = `-- name: ListItems :many +SELECT + id, uid, diagram_id, location, diagram, is_bookmark, is_public, title, text, thumbnail, created_at, updated_at +FROM + items +WHERE + uid = ? + AND location = ? + AND is_public = ? + AND is_bookmark = ? +LIMIT + ? +OFFSET + ? +` + +type ListItemsParams struct { + Uid string + Location string + IsPublic int64 + IsBookmark int64 + Limit int64 + Offset int64 +} + +func (q *Queries) ListItems(ctx context.Context, arg ListItemsParams) ([]Item, error) { + rows, err := q.db.QueryContext(ctx, listItems, + arg.Uid, + arg.Location, + arg.IsPublic, + arg.IsBookmark, + arg.Limit, + arg.Offset, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Item + for rows.Next() { + var i Item + if err := rows.Scan( + &i.ID, + &i.Uid, + &i.DiagramID, + &i.Location, + &i.Diagram, + &i.IsBookmark, + &i.IsPublic, + &i.Title, + &i.Text, + &i.Thumbnail, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateItem = `-- name: UpdateItem :exec +UPDATE items +SET + diagram = ?, + is_bookmark = ?, + is_public = ?, + title = ?, + text = ?, + thumbnail = ?, + location = ?, + updated_at = ? +WHERE + uid = ? + AND diagram_id = ? +` + +type UpdateItemParams struct { + Diagram string + IsBookmark int64 + IsPublic int64 + Title sql.NullString + Text string + Thumbnail sql.NullString + Location string + UpdatedAt int64 + Uid string + DiagramID string +} + +func (q *Queries) UpdateItem(ctx context.Context, arg UpdateItemParams) error { + _, err := q.db.ExecContext(ctx, updateItem, + arg.Diagram, + arg.IsBookmark, + arg.IsPublic, + arg.Title, + arg.Text, + arg.Thumbnail, + arg.Location, + arg.UpdatedAt, + arg.Uid, + arg.DiagramID, + ) + return err +} + +const updateSettings = `-- name: UpdateSettings :exec +UPDATE settings +SET + activity_color = ?, + activity_background_color = ?, + background_color = ?, + height = ?, + line_color = ?, + label_color = ?, + lock_editing = ?, + text_color = ?, + toolbar = ?, + scale = ?, + show_grid = ?, + story_color = ?, + story_background_color = ?, + task_color = ?, + task_background_color = ?, + width = ?, + zoom_control = ?, + updated_at = ? +WHERE + uid = ? + AND diagram = ? +` + +type UpdateSettingsParams struct { + ActivityColor string + ActivityBackgroundColor string + BackgroundColor string + Height int64 + LineColor string + LabelColor string + LockEditing sql.NullInt64 + TextColor sql.NullString + Toolbar sql.NullInt64 + Scale float64 + ShowGrid sql.NullInt64 + StoryColor string + StoryBackgroundColor string + TaskColor string + TaskBackgroundColor string + Width int64 + ZoomControl sql.NullInt64 + UpdatedAt int64 + Uid string + Diagram string +} + +func (q *Queries) UpdateSettings(ctx context.Context, arg UpdateSettingsParams) error { + _, err := q.db.ExecContext(ctx, updateSettings, + arg.ActivityColor, + arg.ActivityBackgroundColor, + arg.BackgroundColor, + arg.Height, + arg.LineColor, + arg.LabelColor, + arg.LockEditing, + arg.TextColor, + arg.Toolbar, + arg.Scale, + arg.ShowGrid, + arg.StoryColor, + arg.StoryBackgroundColor, + arg.TaskColor, + arg.TaskBackgroundColor, + arg.Width, + arg.ZoomControl, + arg.UpdatedAt, + arg.Uid, + arg.Diagram, + ) + return err +} diff --git a/backend/internal/db/tx.go b/backend/internal/db/tx.go index 2d3dcb901..fde8ac800 100644 --- a/backend/internal/db/tx.go +++ b/backend/internal/db/tx.go @@ -1,7 +1,10 @@ +//go:generate go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest +//go:generate sqlc generate -f ../../sqlc.yaml package db import ( "context" + "database/sql" "fmt" "log/slog" @@ -19,6 +22,10 @@ type postgresTx struct { db *pgxpool.Pool } +type dbTx struct { + db *sql.Conn +} + type firestoreTx struct { db *firestore.Client } @@ -27,6 +34,10 @@ func NewPostgresTx(config *config.Config) Transaction { return &postgresTx{db: config.PostgresConn} } +func NewDBTx(config *config.Config) Transaction { + return &dbTx{db: config.SqlConn} +} + func NewFirestoreTx(config *config.Config) Transaction { return &firestoreTx{db: config.FirestoreClient} } @@ -36,7 +47,7 @@ func (t *postgresTx) Do(ctx context.Context, fn func(ctx context.Context) error) if err != nil { return err } - ctx = values.WithDBTx(ctx, &tx) + ctx = values.WithPostgresTx(ctx, &tx) _, err = tx.Exec(ctx, fmt.Sprintf("SET LOCAL app.uid = \"%s\";", values.GetUID(ctx).MustGet())) @@ -59,6 +70,30 @@ func (t *postgresTx) Do(ctx context.Context, fn func(ctx context.Context) error) return nil } +func (t *dbTx) Do(ctx context.Context, fn func(ctx context.Context) error) error { + tx, err := t.db.BeginTx(ctx, nil) + + if err != nil { + return err + } + + ctx = values.WithDBTx(ctx, tx) + + if err = fn(ctx); err != nil { + if txErr := tx.Rollback(); txErr != nil { + return err + } + + slog.Error(err.Error()) + return err + } + + if err = tx.Commit(); err != nil { + return err + } + return nil +} + func (t *firestoreTx) Do(ctx context.Context, fn func(ctx context.Context) error) error { return t.db.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error { ctx = values.WithFirestoreTx(ctx, tx) diff --git a/backend/internal/infra/postgres/item/diagramitem.go b/backend/internal/infra/postgres/item/diagramitem.go index a87c5f41b..67dfbcf05 100644 --- a/backend/internal/infra/postgres/item/diagramitem.go +++ b/backend/internal/infra/postgres/item/diagramitem.go @@ -8,7 +8,7 @@ import ( "github.com/google/uuid" "github.com/harehare/textusm/internal/config" "github.com/harehare/textusm/internal/context/values" - "github.com/harehare/textusm/internal/db" + "github.com/harehare/textusm/internal/db/postgres" "github.com/harehare/textusm/internal/domain/model/item/diagramitem" itemRepo "github.com/harehare/textusm/internal/domain/repository/item" "github.com/jackc/pgx/v5/pgtype" @@ -16,15 +16,15 @@ import ( ) type PostgresItemRepository struct { - _db *db.Queries + _db *postgres.Queries } func NewPostgresItemRepository(config *config.Config) itemRepo.ItemRepository { - return &PostgresItemRepository{_db: db.New(config.PostgresConn)} + return &PostgresItemRepository{_db: postgres.New(config.PostgresConn)} } -func (r *PostgresItemRepository) tx(ctx context.Context) *db.Queries { - tx := values.GetDBTx(ctx) +func (r *PostgresItemRepository) tx(ctx context.Context) *postgres.Queries { + tx := values.GetPostgresTx(ctx) if tx.IsPresent() { return r._db.WithTx(*tx.MustGet()) @@ -40,9 +40,9 @@ func (r *PostgresItemRepository) FindByID(ctx context.Context, userID string, it return mo.Err[*diagramitem.DiagramItem](err) } - i, err := r.tx(ctx).GetItem(ctx, db.GetItemParams{ + i, err := r.tx(ctx).GetItem(ctx, postgres.GetItemParams{ DiagramID: pgtype.UUID{Bytes: u, Valid: true}, - Location: db.LocationSYSTEM, + Location: postgres.LocationSYSTEM, }) if err != nil { @@ -77,8 +77,8 @@ func (r *PostgresItemRepository) FindByID(ctx context.Context, userID string, it } func (r *PostgresItemRepository) Find(ctx context.Context, userID string, offset, limit int, isPublic bool, isBookmark bool, shouldLoadText bool) mo.Result[[]*diagramitem.DiagramItem] { - dbItems, err := r.tx(ctx).ListItems(ctx, db.ListItemsParams{ - Location: db.LocationSYSTEM, + dbItems, err := r.tx(ctx).ListItems(ctx, postgres.ListItemsParams{ + Location: postgres.LocationSYSTEM, IsPublic: &isPublic, IsBookmark: &isBookmark, Limit: int32(limit), @@ -135,9 +135,9 @@ func (r *PostgresItemRepository) Save(ctx context.Context, userID string, item * return mo.Err[*diagramitem.DiagramItem](err) } - _, err = r.tx(ctx).GetItem(ctx, db.GetItemParams{ + _, err = r.tx(ctx).GetItem(ctx, postgres.GetItemParams{ DiagramID: pgtype.UUID{Bytes: u, Valid: true}, - Location: db.LocationSYSTEM, + Location: postgres.LocationSYSTEM, }) isBookmark := item.IsBookmark() @@ -148,16 +148,16 @@ func (r *PostgresItemRepository) Save(ctx context.Context, userID string, item * titlePtr := &title if errors.Is(err, sql.ErrNoRows) { - err := r.tx(ctx).CreateItem(ctx, db.CreateItemParams{ + err := r.tx(ctx).CreateItem(ctx, postgres.CreateItemParams{ Uid: userID, - Diagram: db.Diagram(item.Diagram()), + Diagram: postgres.Diagram(item.Diagram()), DiagramID: pgtype.UUID{Bytes: u, Valid: true}, IsBookmark: isBookmarkPtr, IsPublic: isPublicPtr, Title: titlePtr, Text: item.Text(), Thumbnail: item.Thumbnail(), - Location: db.LocationSYSTEM, + Location: postgres.LocationSYSTEM, }) if err != nil { @@ -167,15 +167,15 @@ func (r *PostgresItemRepository) Save(ctx context.Context, userID string, item * return mo.Err[*diagramitem.DiagramItem](err) } else { - err := r.tx(ctx).UpdateItem(ctx, db.UpdateItemParams{ - Diagram: db.Diagram(item.Diagram()), + err := r.tx(ctx).UpdateItem(ctx, postgres.UpdateItemParams{ + Diagram: postgres.Diagram(item.Diagram()), IsBookmark: isBookmarkPtr, IsPublic: isPublicPtr, Title: &title, Text: item.Text(), Thumbnail: item.Thumbnail(), DiagramID: pgtype.UUID{Bytes: u, Valid: true}, - Location: db.LocationSYSTEM, + Location: postgres.LocationSYSTEM, }) if err != nil { diff --git a/backend/internal/infra/postgres/item/gistitem.go b/backend/internal/infra/postgres/item/gistitem.go index b364ccad9..711023699 100644 --- a/backend/internal/infra/postgres/item/gistitem.go +++ b/backend/internal/infra/postgres/item/gistitem.go @@ -8,7 +8,7 @@ import ( "github.com/google/uuid" "github.com/harehare/textusm/internal/config" "github.com/harehare/textusm/internal/context/values" - "github.com/harehare/textusm/internal/db" + "github.com/harehare/textusm/internal/db/postgres" "github.com/harehare/textusm/internal/domain/model/item/gistitem" itemRepo "github.com/harehare/textusm/internal/domain/repository/item" "github.com/jackc/pgx/v5/pgtype" @@ -16,15 +16,15 @@ import ( ) type PostgresGistItemRepository struct { - _db *db.Queries + _db *postgres.Queries } func NewPostgresGistItemRepository(config *config.Config) itemRepo.GistItemRepository { - return &PostgresGistItemRepository{_db: db.New(config.PostgresConn)} + return &PostgresGistItemRepository{_db: postgres.New(config.PostgresConn)} } -func (r *PostgresGistItemRepository) tx(ctx context.Context) *db.Queries { - tx := values.GetDBTx(ctx) +func (r *PostgresGistItemRepository) tx(ctx context.Context) *postgres.Queries { + tx := values.GetPostgresTx(ctx) if tx.IsPresent() { return r._db.WithTx(*tx.MustGet()) @@ -40,9 +40,9 @@ func (r *PostgresGistItemRepository) FindByID(ctx context.Context, userID string return mo.Err[*gistitem.GistItem](err) } - i, err := r.tx(ctx).GetItem(ctx, db.GetItemParams{ + i, err := r.tx(ctx).GetItem(ctx, postgres.GetItemParams{ DiagramID: pgtype.UUID{Bytes: u, Valid: true}, - Location: db.LocationGIST, + Location: postgres.LocationGIST, }) if err != nil { @@ -77,10 +77,10 @@ func (r *PostgresGistItemRepository) FindByID(ctx context.Context, userID string func (r *PostgresGistItemRepository) Find(ctx context.Context, userID string, offset, limit int) mo.Result[[]*gistitem.GistItem] { isPublic := false isBookmark := false - dbItems, err := r.tx(ctx).ListItems(ctx, db.ListItemsParams{ + dbItems, err := r.tx(ctx).ListItems(ctx, postgres.ListItemsParams{ IsPublic: &isPublic, IsBookmark: &isBookmark, - Location: db.LocationGIST, + Location: postgres.LocationGIST, Limit: int32(limit), Offset: int32(offset), }) @@ -133,9 +133,9 @@ func (r *PostgresGistItemRepository) Save(ctx context.Context, userID string, it return mo.Err[*gistitem.GistItem](err) } - _, err = r.tx(ctx).GetItem(ctx, db.GetItemParams{ + _, err = r.tx(ctx).GetItem(ctx, postgres.GetItemParams{ DiagramID: pgtype.UUID{Bytes: u, Valid: true}, - Location: db.LocationGIST, + Location: postgres.LocationGIST, }) isBookmark := item.IsBookmark() @@ -146,27 +146,27 @@ func (r *PostgresGistItemRepository) Save(ctx context.Context, userID string, it titlePtr := &title if errors.Is(err, sql.ErrNoRows) { - r.tx(ctx).CreateItem(ctx, db.CreateItemParams{ + r.tx(ctx).CreateItem(ctx, postgres.CreateItemParams{ Uid: userID, - Diagram: db.Diagram(item.Diagram()), + Diagram: postgres.Diagram(item.Diagram()), DiagramID: pgtype.UUID{Bytes: u, Valid: true}, IsBookmark: isBookmarkPtr, IsPublic: &isPublicPtr, Title: titlePtr, Thumbnail: item.Thumbnail(), - Location: db.LocationGIST, + Location: postgres.LocationGIST, }) } else if err != nil { return mo.Err[*gistitem.GistItem](err) } else { - r.tx(ctx).UpdateItem(ctx, db.UpdateItemParams{ - Diagram: db.Diagram(item.Diagram()), + r.tx(ctx).UpdateItem(ctx, postgres.UpdateItemParams{ + Diagram: postgres.Diagram(item.Diagram()), IsBookmark: isBookmarkPtr, IsPublic: &isPublicPtr, Title: &title, Thumbnail: item.Thumbnail(), DiagramID: pgtype.UUID{Bytes: u, Valid: true}, - Location: db.LocationGIST, + Location: postgres.LocationGIST, }) } return mo.Ok(item) diff --git a/backend/internal/infra/postgres/settings/settings.go b/backend/internal/infra/postgres/settings/settings.go index 0b144bf34..3fc748611 100644 --- a/backend/internal/infra/postgres/settings/settings.go +++ b/backend/internal/infra/postgres/settings/settings.go @@ -7,7 +7,7 @@ import ( "github.com/harehare/textusm/internal/config" v "github.com/harehare/textusm/internal/context/values" - "github.com/harehare/textusm/internal/db" + "github.com/harehare/textusm/internal/db/postgres" "github.com/harehare/textusm/internal/domain/model/settings" settingsRepo "github.com/harehare/textusm/internal/domain/repository/settings" "github.com/harehare/textusm/internal/domain/values" @@ -15,15 +15,15 @@ import ( ) type PostgresSettingsRepository struct { - _db *db.Queries + _db *postgres.Queries } func NewPostgresSettingsRepository(config *config.Config) settingsRepo.SettingsRepository { - return &PostgresSettingsRepository{_db: db.New(config.PostgresConn)} + return &PostgresSettingsRepository{_db: postgres.New(config.PostgresConn)} } -func (r *PostgresSettingsRepository) tx(ctx context.Context) *db.Queries { - tx := v.GetDBTx(ctx) +func (r *PostgresSettingsRepository) tx(ctx context.Context) *postgres.Queries { + tx := v.GetPostgresTx(ctx) if tx.IsPresent() { return r._db.WithTx(*tx.MustGet()) @@ -33,7 +33,7 @@ func (r *PostgresSettingsRepository) tx(ctx context.Context) *db.Queries { } func (r *PostgresSettingsRepository) Find(ctx context.Context, userID string, diagram values.Diagram) mo.Result[*settings.Settings] { - s, err := r.tx(ctx).GetSettings(ctx, db.Diagram(diagram)) + s, err := r.tx(ctx).GetSettings(ctx, postgres.Diagram(diagram)) if err != nil { return mo.Err[*settings.Settings](err) @@ -42,15 +42,15 @@ func (r *PostgresSettingsRepository) Find(ctx context.Context, userID string, di scale := float64(*s.Scale) ss := settings.Settings{ - Font: *s.Font, - Width: int(*s.Width), - Height: int(*s.Height), - BackgroundColor: *s.BackgroundColor, - ActivityColor: settings.Color{ForegroundColor: *s.ActivityColor, BackgroundColor: *s.ActivityBackgroundColor}, - TaskColor: settings.Color{ForegroundColor: *s.TaskColor, BackgroundColor: *s.TaskBackgroundColor}, - StoryColor: settings.Color{ForegroundColor: *s.StoryColor, BackgroundColor: *s.StoryBackgroundColor}, - LineColor: *s.LineColor, - LabelColor: *s.LabelColor, + Font: s.Font, + Width: int(s.Width), + Height: int(s.Height), + BackgroundColor: s.BackgroundColor, + ActivityColor: settings.Color{ForegroundColor: s.ActivityColor, BackgroundColor: s.ActivityBackgroundColor}, + TaskColor: settings.Color{ForegroundColor: s.TaskColor, BackgroundColor: s.TaskBackgroundColor}, + StoryColor: settings.Color{ForegroundColor: s.StoryColor, BackgroundColor: s.StoryBackgroundColor}, + LineColor: s.LineColor, + LabelColor: s.LabelColor, TextColor: s.TextColor, ZoomControl: s.ZoomControl, Scale: &scale, @@ -68,50 +68,50 @@ func (r *PostgresSettingsRepository) Save(ctx context.Context, userID string, di height := int32(s.Height) scale := float32(*s.Scale) - _, err := r.tx(ctx).GetSettings(ctx, db.Diagram(diagram)) + _, err := r.tx(ctx).GetSettings(ctx, postgres.Diagram(diagram)) if errors.Is(err, sql.ErrNoRows) { - err = r.tx(ctx).CreateSettings(ctx, db.CreateSettingsParams{ + err = r.tx(ctx).CreateSettings(ctx, postgres.CreateSettingsParams{ Uid: userID, - Diagram: db.Diagram(diagram), - ActivityColor: &s.ActivityColor.ForegroundColor, - ActivityBackgroundColor: &s.ActivityColor.BackgroundColor, - BackgroundColor: &backgroundColor, - Height: &height, - LineColor: &s.LineColor, - LabelColor: &s.LabelColor, + Diagram: postgres.Diagram(diagram), + ActivityColor: s.ActivityColor.ForegroundColor, + ActivityBackgroundColor: s.ActivityColor.BackgroundColor, + BackgroundColor: backgroundColor, + Height: height, + LineColor: s.LineColor, + LabelColor: s.LabelColor, LockEditing: s.LockEditing, TextColor: s.TextColor, Toolbar: s.Toolbar, Scale: &scale, ShowGrid: s.ShowGrid, - StoryColor: &s.StoryColor.ForegroundColor, - StoryBackgroundColor: &s.StoryColor.BackgroundColor, - TaskColor: &s.TaskColor.ForegroundColor, - TaskBackgroundColor: &s.TaskColor.BackgroundColor, - Width: &width, + StoryColor: s.StoryColor.ForegroundColor, + StoryBackgroundColor: s.StoryColor.BackgroundColor, + TaskColor: s.TaskColor.ForegroundColor, + TaskBackgroundColor: s.TaskColor.BackgroundColor, + Width: width, ZoomControl: s.ZoomControl, }) } else if err != nil { return mo.Err[*settings.Settings](err) } else { - err = r.tx(ctx).UpdateSettings(ctx, db.UpdateSettingsParams{ - ActivityColor: &s.ActivityColor.ForegroundColor, - ActivityBackgroundColor: &s.ActivityColor.BackgroundColor, - BackgroundColor: &backgroundColor, - Height: &height, - LineColor: &s.LineColor, - LabelColor: &s.LabelColor, + err = r.tx(ctx).UpdateSettings(ctx, postgres.UpdateSettingsParams{ + ActivityColor: s.ActivityColor.ForegroundColor, + ActivityBackgroundColor: s.ActivityColor.BackgroundColor, + BackgroundColor: backgroundColor, + Height: height, + LineColor: s.LineColor, + LabelColor: s.LabelColor, LockEditing: s.LockEditing, TextColor: s.TextColor, Toolbar: s.Toolbar, Scale: &scale, ShowGrid: s.ShowGrid, - StoryColor: &s.StoryColor.ForegroundColor, - StoryBackgroundColor: &s.StoryColor.BackgroundColor, - TaskColor: &s.TaskColor.ForegroundColor, - TaskBackgroundColor: &s.TaskColor.BackgroundColor, - Width: &width, + StoryColor: s.StoryColor.ForegroundColor, + StoryBackgroundColor: s.StoryColor.BackgroundColor, + TaskColor: s.TaskColor.ForegroundColor, + TaskBackgroundColor: s.TaskColor.BackgroundColor, + Width: width, ZoomControl: s.ZoomControl, }) } diff --git a/backend/internal/infra/postgres/share/share.go b/backend/internal/infra/postgres/share/share.go index b528b3b20..c90e7a6a0 100644 --- a/backend/internal/infra/postgres/share/share.go +++ b/backend/internal/infra/postgres/share/share.go @@ -6,7 +6,7 @@ import ( "github.com/google/uuid" "github.com/harehare/textusm/internal/config" "github.com/harehare/textusm/internal/context/values" - "github.com/harehare/textusm/internal/db" + "github.com/harehare/textusm/internal/db/postgres" "github.com/harehare/textusm/internal/domain/model/item/diagramitem" "github.com/harehare/textusm/internal/domain/model/share" shareRepo "github.com/harehare/textusm/internal/domain/repository/share" @@ -16,15 +16,15 @@ import ( ) type PostgresShareRepository struct { - _db *db.Queries + _db *postgres.Queries } func NewPostgresShareRepository(config *config.Config) shareRepo.ShareRepository { - return &PostgresShareRepository{_db: db.New(config.PostgresConn)} + return &PostgresShareRepository{_db: postgres.New(config.PostgresConn)} } -func (r *PostgresShareRepository) tx(ctx context.Context) *db.Queries { - tx := values.GetDBTx(ctx) +func (r *PostgresShareRepository) tx(ctx context.Context) *postgres.Queries { + tx := values.GetPostgresTx(ctx) if tx.IsPresent() { return r._db.WithTx(*tx.MustGet()) @@ -40,7 +40,7 @@ func (r *PostgresShareRepository) Find(ctx context.Context, hashKey string) mo.R return mo.Err[shareRepo.ShareValue](err) } - item, err := r.tx(ctx).GetItem(ctx, db.GetItemParams{ + item, err := r.tx(ctx).GetItem(ctx, postgres.GetItemParams{ DiagramID: s.DiagramID, Location: s.Location, }) @@ -94,14 +94,14 @@ func (r *PostgresShareRepository) Save(ctx context.Context, userID, hashKey stri return mo.Err[bool](err) } - _, err = r.tx(ctx).GetShareConditionItem(ctx, db.GetShareConditionItemParams{ - Location: db.LocationSYSTEM, + _, err = r.tx(ctx).GetShareConditionItem(ctx, postgres.GetShareConditionItemParams{ + Location: postgres.LocationSYSTEM, DiagramID: pgtype.UUID{Bytes: id, Valid: true}, }) if err == nil { - err = r.tx(ctx).DeleteShareConditionItem(ctx, db.DeleteShareConditionItemParams{ - Location: db.LocationSYSTEM, + err = r.tx(ctx).DeleteShareConditionItem(ctx, postgres.DeleteShareConditionItemParams{ + Location: postgres.LocationSYSTEM, DiagramID: pgtype.UUID{Bytes: id, Valid: true}, }) @@ -123,11 +123,11 @@ func (r *PostgresShareRepository) Save(ctx context.Context, userID, hashKey stri savePassword = "" } - err = r.tx(ctx).CreateShareCondition(ctx, db.CreateShareConditionParams{ + err = r.tx(ctx).CreateShareCondition(ctx, postgres.CreateShareConditionParams{ Uid: userID, Hashkey: hashKey, DiagramID: pgtype.UUID{Bytes: id, Valid: true}, - Location: db.LocationSYSTEM, + Location: postgres.LocationSYSTEM, AllowIpList: shareInfo.AllowIPList, AllowEmailList: shareInfo.AllowEmailList, ExpireTime: &expireTime, diff --git a/backend/internal/infra/sqlite/db.go b/backend/internal/infra/sqlite/db.go new file mode 100644 index 000000000..d70dbd99e --- /dev/null +++ b/backend/internal/infra/sqlite/db.go @@ -0,0 +1,64 @@ +package sqlite + +import ( + "database/sql" + "time" +) + +const ( + LocationSYSTEM = "system" + LocationGIST = "gist" +) + +func StringToNullString(s *string) sql.NullString { + if s == nil { + return sql.NullString{String: "", Valid: false} + } else { + return sql.NullString{String: *s, Valid: true} + } +} + +func NullStringToString(s sql.NullString) *string { + if s.Valid { + return &s.String + } else { + return nil + } +} + +func NullIntToBool(s sql.NullInt64) *bool { + if s.Valid && s.Int64 == 1 { + val := true + return &val + } else { + return nil + } +} + +func BoolToNullInt(b *bool) sql.NullInt64 { + if b != nil && *b { + return sql.NullInt64{Int64: 1, Valid: true} + } else { + return sql.NullInt64{Int64: 0, Valid: false} + } +} + +func IntToBool(i int64) bool { + return i == 1 +} + +func BoolToInt(b bool) int64 { + if b { + return 1 + } else { + return 0 + } +} + +func IntToDateTime(i int64) time.Time { + return time.Unix(i, 0) +} + +func DateTimeToInt(t time.Time) int64 { + return t.Unix() +} diff --git a/backend/internal/infra/sqlite/item/diagramitem.go b/backend/internal/infra/sqlite/item/diagramitem.go new file mode 100644 index 000000000..d862afdde --- /dev/null +++ b/backend/internal/infra/sqlite/item/diagramitem.go @@ -0,0 +1,178 @@ +package item + +import ( + "context" + "database/sql" + "errors" + "time" + + "github.com/harehare/textusm/internal/config" + "github.com/harehare/textusm/internal/context/values" + "github.com/harehare/textusm/internal/db/sqlite" + "github.com/harehare/textusm/internal/domain/model/item/diagramitem" + itemRepo "github.com/harehare/textusm/internal/domain/repository/item" + db "github.com/harehare/textusm/internal/infra/sqlite" + "github.com/samber/mo" +) + +type SqliteItemRepository struct { + _db *sqlite.Queries +} + +func NewSqliteItemRepository(config *config.Config) itemRepo.ItemRepository { + return &SqliteItemRepository{_db: sqlite.New(config.SqlConn)} +} + +func (r *SqliteItemRepository) tx(ctx context.Context) *sqlite.Queries { + tx := values.GetDBTx(ctx) + + if tx.IsPresent() { + return r._db.WithTx(tx.MustGet()) + } else { + return r._db + } +} + +func (r *SqliteItemRepository) FindByID(ctx context.Context, userID string, itemID string, isPublic bool) mo.Result[*diagramitem.DiagramItem] { + i, err := r.tx(ctx).GetItem(ctx, sqlite.GetItemParams{ + Uid: userID, + DiagramID: itemID, + Location: "system", + }) + + if err != nil { + return mo.Err[*diagramitem.DiagramItem](err) + } + + var thumbnail mo.Option[string] + + if i.Thumbnail.Valid { + thumbnail = mo.None[string]() + } else { + thumbnail = mo.Some[string](*&i.Thumbnail.String) + } + + return diagramitem.New(). + WithID(i.DiagramID). + WithTitle(i.Title.String). + WithEncryptedText(i.Text). + WithThumbnail(thumbnail). + WithDiagramString(string(i.Diagram)). + WithIsPublic(db.IntToBool(i.IsPublic)). + WithIsBookmark(db.IntToBool(i.IsBookmark)). + WithCreatedAt(db.IntToDateTime(i.CreatedAt)). + WithUpdatedAt(db.IntToDateTime(i.UpdatedAt)). + Build() +} + +func (r *SqliteItemRepository) Find(ctx context.Context, userID string, offset, limit int, isPublic bool, isBookmark bool, shouldLoadText bool) mo.Result[[]*diagramitem.DiagramItem] { + dbItems, err := r.tx(ctx).ListItems(ctx, sqlite.ListItemsParams{ + Uid: userID, + Location: db.LocationSYSTEM, + IsPublic: db.BoolToInt(isPublic), + IsBookmark: db.BoolToInt(isBookmark), + Limit: int64(limit), + Offset: int64(offset), + }) + + if err != nil { + return mo.Err[[]*diagramitem.DiagramItem](err) + } + + var items []*diagramitem.DiagramItem + + for _, i := range dbItems { + var thumbnail mo.Option[string] + + if i.Thumbnail.Valid { + thumbnail = mo.Some[string](*&i.Thumbnail.String) + } else { + thumbnail = mo.None[string]() + } + + item := diagramitem.New(). + WithID(i.DiagramID). + WithTitle(i.Title.String). + WithEncryptedText(i.Text). + WithThumbnail(thumbnail). + WithDiagramString(string(i.Diagram)). + WithIsPublic(i.IsPublic == 1). + WithIsBookmark(i.IsBookmark == 1). + WithCreatedAt(time.Unix(i.CreatedAt, 0)). + WithUpdatedAt(time.Unix(i.UpdatedAt, 0)). + Build() + + if item.IsError() { + return mo.Err[[]*diagramitem.DiagramItem](item.Error()) + } + + items = append(items, item.MustGet()) + } + + return mo.Ok(items) +} + +func (r *SqliteItemRepository) Save(ctx context.Context, userID string, item *diagramitem.DiagramItem, isPublic bool) mo.Result[*diagramitem.DiagramItem] { + _, err := r.tx(ctx).GetItem(ctx, sqlite.GetItemParams{ + Uid: userID, + DiagramID: item.ID(), + Location: db.LocationSYSTEM, + }) + + isBookmark := item.IsBookmark() + title := item.Title() + + if errors.Is(err, sql.ErrNoRows) { + err := r.tx(ctx).CreateItem(ctx, sqlite.CreateItemParams{ + Uid: userID, + Diagram: string(item.Diagram()), + DiagramID: item.ID(), + IsBookmark: db.BoolToInt(isBookmark), + IsPublic: db.BoolToInt(isPublic), + Title: sql.NullString{String: title, Valid: true}, + Text: item.Text(), + Thumbnail: db.StringToNullString(item.Thumbnail()), + Location: db.LocationSYSTEM, + CreatedAt: db.DateTimeToInt(time.Now()), + UpdatedAt: db.DateTimeToInt(time.Now()), + }) + + if err != nil { + return mo.Err[*diagramitem.DiagramItem](err) + } + } else if err != nil { + return mo.Err[*diagramitem.DiagramItem](err) + } else { + + err := r.tx(ctx).UpdateItem(ctx, sqlite.UpdateItemParams{ + Uid: userID, + Diagram: string(item.Diagram()), + IsBookmark: db.BoolToInt(isBookmark), + IsPublic: db.BoolToInt(isPublic), + Title: sql.NullString{String: title, Valid: true}, + Text: item.Text(), + Thumbnail: db.StringToNullString(item.Thumbnail()), + DiagramID: item.ID(), + Location: db.LocationSYSTEM, + UpdatedAt: db.DateTimeToInt(time.Now()), + }) + + if err != nil { + return mo.Err[*diagramitem.DiagramItem](err) + } + } + return mo.Ok(item) +} + +func (r *SqliteItemRepository) Delete(ctx context.Context, userID string, itemID string, isPublic bool) mo.Result[bool] { + err := r.tx(ctx).DeleteItem(ctx, sqlite.DeleteItemParams{ + Uid: userID, + DiagramID: itemID, + }) + + if err != nil { + return mo.Err[bool](err) + } + + return mo.Ok(true) +} diff --git a/backend/internal/infra/sqlite/item/gistitem.go b/backend/internal/infra/sqlite/item/gistitem.go new file mode 100644 index 000000000..f027bfbf2 --- /dev/null +++ b/backend/internal/infra/sqlite/item/gistitem.go @@ -0,0 +1,161 @@ +package item + +import ( + "context" + "database/sql" + "errors" + + "github.com/harehare/textusm/internal/config" + "github.com/harehare/textusm/internal/context/values" + "github.com/harehare/textusm/internal/db/sqlite" + "github.com/harehare/textusm/internal/domain/model/item/gistitem" + itemRepo "github.com/harehare/textusm/internal/domain/repository/item" + db "github.com/harehare/textusm/internal/infra/sqlite" + "github.com/samber/mo" +) + +type SqliteGistItemRepository struct { + _db *sqlite.Queries +} + +func NewSqliteGistItemRepository(config *config.Config) itemRepo.GistItemRepository { + return &SqliteGistItemRepository{_db: sqlite.New(config.SqlConn)} +} + +func (r *SqliteGistItemRepository) tx(ctx context.Context) *sqlite.Queries { + tx := values.GetDBTx(ctx) + + if tx.IsPresent() { + return r._db.WithTx(tx.MustGet()) + } else { + return r._db + } +} + +func (r *SqliteGistItemRepository) FindByID(ctx context.Context, userID string, itemID string) mo.Result[*gistitem.GistItem] { + i, err := r.tx(ctx).GetItem(ctx, sqlite.GetItemParams{ + Uid: userID, + DiagramID: itemID, + Location: db.LocationGIST, + }) + + if err != nil { + return mo.Err[*gistitem.GistItem](err) + } + + var thumbnail mo.Option[string] + + if i.Thumbnail.Valid { + thumbnail = mo.Some[string](i.Thumbnail.String) + } else { + thumbnail = mo.None[string]() + } + + return gistitem.New(). + WithID(itemID). + WithTitle(i.Title.String). + WithThumbnail(thumbnail). + WithDiagramString(string(i.Diagram)). + WithIsBookmark(db.IntToBool(i.IsBookmark)). + WithCreatedAt(db.IntToDateTime(i.CreatedAt)). + WithUpdatedAt(db.IntToDateTime(i.UpdatedAt)). + Build() +} + +func (r *SqliteGistItemRepository) Find(ctx context.Context, userID string, offset, limit int) mo.Result[[]*gistitem.GistItem] { + isPublic := false + isBookmark := false + dbItems, err := r.tx(ctx).ListItems(ctx, sqlite.ListItemsParams{ + Uid: userID, + IsPublic: db.BoolToInt(isPublic), + IsBookmark: db.BoolToInt(isBookmark), + Location: db.LocationGIST, + Limit: int64(limit), + Offset: int64(offset), + }) + + if err != nil { + return mo.Err[[]*gistitem.GistItem](err) + } + + var items []*gistitem.GistItem + + for _, i := range dbItems { + var thumbnail mo.Option[string] + + if i.Thumbnail.Valid { + thumbnail = mo.Some[string](i.Thumbnail.String) + } else { + thumbnail = mo.None[string]() + } + + item := gistitem.New(). + WithID(i.DiagramID). + WithTitle(i.Title.String). + WithThumbnail(thumbnail). + WithDiagramString(string(i.Diagram)). + WithIsBookmark(db.IntToBool(i.IsBookmark)). + WithCreatedAt(db.IntToDateTime(i.CreatedAt)). + WithUpdatedAt(db.IntToDateTime(i.UpdatedAt)). + Build() + + if item.IsError() { + return mo.Err[[]*gistitem.GistItem](item.Error()) + } + + items = append(items, item.MustGet()) + } + + return mo.Ok(items) +} + +func (r *SqliteGistItemRepository) Save(ctx context.Context, userID string, item *gistitem.GistItem) mo.Result[*gistitem.GistItem] { + _, err := r.tx(ctx).GetItem(ctx, sqlite.GetItemParams{ + Uid: userID, + DiagramID: item.ID(), + Location: db.LocationGIST, + }) + + isBookmark := item.IsBookmark() + title := item.Title() + + if errors.Is(err, sql.ErrNoRows) { + r.tx(ctx).CreateItem(ctx, sqlite.CreateItemParams{ + Uid: userID, + Diagram: string(item.Diagram()), + DiagramID: item.ID(), + IsBookmark: db.BoolToInt(isBookmark), + IsPublic: db.BoolToInt(false), + Title: sql.NullString{String: title, Valid: true}, + Thumbnail: db.StringToNullString(item.Thumbnail()), + Location: db.LocationGIST, + CreatedAt: db.DateTimeToInt(item.CreatedAt()), + UpdatedAt: db.DateTimeToInt(item.CreatedAt()), + }) + } else if err != nil { + return mo.Err[*gistitem.GistItem](err) + } else { + r.tx(ctx).UpdateItem(ctx, sqlite.UpdateItemParams{ + Uid: userID, + Diagram: string(item.Diagram()), + IsBookmark: db.BoolToInt(isBookmark), + IsPublic: db.BoolToInt(false), + Title: sql.NullString{String: title, Valid: true}, + Thumbnail: db.StringToNullString(item.Thumbnail()), + DiagramID: item.ID(), + Location: db.LocationGIST, + UpdatedAt: db.DateTimeToInt(item.CreatedAt()), + }) + } + return mo.Ok(item) +} + +func (r *SqliteGistItemRepository) Delete(ctx context.Context, userID string, gistID string) mo.Result[bool] { + err := r.tx(ctx).DeleteItem(ctx, sqlite.DeleteItemParams{Uid: userID, DiagramID: gistID}) + + if err != nil { + return mo.Err[bool](err) + } + + return mo.Ok(true) +} diff --git a/backend/internal/infra/sqlite/settings/settings.go b/backend/internal/infra/sqlite/settings/settings.go new file mode 100644 index 000000000..2c2e53899 --- /dev/null +++ b/backend/internal/infra/sqlite/settings/settings.go @@ -0,0 +1,130 @@ +package settings + +import ( + "context" + "database/sql" + "errors" + "time" + + "github.com/harehare/textusm/internal/config" + v "github.com/harehare/textusm/internal/context/values" + "github.com/harehare/textusm/internal/db/sqlite" + "github.com/harehare/textusm/internal/domain/model/settings" + settingsRepo "github.com/harehare/textusm/internal/domain/repository/settings" + "github.com/harehare/textusm/internal/domain/values" + db "github.com/harehare/textusm/internal/infra/sqlite" + "github.com/samber/mo" +) + +type SqliteSettingsRepository struct { + _db *sqlite.Queries +} + +func NewSqliteSettingsRepository(config *config.Config) settingsRepo.SettingsRepository { + return &SqliteSettingsRepository{_db: sqlite.New(config.SqlConn)} +} + +func (r *SqliteSettingsRepository) tx(ctx context.Context) *sqlite.Queries { + tx := v.GetDBTx(ctx) + + if tx.IsPresent() { + return r._db.WithTx(tx.MustGet()) + } else { + return r._db + } +} + +func (r *SqliteSettingsRepository) Find(ctx context.Context, userID string, diagram values.Diagram) mo.Result[*settings.Settings] { + s, err := r.tx(ctx).GetSettings(ctx, sqlite.GetSettingsParams{Uid: userID, Diagram: string(diagram)}) + + if err != nil { + return mo.Err[*settings.Settings](err) + } + + scale := float64(s.Scale) + + ss := settings.Settings{ + Font: s.Font, + Width: int(s.Width), + Height: int(s.Height), + BackgroundColor: s.BackgroundColor, + ActivityColor: settings.Color{ForegroundColor: s.ActivityColor, BackgroundColor: s.ActivityBackgroundColor}, + TaskColor: settings.Color{ForegroundColor: s.TaskColor, BackgroundColor: s.TaskBackgroundColor}, + StoryColor: settings.Color{ForegroundColor: s.StoryColor, BackgroundColor: s.StoryBackgroundColor}, + LineColor: s.LineColor, + LabelColor: s.LabelColor, + TextColor: db.NullStringToString(s.TextColor), + ZoomControl: db.NullIntToBool(s.ZoomControl), + Scale: &scale, + Toolbar: db.NullIntToBool(s.Toolbar), + LockEditing: db.NullIntToBool(s.LockEditing), + ShowGrid: db.NullIntToBool(s.ShowGrid), + } + + return mo.Ok(&ss) +} + +func (r *SqliteSettingsRepository) Save(ctx context.Context, userID string, diagram values.Diagram, s settings.Settings) mo.Result[*settings.Settings] { + backgroundColor := s.BackgroundColor + width := int32(s.Width) + height := int32(s.Height) + scale := float32(*s.Scale) + + _, err := r.tx(ctx).GetSettings(ctx, sqlite.GetSettingsParams{Uid: userID, Diagram: string(diagram)}) + + if errors.Is(err, sql.ErrNoRows) { + err = r.tx(ctx).CreateSettings(ctx, sqlite.CreateSettingsParams{ + Uid: userID, + Diagram: string(diagram), + ActivityColor: s.ActivityColor.ForegroundColor, + ActivityBackgroundColor: s.ActivityColor.BackgroundColor, + BackgroundColor: backgroundColor, + Height: int64(height), + LineColor: s.LineColor, + LabelColor: s.LabelColor, + LockEditing: db.BoolToNullInt(s.LockEditing), + TextColor: db.StringToNullString(s.TextColor), + Toolbar: db.BoolToNullInt(s.Toolbar), + Scale: float64(scale), + ShowGrid: db.BoolToNullInt(s.ShowGrid), + StoryColor: s.StoryColor.ForegroundColor, + StoryBackgroundColor: s.StoryColor.BackgroundColor, + TaskColor: s.TaskColor.ForegroundColor, + TaskBackgroundColor: s.TaskColor.BackgroundColor, + Width: int64(width), + ZoomControl: db.BoolToNullInt(s.ZoomControl), + CreatedAt: db.DateTimeToInt(time.Now()), + UpdatedAt: db.DateTimeToInt(time.Now()), + }) + } else if err != nil { + return mo.Err[*settings.Settings](err) + } else { + err = r.tx(ctx).UpdateSettings(ctx, sqlite.UpdateSettingsParams{ + Uid: userID, + ActivityColor: s.ActivityColor.ForegroundColor, + ActivityBackgroundColor: s.ActivityColor.BackgroundColor, + BackgroundColor: backgroundColor, + Height: int64(height), + LineColor: s.LineColor, + LabelColor: s.LabelColor, + LockEditing: db.BoolToNullInt(s.LockEditing), + TextColor: db.StringToNullString(s.TextColor), + Toolbar: db.BoolToNullInt(s.Toolbar), + Scale: float64(scale), + ShowGrid: db.BoolToNullInt(s.ShowGrid), + StoryColor: s.StoryColor.ForegroundColor, + StoryBackgroundColor: s.StoryColor.BackgroundColor, + TaskColor: s.TaskColor.ForegroundColor, + TaskBackgroundColor: s.TaskColor.BackgroundColor, + Width: int64(width), + ZoomControl: db.BoolToNullInt(s.ZoomControl), + UpdatedAt: db.DateTimeToInt(time.Now()), + }) + } + + if err != nil { + return mo.Err[*settings.Settings](err) + } + + return mo.Ok(&s) +} diff --git a/backend/internal/infra/sqlite/share/share.go b/backend/internal/infra/sqlite/share/share.go new file mode 100644 index 000000000..b9a33d780 --- /dev/null +++ b/backend/internal/infra/sqlite/share/share.go @@ -0,0 +1,145 @@ +package share + +import ( + "context" + "database/sql" + "strings" + "time" + + "github.com/harehare/textusm/internal/config" + "github.com/harehare/textusm/internal/context/values" + "github.com/harehare/textusm/internal/db/sqlite" + "github.com/harehare/textusm/internal/domain/model/item/diagramitem" + "github.com/harehare/textusm/internal/domain/model/share" + shareRepo "github.com/harehare/textusm/internal/domain/repository/share" + db "github.com/harehare/textusm/internal/infra/sqlite" + "github.com/samber/mo" + "golang.org/x/crypto/bcrypt" +) + +type SqliteShareRepository struct { + _db *sqlite.Queries +} + +func NewSqliteShareRepository(config *config.Config) shareRepo.ShareRepository { + return &SqliteShareRepository{_db: sqlite.New(config.SqlConn)} +} + +func (r *SqliteShareRepository) tx(ctx context.Context) *sqlite.Queries { + tx := values.GetDBTx(ctx) + + if tx.IsPresent() { + return r._db.WithTx(tx.MustGet()) + } else { + return r._db + } +} + +func (r *SqliteShareRepository) Find(ctx context.Context, hashKey string) mo.Result[shareRepo.ShareValue] { + s, err := r.tx(ctx).GetShareCondition(ctx, hashKey) + + if err != nil { + return mo.Err[shareRepo.ShareValue](err) + } + + item, err := r.tx(ctx).GetItem(ctx, sqlite.GetItemParams{ + DiagramID: s.DiagramID, + Location: s.Location, + }) + + if err != nil { + return mo.Err[shareRepo.ShareValue](err) + } + + shareInfo := share.Share{ + Token: s.Token, + ExpireTime: s.ExpireTime.Int64, + Password: s.Password.String, + AllowIPList: strings.Split(s.AllowIpList.String, ","), + AllowEmailList: strings.Split(s.AllowEmailList.String, ","), + } + + var thumbnail mo.Option[string] + + if item.Thumbnail.Valid { + thumbnail = mo.Some[string](item.Thumbnail.String) + } else { + thumbnail = mo.None[string]() + } + + diagramitem := diagramitem.New(). + WithID(item.DiagramID). + WithTitle(item.Title.String). + WithEncryptedText(item.Text). + WithThumbnail(thumbnail). + WithDiagramString(string(item.Diagram)). + WithIsPublic(db.IntToBool(item.IsPublic)). + WithIsBookmark(db.IntToBool(item.IsBookmark)). + WithCreatedAt(db.IntToDateTime(item.CreatedAt)). + WithUpdatedAt(db.IntToDateTime(item.UpdatedAt)). + Build().OrEmpty() + + return mo.Ok(shareRepo.ShareValue{DiagramItem: diagramitem, ShareInfo: &shareInfo}) +} + +func (r *SqliteShareRepository) Save(ctx context.Context, userID, hashKey string, item *diagramitem.DiagramItem, shareInfo *share.Share) mo.Result[bool] { + expireTime := shareInfo.ExpireTime + _, err := r.tx(ctx).GetShareConditionItem(ctx, sqlite.GetShareConditionItemParams{ + Location: db.LocationSYSTEM, + DiagramID: item.ID(), + }) + + if err == nil { + err = r.tx(ctx).DeleteShareConditionItem(ctx, sqlite.DeleteShareConditionItemParams{ + Location: db.LocationSYSTEM, + DiagramID: item.ID(), + }) + + if err != nil { + return mo.Err[bool](err) + } + } + + var savePassword string + + if shareInfo.Password != "" { + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(shareInfo.Password), bcrypt.DefaultCost) + + if err != nil { + return mo.Err[bool](err) + } + savePassword = string(hashedPassword) + } else { + savePassword = "" + } + + err = r.tx(ctx).CreateShareCondition(ctx, sqlite.CreateShareConditionParams{ + Uid: userID, + Hashkey: hashKey, + DiagramID: item.ID(), + Location: db.LocationSYSTEM, + AllowIpList: sql.NullString{String: strings.Join(shareInfo.AllowIPList, ","), Valid: true}, + AllowEmailList: sql.NullString{String: strings.Join(shareInfo.AllowEmailList, ","), Valid: true}, + ExpireTime: sql.NullInt64{Int64: expireTime, Valid: true}, + Password: sql.NullString{String: savePassword, Valid: true}, + Token: shareInfo.Token, + CreatedAt: db.DateTimeToInt(time.Now()), + UpdatedAt: db.DateTimeToInt(time.Now()), + }) + + if err != nil { + return mo.Err[bool](err) + } + + return mo.Ok(true) +} + +func (r *SqliteShareRepository) Delete(ctx context.Context, userID, hashKey string) mo.Result[bool] { + err := r.tx(ctx).DeleteShareCondition(ctx, hashKey) + + if err != nil { + return mo.Err[bool](err) + } + + return mo.Ok(true) +} diff --git a/backend/internal/presentation/graphql/generated.go b/backend/internal/presentation/graphql/generated.go index 8dce1f5d5..fe027ac8f 100644 --- a/backend/internal/presentation/graphql/generated.go +++ b/backend/internal/presentation/graphql/generated.go @@ -1,5 +1,3 @@ -//go:generate go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest -//go:generate sqlc generate // Code generated by github.com/99designs/gqlgen, DO NOT EDIT. package graphql @@ -903,371 +901,875 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) func (ec *executionContext) field_Mutation_bookmark_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["itemID"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("itemID")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_bookmark_argsItemID(ctx, rawArgs) + if err != nil { + return nil, err } args["itemID"] = arg0 - var arg1 bool - if tmp, ok := rawArgs["isBookmark"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isBookmark")) - arg1, err = ec.unmarshalNBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Mutation_bookmark_argsIsBookmark(ctx, rawArgs) + if err != nil { + return nil, err } args["isBookmark"] = arg1 return args, nil } +func (ec *executionContext) field_Mutation_bookmark_argsItemID( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["itemID"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("itemID")) + if tmp, ok := rawArgs["itemID"]; ok { + return ec.unmarshalNID2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_bookmark_argsIsBookmark( + ctx context.Context, + rawArgs map[string]interface{}, +) (bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["isBookmark"] + if !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("isBookmark")) + if tmp, ok := rawArgs["isBookmark"]; ok { + return ec.unmarshalNBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} func (ec *executionContext) field_Mutation_deleteGist_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["gistID"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("gistID")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_deleteGist_argsGistID(ctx, rawArgs) + if err != nil { + return nil, err } args["gistID"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_deleteGist_argsGistID( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["gistID"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("gistID")) + if tmp, ok := rawArgs["gistID"]; ok { + return ec.unmarshalNID2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} func (ec *executionContext) field_Mutation_delete_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["itemID"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("itemID")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_delete_argsItemID(ctx, rawArgs) + if err != nil { + return nil, err } args["itemID"] = arg0 - var arg1 *bool - if tmp, ok := rawArgs["isPublic"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) - arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Mutation_delete_argsIsPublic(ctx, rawArgs) + if err != nil { + return nil, err } args["isPublic"] = arg1 return args, nil } +func (ec *executionContext) field_Mutation_delete_argsItemID( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["itemID"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("itemID")) + if tmp, ok := rawArgs["itemID"]; ok { + return ec.unmarshalNID2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_delete_argsIsPublic( + ctx context.Context, + rawArgs map[string]interface{}, +) (*bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["isPublic"] + if !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) + if tmp, ok := rawArgs["isPublic"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} func (ec *executionContext) field_Mutation_saveGist_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 InputGistItem - if tmp, ok := rawArgs["input"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalNInputGistItem2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputGistItem(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_saveGist_argsInput(ctx, rawArgs) + if err != nil { + return nil, err } args["input"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_saveGist_argsInput( + ctx context.Context, + rawArgs map[string]interface{}, +) (InputGistItem, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["input"] + if !ok { + var zeroVal InputGistItem + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNInputGistItem2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputGistItem(ctx, tmp) + } + + var zeroVal InputGistItem + return zeroVal, nil +} func (ec *executionContext) field_Mutation_saveSettings_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *values.Diagram - if tmp, ok := rawArgs["diagram"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("diagram")) - arg0, err = ec.unmarshalNDiagram2ᚖgithubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋvaluesᚐDiagram(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_saveSettings_argsDiagram(ctx, rawArgs) + if err != nil { + return nil, err } args["diagram"] = arg0 - var arg1 InputSettings - if tmp, ok := rawArgs["input"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg1, err = ec.unmarshalNInputSettings2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputSettings(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Mutation_saveSettings_argsInput(ctx, rawArgs) + if err != nil { + return nil, err } args["input"] = arg1 return args, nil } +func (ec *executionContext) field_Mutation_saveSettings_argsDiagram( + ctx context.Context, + rawArgs map[string]interface{}, +) (*values.Diagram, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["diagram"] + if !ok { + var zeroVal *values.Diagram + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("diagram")) + if tmp, ok := rawArgs["diagram"]; ok { + return ec.unmarshalNDiagram2ᚖgithubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋvaluesᚐDiagram(ctx, tmp) + } + + var zeroVal *values.Diagram + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_saveSettings_argsInput( + ctx context.Context, + rawArgs map[string]interface{}, +) (InputSettings, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["input"] + if !ok { + var zeroVal InputSettings + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNInputSettings2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputSettings(ctx, tmp) + } + + var zeroVal InputSettings + return zeroVal, nil +} func (ec *executionContext) field_Mutation_save_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 InputItem - if tmp, ok := rawArgs["input"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalNInputItem2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputItem(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_save_argsInput(ctx, rawArgs) + if err != nil { + return nil, err } args["input"] = arg0 - var arg1 *bool - if tmp, ok := rawArgs["isPublic"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) - arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Mutation_save_argsIsPublic(ctx, rawArgs) + if err != nil { + return nil, err } args["isPublic"] = arg1 return args, nil } +func (ec *executionContext) field_Mutation_save_argsInput( + ctx context.Context, + rawArgs map[string]interface{}, +) (InputItem, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["input"] + if !ok { + var zeroVal InputItem + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNInputItem2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputItem(ctx, tmp) + } + + var zeroVal InputItem + return zeroVal, nil +} + +func (ec *executionContext) field_Mutation_save_argsIsPublic( + ctx context.Context, + rawArgs map[string]interface{}, +) (*bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["isPublic"] + if !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) + if tmp, ok := rawArgs["isPublic"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} func (ec *executionContext) field_Mutation_share_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 InputShareItem - if tmp, ok := rawArgs["input"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) - arg0, err = ec.unmarshalNInputShareItem2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputShareItem(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Mutation_share_argsInput(ctx, rawArgs) + if err != nil { + return nil, err } args["input"] = arg0 return args, nil } +func (ec *executionContext) field_Mutation_share_argsInput( + ctx context.Context, + rawArgs map[string]interface{}, +) (InputShareItem, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["input"] + if !ok { + var zeroVal InputShareItem + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + if tmp, ok := rawArgs["input"]; ok { + return ec.unmarshalNInputShareItem2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋpresentationᚋgraphqlᚐInputShareItem(ctx, tmp) + } + + var zeroVal InputShareItem + return zeroVal, nil +} func (ec *executionContext) field_Query_ShareCondition_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_ShareCondition_argsID(ctx, rawArgs) + if err != nil { + return nil, err } args["id"] = arg0 return args, nil } +func (ec *executionContext) field_Query_ShareCondition_argsID( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["id"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + if tmp, ok := rawArgs["id"]; ok { + return ec.unmarshalNID2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query___type_argsName(ctx, rawArgs) + if err != nil { + return nil, err } args["name"] = arg0 return args, nil } +func (ec *executionContext) field_Query___type_argsName( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["name"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + if tmp, ok := rawArgs["name"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} func (ec *executionContext) field_Query_allItems_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *int - if tmp, ok := rawArgs["offset"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("offset")) - arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_allItems_argsOffset(ctx, rawArgs) + if err != nil { + return nil, err } args["offset"] = arg0 - var arg1 *int - if tmp, ok := rawArgs["limit"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("limit")) - arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Query_allItems_argsLimit(ctx, rawArgs) + if err != nil { + return nil, err } args["limit"] = arg1 return args, nil } +func (ec *executionContext) field_Query_allItems_argsOffset( + ctx context.Context, + rawArgs map[string]interface{}, +) (*int, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["offset"] + if !ok { + var zeroVal *int + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("offset")) + if tmp, ok := rawArgs["offset"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Query_allItems_argsLimit( + ctx context.Context, + rawArgs map[string]interface{}, +) (*int, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["limit"] + if !ok { + var zeroVal *int + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("limit")) + if tmp, ok := rawArgs["limit"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} func (ec *executionContext) field_Query_gistItem_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_gistItem_argsID(ctx, rawArgs) + if err != nil { + return nil, err } args["id"] = arg0 return args, nil } +func (ec *executionContext) field_Query_gistItem_argsID( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["id"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + if tmp, ok := rawArgs["id"]; ok { + return ec.unmarshalNID2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} func (ec *executionContext) field_Query_gistItems_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *int - if tmp, ok := rawArgs["offset"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("offset")) - arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_gistItems_argsOffset(ctx, rawArgs) + if err != nil { + return nil, err } args["offset"] = arg0 - var arg1 *int - if tmp, ok := rawArgs["limit"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("limit")) - arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Query_gistItems_argsLimit(ctx, rawArgs) + if err != nil { + return nil, err } args["limit"] = arg1 return args, nil } +func (ec *executionContext) field_Query_gistItems_argsOffset( + ctx context.Context, + rawArgs map[string]interface{}, +) (*int, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["offset"] + if !ok { + var zeroVal *int + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("offset")) + if tmp, ok := rawArgs["offset"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Query_gistItems_argsLimit( + ctx context.Context, + rawArgs map[string]interface{}, +) (*int, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["limit"] + if !ok { + var zeroVal *int + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("limit")) + if tmp, ok := rawArgs["limit"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} func (ec *executionContext) field_Query_item_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_item_argsID(ctx, rawArgs) + if err != nil { + return nil, err } args["id"] = arg0 - var arg1 *bool - if tmp, ok := rawArgs["isPublic"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) - arg1, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Query_item_argsIsPublic(ctx, rawArgs) + if err != nil { + return nil, err } args["isPublic"] = arg1 return args, nil } +func (ec *executionContext) field_Query_item_argsID( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["id"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + if tmp, ok := rawArgs["id"]; ok { + return ec.unmarshalNID2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + +func (ec *executionContext) field_Query_item_argsIsPublic( + ctx context.Context, + rawArgs map[string]interface{}, +) (*bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["isPublic"] + if !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) + if tmp, ok := rawArgs["isPublic"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} func (ec *executionContext) field_Query_items_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *int - if tmp, ok := rawArgs["offset"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("offset")) - arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_items_argsOffset(ctx, rawArgs) + if err != nil { + return nil, err } args["offset"] = arg0 - var arg1 *int - if tmp, ok := rawArgs["limit"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("limit")) - arg1, err = ec.unmarshalOInt2ᚖint(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Query_items_argsLimit(ctx, rawArgs) + if err != nil { + return nil, err } args["limit"] = arg1 - var arg2 *bool - if tmp, ok := rawArgs["isBookmark"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isBookmark")) - arg2, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) - if err != nil { - return nil, err - } + arg2, err := ec.field_Query_items_argsIsBookmark(ctx, rawArgs) + if err != nil { + return nil, err } args["isBookmark"] = arg2 - var arg3 *bool - if tmp, ok := rawArgs["isPublic"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) - arg3, err = ec.unmarshalOBoolean2ᚖbool(ctx, tmp) - if err != nil { - return nil, err - } + arg3, err := ec.field_Query_items_argsIsPublic(ctx, rawArgs) + if err != nil { + return nil, err } args["isPublic"] = arg3 return args, nil } +func (ec *executionContext) field_Query_items_argsOffset( + ctx context.Context, + rawArgs map[string]interface{}, +) (*int, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["offset"] + if !ok { + var zeroVal *int + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("offset")) + if tmp, ok := rawArgs["offset"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Query_items_argsLimit( + ctx context.Context, + rawArgs map[string]interface{}, +) (*int, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["limit"] + if !ok { + var zeroVal *int + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("limit")) + if tmp, ok := rawArgs["limit"]; ok { + return ec.unmarshalOInt2ᚖint(ctx, tmp) + } + + var zeroVal *int + return zeroVal, nil +} + +func (ec *executionContext) field_Query_items_argsIsBookmark( + ctx context.Context, + rawArgs map[string]interface{}, +) (*bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["isBookmark"] + if !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("isBookmark")) + if tmp, ok := rawArgs["isBookmark"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} + +func (ec *executionContext) field_Query_items_argsIsPublic( + ctx context.Context, + rawArgs map[string]interface{}, +) (*bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["isPublic"] + if !ok { + var zeroVal *bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("isPublic")) + if tmp, ok := rawArgs["isPublic"]; ok { + return ec.unmarshalOBoolean2ᚖbool(ctx, tmp) + } + + var zeroVal *bool + return zeroVal, nil +} func (ec *executionContext) field_Query_settings_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 *values.Diagram - if tmp, ok := rawArgs["diagram"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("diagram")) - arg0, err = ec.unmarshalNDiagram2ᚖgithubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋvaluesᚐDiagram(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_settings_argsDiagram(ctx, rawArgs) + if err != nil { + return nil, err } args["diagram"] = arg0 return args, nil } +func (ec *executionContext) field_Query_settings_argsDiagram( + ctx context.Context, + rawArgs map[string]interface{}, +) (*values.Diagram, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["diagram"] + if !ok { + var zeroVal *values.Diagram + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("diagram")) + if tmp, ok := rawArgs["diagram"]; ok { + return ec.unmarshalNDiagram2ᚖgithubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋvaluesᚐDiagram(ctx, tmp) + } + + var zeroVal *values.Diagram + return zeroVal, nil +} func (ec *executionContext) field_Query_shareItem_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["token"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("token")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field_Query_shareItem_argsToken(ctx, rawArgs) + if err != nil { + return nil, err } args["token"] = arg0 - var arg1 *string - if tmp, ok := rawArgs["password"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("password")) - arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) - if err != nil { - return nil, err - } + arg1, err := ec.field_Query_shareItem_argsPassword(ctx, rawArgs) + if err != nil { + return nil, err } args["password"] = arg1 return args, nil } +func (ec *executionContext) field_Query_shareItem_argsToken( + ctx context.Context, + rawArgs map[string]interface{}, +) (string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["token"] + if !ok { + var zeroVal string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("token")) + if tmp, ok := rawArgs["token"]; ok { + return ec.unmarshalNString2string(ctx, tmp) + } + + var zeroVal string + return zeroVal, nil +} + +func (ec *executionContext) field_Query_shareItem_argsPassword( + ctx context.Context, + rawArgs map[string]interface{}, +) (*string, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["password"] + if !ok { + var zeroVal *string + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("password")) + if tmp, ok := rawArgs["password"]; ok { + return ec.unmarshalOString2ᚖstring(ctx, tmp) + } + + var zeroVal *string + return zeroVal, nil +} func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field___Type_enumValues_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err } args["includeDeprecated"] = arg0 return args, nil } +func (ec *executionContext) field___Type_enumValues_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]interface{}, +) (bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["includeDeprecated"] + if !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } + arg0, err := ec.field___Type_fields_argsIncludeDeprecated(ctx, rawArgs) + if err != nil { + return nil, err } args["includeDeprecated"] = arg0 return args, nil } +func (ec *executionContext) field___Type_fields_argsIncludeDeprecated( + ctx context.Context, + rawArgs map[string]interface{}, +) (bool, error) { + // We won't call the directive if the argument is null. + // Set call_argument_directives_with_null to true to call directives + // even if the argument is null. + _, ok := rawArgs["includeDeprecated"] + if !ok { + var zeroVal bool + return zeroVal, nil + } + + ctx = graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + if tmp, ok := rawArgs["includeDeprecated"]; ok { + return ec.unmarshalOBoolean2bool(ctx, tmp) + } + + var zeroVal bool + return zeroVal, nil +} // endregion ***************************** args.gotpl ***************************** @@ -1308,7 +1810,7 @@ func (ec *executionContext) _Color_foregroundColor(ctx context.Context, field gr return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Color_foregroundColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Color_foregroundColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Color", Field: field, @@ -1352,7 +1854,7 @@ func (ec *executionContext) _Color_backgroundColor(ctx context.Context, field gr return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Color_backgroundColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Color_backgroundColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Color", Field: field, @@ -1396,7 +1898,7 @@ func (ec *executionContext) _GistItem_id(ctx context.Context, field graphql.Coll return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1440,7 +1942,7 @@ func (ec *executionContext) _GistItem_url(ctx context.Context, field graphql.Col return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_url(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_url(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1484,7 +1986,7 @@ func (ec *executionContext) _GistItem_title(ctx context.Context, field graphql.C return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_title(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1525,7 +2027,7 @@ func (ec *executionContext) _GistItem_thumbnail(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_thumbnail(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_thumbnail(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1569,7 +2071,7 @@ func (ec *executionContext) _GistItem_diagram(ctx context.Context, field graphql return ec.marshalNDiagram2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋvaluesᚐDiagram(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_diagram(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_diagram(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1613,7 +2115,7 @@ func (ec *executionContext) _GistItem_isBookmark(ctx context.Context, field grap return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_isBookmark(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_isBookmark(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1657,7 +2159,7 @@ func (ec *executionContext) _GistItem_createdAt(ctx context.Context, field graph return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1701,7 +2203,7 @@ func (ec *executionContext) _GistItem_updatedAt(ctx context.Context, field graph return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_GistItem_updatedAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_GistItem_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "GistItem", Field: field, @@ -1745,7 +2247,7 @@ func (ec *executionContext) _Item_id(ctx context.Context, field graphql.Collecte return ec.marshalNID2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_id(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -1789,7 +2291,7 @@ func (ec *executionContext) _Item_title(ctx context.Context, field graphql.Colle return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_title(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_title(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -1833,7 +2335,7 @@ func (ec *executionContext) _Item_text(ctx context.Context, field graphql.Collec return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_text(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_text(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -1874,7 +2376,7 @@ func (ec *executionContext) _Item_thumbnail(ctx context.Context, field graphql.C return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_thumbnail(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_thumbnail(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -1918,7 +2420,7 @@ func (ec *executionContext) _Item_diagram(ctx context.Context, field graphql.Col return ec.marshalNDiagram2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋvaluesᚐDiagram(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_diagram(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_diagram(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -1962,7 +2464,7 @@ func (ec *executionContext) _Item_isPublic(ctx context.Context, field graphql.Co return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_isPublic(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_isPublic(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -2006,7 +2508,7 @@ func (ec *executionContext) _Item_isBookmark(ctx context.Context, field graphql. return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_isBookmark(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_isBookmark(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -2050,7 +2552,7 @@ func (ec *executionContext) _Item_createdAt(ctx context.Context, field graphql.C return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_createdAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -2094,7 +2596,7 @@ func (ec *executionContext) _Item_updatedAt(ctx context.Context, field graphql.C return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Item_updatedAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Item_updatedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Item", Field: field, @@ -3255,7 +3757,7 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Query___schema(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Query", Field: field, @@ -3313,7 +3815,7 @@ func (ec *executionContext) _Settings_font(ctx context.Context, field graphql.Co return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_font(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_font(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3357,7 +3859,7 @@ func (ec *executionContext) _Settings_width(ctx context.Context, field graphql.C return ec.marshalNInt2int(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_width(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_width(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3401,7 +3903,7 @@ func (ec *executionContext) _Settings_height(ctx context.Context, field graphql. return ec.marshalNInt2int(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_height(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_height(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3445,7 +3947,7 @@ func (ec *executionContext) _Settings_backgroundColor(ctx context.Context, field return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_backgroundColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_backgroundColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3489,7 +3991,7 @@ func (ec *executionContext) _Settings_activityColor(ctx context.Context, field g return ec.marshalNColor2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋmodelᚋsettingsᚐColor(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_activityColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_activityColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3539,7 +4041,7 @@ func (ec *executionContext) _Settings_taskColor(ctx context.Context, field graph return ec.marshalNColor2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋmodelᚋsettingsᚐColor(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_taskColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_taskColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3589,7 +4091,7 @@ func (ec *executionContext) _Settings_storyColor(ctx context.Context, field grap return ec.marshalNColor2githubᚗcomᚋharehareᚋtextusmᚋinternalᚋdomainᚋmodelᚋsettingsᚐColor(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_storyColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_storyColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3639,7 +4141,7 @@ func (ec *executionContext) _Settings_lineColor(ctx context.Context, field graph return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_lineColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_lineColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3683,7 +4185,7 @@ func (ec *executionContext) _Settings_labelColor(ctx context.Context, field grap return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_labelColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_labelColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3724,7 +4226,7 @@ func (ec *executionContext) _Settings_textColor(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_textColor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_textColor(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3765,7 +4267,7 @@ func (ec *executionContext) _Settings_zoomControl(ctx context.Context, field gra return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_zoomControl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_zoomControl(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3806,7 +4308,7 @@ func (ec *executionContext) _Settings_scale(ctx context.Context, field graphql.C return ec.marshalOFloat2ᚖfloat64(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_scale(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_scale(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3847,7 +4349,7 @@ func (ec *executionContext) _Settings_toolbar(ctx context.Context, field graphql return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_toolbar(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_toolbar(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3888,7 +4390,7 @@ func (ec *executionContext) _Settings_lockEditing(ctx context.Context, field gra return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_lockEditing(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_lockEditing(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3929,7 +4431,7 @@ func (ec *executionContext) _Settings_showGrid(ctx context.Context, field graphq return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_Settings_showGrid(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_Settings_showGrid(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "Settings", Field: field, @@ -3973,7 +4475,7 @@ func (ec *executionContext) _ShareCondition_token(ctx context.Context, field gra return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ShareCondition_token(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ShareCondition_token(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ShareCondition", Field: field, @@ -4017,7 +4519,7 @@ func (ec *executionContext) _ShareCondition_usePassword(ctx context.Context, fie return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ShareCondition_usePassword(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ShareCondition_usePassword(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ShareCondition", Field: field, @@ -4061,7 +4563,7 @@ func (ec *executionContext) _ShareCondition_expireTime(ctx context.Context, fiel return ec.marshalNInt2int(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ShareCondition_expireTime(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ShareCondition_expireTime(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ShareCondition", Field: field, @@ -4102,7 +4604,7 @@ func (ec *executionContext) _ShareCondition_allowIPList(ctx context.Context, fie return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ShareCondition_allowIPList(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ShareCondition_allowIPList(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ShareCondition", Field: field, @@ -4143,7 +4645,7 @@ func (ec *executionContext) _ShareCondition_allowEmailList(ctx context.Context, return ec.marshalOString2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext_ShareCondition_allowEmailList(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext_ShareCondition_allowEmailList(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "ShareCondition", Field: field, @@ -4187,7 +4689,7 @@ func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, @@ -4228,7 +4730,7 @@ func (ec *executionContext) ___Directive_description(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, @@ -4272,7 +4774,7 @@ func (ec *executionContext) ___Directive_locations(ctx context.Context, field gr return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_locations(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, @@ -4316,7 +4818,7 @@ func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_args(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, @@ -4370,7 +4872,7 @@ func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Directive_isRepeatable(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Directive", Field: field, @@ -4414,7 +4916,7 @@ func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -4455,7 +4957,7 @@ func (ec *executionContext) ___EnumValue_description(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -4499,7 +5001,7 @@ func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -4540,7 +5042,7 @@ func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___EnumValue_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__EnumValue", Field: field, @@ -4584,7 +5086,7 @@ func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.Col return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -4625,7 +5127,7 @@ func (ec *executionContext) ___Field_description(ctx context.Context, field grap return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -4669,7 +5171,7 @@ func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.Col return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_args(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -4723,7 +5225,7 @@ func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.Col return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -4789,7 +5291,7 @@ func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field gra return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_isDeprecated(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -4830,7 +5332,7 @@ func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Field_deprecationReason(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Field", Field: field, @@ -4874,7 +5376,7 @@ func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphq return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -4915,7 +5417,7 @@ func (ec *executionContext) ___InputValue_description(ctx context.Context, field return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -4959,7 +5461,7 @@ func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphq return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_type(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -5022,7 +5524,7 @@ func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, fiel return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___InputValue_defaultValue(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__InputValue", Field: field, @@ -5063,7 +5565,7 @@ func (ec *executionContext) ___Schema_description(ctx context.Context, field gra return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -5107,7 +5609,7 @@ func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.C return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_types(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -5173,7 +5675,7 @@ func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graph return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_queryType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -5236,7 +5738,7 @@ func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field gr return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_mutationType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -5299,7 +5801,7 @@ func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, fiel return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_subscriptionType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -5365,7 +5867,7 @@ func (ec *executionContext) ___Schema_directives(ctx context.Context, field grap return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Schema_directives(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Schema", Field: field, @@ -5421,7 +5923,7 @@ func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.Coll return ec.marshalN__TypeKind2string(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_kind(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -5462,7 +5964,7 @@ func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.Coll return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_name(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -5503,7 +6005,7 @@ func (ec *executionContext) ___Type_description(ctx context.Context, field graph return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_description(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -5610,7 +6112,7 @@ func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphq return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_interfaces(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -5673,7 +6175,7 @@ func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field gra return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_possibleTypes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -5798,7 +6300,7 @@ func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graph return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_inputFields(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -5849,7 +6351,7 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_ofType(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -5912,7 +6414,7 @@ func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field gr return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { +func (ec *executionContext) fieldContext___Type_specifiedByURL(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { fc = &graphql.FieldContext{ Object: "__Type", Field: field, @@ -6655,7 +7157,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr case "allItems": field := field - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -6740,7 +7242,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr case "ShareCondition": field := field - innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) diff --git a/backend/internal/presentation/graphql/query.go b/backend/internal/presentation/graphql/query.go index 1338b31b0..a218fe324 100644 --- a/backend/internal/presentation/graphql/query.go +++ b/backend/internal/presentation/graphql/query.go @@ -76,10 +76,6 @@ func (r *queryResolver) AllItems(ctx context.Context, offset, limit *int) ([]uni gistItems := r.gistService.Find(ctx, *offset, *limit) - if err != nil { - return nil, err - } - for _, item := range items { diagramItems = append(diagramItems, item) } diff --git a/backend/justfile b/backend/justfile index 1ac35b199..c40cc2c0c 100644 --- a/backend/justfile +++ b/backend/justfile @@ -5,13 +5,13 @@ module := "github.com/harehare/textusm" sec := "gosec" target := "./..." -setup: - go get honnef.co/go/tools/cmd/staticcheck - go get github.com/securego/gosec/v2/cmd/gosec +install-tools: + go install honnef.co/go/tools/cmd/staticcheck@latest + go install github.com/securego/gosec/v2/cmd/gosec@latest go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest - go install github.com/cosmtrek/air@latest - go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.56.2 - go install github.com/google/wire/cmd/wire@latest + go install github.com/air-verse/air@latest + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + go install github.com/amacneil/dbmate@latest run: go run {{ main }} @@ -35,25 +35,22 @@ generate: go get github.com/urfave/cli/v2 go generate {{ target }} -di: - wire gen ./internal/app/wire.go - test: go test {{ target }} -lint: +lintre: staticcheck {{ target }} gosec {{ target }} golangci-lint run {{ target }} - fix: fieldalignment -fix pkg/domain/model/item/gistitem/gistitem.go fieldalignment -fix pkg/domain/model/item/gistitem/gistitem.go fieldalignment -fix pkg/presentation/graphql/models.go -migrate DATABASE='postgresql': - dbmate -d db/{{DATABASE}}/migrations up +migrate: + DBMATE_SCHEMA_FILE=db/${DB_TYPE}/schema.sql dbmate -d db/${DB_TYPE}/migrations up + DBMATE_SCHEMA_FILE=db/${DB_TYPE}/schema.sql dbmate dump -rollback DATABASE='postgresql': - dbmate -d db/{{DATABASE}}/migrations down +rollback: + DBMATE_SCHEMA_FILE=db/${DB_TYPE}/schema.sql dbmate -d db/${DB_TYPE}/migrations down diff --git a/backend/sqlc.yaml b/backend/sqlc.yaml index a1e34bbbb..10a84e300 100644 --- a/backend/sqlc.yaml +++ b/backend/sqlc.yaml @@ -2,12 +2,19 @@ version: "2" cloud: project: "textusm" sql: - - schema: "db/postgresql/migrations" + - schema: "db/postgresql/schema.sql" queries: "db/postgresql/query.sql" engine: "postgresql" gen: go: - package: "db" - out: "internal/db" + package: "postgres" + out: "internal/db/postgres" sql_package: "pgx/v5" emit_pointers_for_null_types: true + - schema: "db/sqlite/schema.sql" + queries: "db/sqlite/query.sql" + engine: "sqlite" + gen: + go: + package: "sqlite" + out: "internal/db/sqlite" diff --git a/frontend/e2e/textusm.spec.ts b/frontend/e2e/textusm.spec.ts index 63334f41b..a3c9d685b 100644 --- a/frontend/e2e/textusm.spec.ts +++ b/frontend/e2e/textusm.spec.ts @@ -1,4 +1,31 @@ -import { test, expect } from '@playwright/test'; +import { test, expect, Page } from '@playwright/test'; + +const signIn = async (page: Page) => { + // sign in + await page.locator('[data-test-id="header-signin"]').click(); + await page.locator('[data-test-id="google-menu-item"]').click(); + + const popup = await page.waitForEvent('popup'); + await popup.waitForLoadState('networkidle'); + await popup.getByRole('button', { name: /add new account/i }).click(); + await popup.waitForLoadState('networkidle'); + await popup.getByRole('button', { name: /auto-generate/i }).click(); + await popup.getByRole('button', { name: /sign in/i }).click(); + + await page.waitForSelector('[data-test-id="header-title"]'); +}; + +const editTitle = async (page: Page, title: string) => { + await page.locator('[data-test-id="header-title"]').click(); + await page.locator('[data-test-id="header-input-title"]').fill(title); + await page.locator('[data-test-id="header-input-title"]').press('Enter'); +}; + +const editText = async (page: Page, text: string) => { + const monacoEditor = await page.$('monaco-editor'); + await monacoEditor?.evaluate((node, text) => node.setAttribute('value', text), text); + await page.waitForTimeout(500); +}; test('Create new diagram', async ({ page }) => { await page.goto('http://localhost:3000'); @@ -14,16 +41,13 @@ test('Create new diagram', async ({ page }) => { test('Save the diagram to local and load it', async ({ page }) => { await page.goto('http://localhost:3000'); - await page.locator('[data-test-id="header-title"]').click(); - await page.locator('[data-test-id="header-input-title"]').fill('test'); - await page.locator('[data-test-id="header-input-title"]').press('Enter'); - - const monacoEditor = await page.$('monaco-editor'); - await monacoEditor?.evaluate((node) => node.setAttribute('value', 'test1\n test2\n test3')); - await page.waitForTimeout(500); + await editTitle(page, 'test'); + await editText(page, 'test1\n test2\n test3'); + await editText(page, 'test1\n test2\n test3'); await page.locator('[data-test-id="save-menu"]').click(); await page.locator('[data-test-id="list-menu"]').click(); + await page.waitForSelector('[data-test-id="diagram-list-item"]'); await page.locator('[data-test-id="diagram-list-item"]').first().click(); await expect(await page.locator('monaco-editor').getAttribute('value')).toContain(`test1`); @@ -69,3 +93,22 @@ test('Change background color settings', async ({ page }) => { await expect(backgroundColor).toBe(`rgb(254, 254, 254)`); }); + +test('Save the diagram to remote and load it', async ({ page }) => { + await page.goto('http://localhost:3000'); + + await signIn(page); + await editTitle(page, 'test'); + await editText(page, 'test1\n test2\n test3'); + await editText(page, 'test1\n test2\n test3'); + + await page.locator('[data-test-id="save-menu"]').click(); + await page.waitForLoadState('networkidle'); + await page.waitForSelector('[data-test-id="list-menu"]'); + await page.locator('[data-test-id="list-menu"]').click(); + await page.waitForSelector('[data-test-id="diagram-list-item"]'); + await page.locator('[data-test-id="diagram-list-item"]').first().click(); + await page.waitForLoadState('networkidle'); + + await expect(await page.locator('monaco-editor').getAttribute('value')).toContain(`test1`); +}); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7c702094a..f5efe5992 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "textusm", - "version": "0.14.8", + "version": "0.14.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "textusm", - "version": "0.14.8", + "version": "0.14.9", "license": "MIT", "dependencies": { "@sentry/browser": "^8.26.0", @@ -43,6 +43,7 @@ "elm-review": "^2.12.0", "elm-test": "^0.19.1-revision12", "firebase-tools": "^13.15.1", + "kill-port": "^2.0.1", "prettier": "^3.3.3", "rimraf": "^6.0.1", "size-limit": "^11.0.2", @@ -13165,6 +13166,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-them-args": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/get-them-args/-/get-them-args-1.3.2.tgz", + "integrity": "sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==", + "dev": true + }, "node_modules/get-tsconfig": { "version": "4.7.5", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", @@ -15200,6 +15207,19 @@ "json-buffer": "3.0.1" } }, + "node_modules/kill-port": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kill-port/-/kill-port-2.0.1.tgz", + "integrity": "sha512-e0SVOV5jFo0mx8r7bS29maVWp17qGqLBZ5ricNSajON6//kmb7qqqNnml4twNE8Dtj97UQD+gNFOaipS/q1zzQ==", + "dev": true, + "dependencies": { + "get-them-args": "1.3.2", + "shell-exec": "1.0.2" + }, + "bin": { + "kill-port": "cli.js" + } + }, "node_modules/kind-of": { "version": "6.0.3", "dev": true, @@ -18314,6 +18334,12 @@ "node": ">=0.10.0" } }, + "node_modules/shell-exec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shell-exec/-/shell-exec-1.0.2.tgz", + "integrity": "sha512-jyVd+kU2X+mWKMmGhx4fpWbPsjvD53k9ivqetutVW/BQ+WIZoDoP4d8vUMGezV6saZsiNoW2f9GIhg9Dondohg==", + "dev": true + }, "node_modules/shell-quote": { "version": "1.8.1", "dev": true, diff --git a/frontend/package.json b/frontend/package.json index 3b3cf463e..75070fe93 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -42,6 +42,7 @@ "elm-review": "^2.12.0", "elm-test": "^0.19.1-revision12", "firebase-tools": "^13.15.1", + "kill-port": "^2.0.1", "prettier": "^3.3.3", "rimraf": "^6.0.1", "size-limit": "^11.0.2", @@ -67,9 +68,9 @@ "build:lib": "elm make src/elm/Extension/Lib.elm --optimize --output elm.optimized.js && terser elm.optimized.js --compress 'pure_funcs=\"F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9\",pure_getters,keep_fargs=false,unsafe_comps,unsafe' --mangle --output=elm.js && rimraf elm.optimized.js && mv elm.js ../extension/lib/src/js/", "build:vscode": "elm make src/elm/Extension/VSCode.elm --optimize --output elm.optimized.js && terser elm.optimized.js --compress 'pure_funcs=\"F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9\",pure_getters,keep_fargs=false,unsafe_comps,unsafe' --mangle --output=elm.js && rimraf elm.optimized.js && mv elm.js ../extension/vscode/js/", "dev": "concurrently \"npm:dev:*\"", + "dev:emulators": "cd .. && mkdir -p data && firebase emulators:start --only firestore,auth,storage --import=data", "dev:frontend": "npm run generate:elm-constants && vite", "dev:backend": "cd ../backend/ && just watch", - "dev:emulators": "cd .. && mkdir -p data && firebase emulators:start --only firestore,auth,storage --import=data", "embed:build": "npm run prod && cp -r dist ../backend/internal/app", "format:ts": "prettier --write src/**/*.ts", "format:elm": "elm-format src/**/*.elm", @@ -87,12 +88,13 @@ "lint-fix:elm": "elm-review --fix", "prod": "NODE_ENV=production NODE_OPTIONS='--max-old-space-size=4096' vite build", "postprod": "rimraf -rf dist/*.map", - "preview": "concurrently \"vite preview\" \"npm run dev:backend\"", + "preview": "concurrently \"vite preview\" \"cd ../backend/ && just run\"", + "preview:dev": "concurrently \"npm run dev:frontend\" \"cd ../backend/ && just run\"", "prepreview": "npm run prod", "setup:emulators": "cd .. && firebase init emulators", "test": "elm-test", "test:e2e:init": "playwright install --with-deps", - "test:e2e": "USE_HTTPS=0 playwright test" + "test:e2e": "firebase emulators:exec --only auth 'playwright test' ; kill-port 8081" }, "browserslist": [ "defaults" diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index bd6f0e9b8..7fba4bf85 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -21,8 +21,10 @@ export default defineConfig({ }, ], webServer: { - command: 'FIREBASE_AUTH_EMULATOR_HOST="localhost:9099" USE_HTTPS=0 npm run dev:frontend', - url: 'http://127.0.0.1:3000', + command: 'DB_TYPE=sqlite FIREBASE_AUTH_EMULATOR_HOST="localhost:9099" USE_HTTPS=0 npm run preview:dev', + url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, + stdout: 'pipe', + stderr: 'pipe', }, }); diff --git a/frontend/src/elm/Main.elm b/frontend/src/elm/Main.elm index 264cef420..e998c3961 100644 --- a/frontend/src/elm/Main.elm +++ b/frontend/src/elm/Main.elm @@ -660,62 +660,62 @@ openCurrentFile diagram = save : Return.ReturnF Msg Model save = - (\m -> - Return.singleton m - |> (let - location : Location - location = - m.currentDiagram.location - |> Maybe.withDefault - (if - m.currentDiagram - |> DiagramItem.isRemoteDiagram m.session - then - m.settingsModel.settings.location - |> Maybe.withDefault DiagramLocation.Remote - - else - DiagramLocation.Local - ) - - newDiagramModel : Diagram.Types.Model - newDiagramModel = - Diagram.Types.updatedText m.diagramModel (Text.saved m.diagramModel.text) - - diagram : DiagramItem - diagram = - m.currentDiagram - |> DiagramItem.text.set newDiagramModel.text - |> DiagramItem.thumbnail.set Nothing - |> DiagramItem.location.set (Just location) - |> DiagramItem.diagram.set newDiagramModel.diagramType - in - Return.map - (\m_ -> - { m_ - | diagramModel = newDiagramModel - , diagramListModel = m_.diagramListModel |> Page.List.diagramList.set Page.List.DiagramList.notAsked - } - ) - >> (case ( location, Session.loginProvider m.session ) of - ( DiagramLocation.Gist, Just (LoginProvider.Github Nothing) ) -> - Effect.getGistTokenAfterSave + Return.andThen + (\m -> + Return.singleton m + |> (let + location : Location + location = + m.currentDiagram.location + |> Maybe.withDefault + (if + m.currentDiagram + |> DiagramItem.isRemoteDiagram m.session + then + m.settingsModel.settings.location + |> Maybe.withDefault DiagramLocation.Remote + + else + DiagramLocation.Local + ) + + newDiagramModel : Diagram.Types.Model + newDiagramModel = + Diagram.Types.updatedText m.diagramModel (Text.saved m.diagramModel.text) + + diagram : DiagramItem + diagram = + m.currentDiagram + |> DiagramItem.text.set newDiagramModel.text + |> DiagramItem.thumbnail.set Nothing + |> DiagramItem.location.set (Just location) + |> DiagramItem.diagram.set newDiagramModel.diagramType + in + Return.map + (\m_ -> + { m_ + | diagramModel = newDiagramModel + , diagramListModel = m_.diagramListModel |> Page.List.diagramList.set Page.List.DiagramList.notAsked + } + ) + >> (case ( location, Session.loginProvider m.session ) of + ( DiagramLocation.Gist, Just (LoginProvider.Github Nothing) ) -> + Effect.getGistTokenAfterSave - ( DiagramLocation.Gist, _ ) -> - Diagram.Effect.save diagram + ( DiagramLocation.Gist, _ ) -> + Diagram.Effect.save diagram - ( DiagramLocation.Remote, _ ) -> - Diagram.Effect.save diagram + ( DiagramLocation.Remote, _ ) -> + Diagram.Effect.save diagram - ( DiagramLocation.LocalFileSystem, _ ) -> - Return.zero + ( DiagramLocation.LocalFileSystem, _ ) -> + Return.zero - ( DiagramLocation.Local, _ ) -> - Diagram.Effect.save diagram - ) - ) - ) - |> Return.andThen + ( DiagramLocation.Local, _ ) -> + Diagram.Effect.save diagram + ) + ) + ) signIn : Session.User -> Return.ReturnF Msg Model diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 5d928187b..fecaad163 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -7,7 +7,7 @@ "moduleResolution": "node", "esModuleInterop": true, "lib": ["esnext", "dom"], - "rootDir": "src/ts", + "rootDir": ".", "importHelpers": true, "noImplicitAny": true, "strictNullChecks": true, @@ -17,5 +17,6 @@ "exactOptionalPropertyTypes": false, "types": ["jspdf", "requestidlecallback", "uuid", "wicg-file-system-access", "node", "vite/client"] }, - "exclude": ["**/node_modules/*", "**/*.spec.ts", "vite.config.ts"] + "include": ["src/ts", "vite.config.ts", "playwright.config.ts"], + "exclude": ["**/node_modules/*", "**/*.spec.ts"] } From d23ee7bfedf933794f34dc826d13eff30f2c10bd Mon Sep 17 00:00:00 2001 From: harehare Date: Wed, 30 Oct 2024 22:38:16 +0900 Subject: [PATCH 2/2] :green_heart: Fix e2e test --- .github/workflows/test.yml | 4 ++-- frontend/e2e/textusm.spec.ts | 4 +++- frontend/package.json | 4 +--- frontend/playwright.config.ts | 25 ++++++++++++++++++------- lua/init.lua | 13 +++++++++++++ 5 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 lua/init.lua diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 88de20062..8d66b45c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -98,8 +98,8 @@ jobs: run: npm run test:e2e working-directory: frontend env: - API_ROOT: ${{ secrets.API_ROOT }} - WEB_ROOT: ${{ secrets.WEB_ROOT }} + API_ROOT: http://localhost:8081 + WEB_ROOT: http://localhost:3000 APP_VERSION: "" FIREBASE_API_KEY: textusm FIREBASE_AUTH_DOMAIN: textusm diff --git a/frontend/e2e/textusm.spec.ts b/frontend/e2e/textusm.spec.ts index a3c9d685b..bf2005efe 100644 --- a/frontend/e2e/textusm.spec.ts +++ b/frontend/e2e/textusm.spec.ts @@ -103,10 +103,12 @@ test('Save the diagram to remote and load it', async ({ page }) => { await editText(page, 'test1\n test2\n test3'); await page.locator('[data-test-id="save-menu"]').click(); + await page.waitForURL(/edit.+/); + await page.waitForLoadState('networkidle'); await page.waitForSelector('[data-test-id="list-menu"]'); await page.locator('[data-test-id="list-menu"]').click(); - await page.waitForSelector('[data-test-id="diagram-list-item"]'); + await page.waitForLoadState('networkidle'); await page.locator('[data-test-id="diagram-list-item"]').first().click(); await page.waitForLoadState('networkidle'); diff --git a/frontend/package.json b/frontend/package.json index 75070fe93..8ad9e5cf7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -42,7 +42,6 @@ "elm-review": "^2.12.0", "elm-test": "^0.19.1-revision12", "firebase-tools": "^13.15.1", - "kill-port": "^2.0.1", "prettier": "^3.3.3", "rimraf": "^6.0.1", "size-limit": "^11.0.2", @@ -89,12 +88,11 @@ "prod": "NODE_ENV=production NODE_OPTIONS='--max-old-space-size=4096' vite build", "postprod": "rimraf -rf dist/*.map", "preview": "concurrently \"vite preview\" \"cd ../backend/ && just run\"", - "preview:dev": "concurrently \"npm run dev:frontend\" \"cd ../backend/ && just run\"", "prepreview": "npm run prod", "setup:emulators": "cd .. && firebase init emulators", "test": "elm-test", "test:e2e:init": "playwright install --with-deps", - "test:e2e": "firebase emulators:exec --only auth 'playwright test' ; kill-port 8081" + "test:e2e": "firebase emulators:exec --only auth 'playwright test'" }, "browserslist": [ "defaults" diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index 7fba4bf85..c3e11a612 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -20,11 +20,22 @@ export default defineConfig({ use: { ...devices['Desktop Firefox'] }, }, ], - webServer: { - command: 'DB_TYPE=sqlite FIREBASE_AUTH_EMULATOR_HOST="localhost:9099" USE_HTTPS=0 npm run preview:dev', - url: 'http://localhost:3000', - reuseExistingServer: !process.env.CI, - stdout: 'pipe', - stderr: 'pipe', - }, + webServer: [ + { + command: 'npm run dev:frontend', + url: 'http://localhost:3000', + reuseExistingServer: !process.env.CI, + timeout: 10 * 60 * 1000, + stdout: 'pipe', + stderr: 'pipe', + }, + { + command: 'cd ../backend && DB_TYPE=sqlite FIREBASE_AUTH_EMULATOR_HOST="localhost:9099" USE_HTTPS=0 just run', + url: 'http://localhost:8081/healthcheck', + reuseExistingServer: !process.env.CI, + timeout: 10 * 60 * 1000, + stdout: 'pipe', + stderr: 'pipe', + }, + ], }); diff --git a/lua/init.lua b/lua/init.lua new file mode 100644 index 000000000..0a111fb55 --- /dev/null +++ b/lua/init.lua @@ -0,0 +1,13 @@ +local M = {} + +local testModule = require('simple-nvim-plugin/testModule') + +function M.test() + print('hello world'); +end + +function M.callModule(str) + testModule.test(str) +end + +return M