Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6253c33
[FE] Add node-sass & typed-scss-modules
OHUSAR Mar 27, 2021
75690ea
[BE] Add marina field resolvers
OHUSAR Mar 27, 2021
23ee3b0
[BE] Resolve city, country, amenity id from code
OHUSAR Mar 27, 2021
6ac4929
[BE] Fix amenity.TYPE not using amenity.resolver
OHUSAR Mar 27, 2021
c0de4b6
[BE] Add marina (by id) query
OHUSAR Mar 27, 2021
0be2552
[FE] Add simple Routes class for path config
OHUSAR Mar 27, 2021
7ecb7f6
[FE] Implement basic layout
OHUSAR Mar 27, 2021
bbda8e0
[FE & BE] Config, schema & codegen
OHUSAR Mar 27, 2021
e4f55a7
[FE] Polish MarinaList design & add basic responsivity
OHUSAR Mar 27, 2021
9d21fc1
[FE] Add mapbox lib
OHUSAR Mar 27, 2021
57b98e0
[FE] Add 'AddMarina' form (without mutation)
OHUSAR Mar 27, 2021
8d525ac
[BE] Add country resolver to City node
OHUSAR Mar 27, 2021
cdb794b
[BE] Add yup
OHUSAR Mar 27, 2021
8a1b5b0
[BE] Add AddMarina mutation & Yup validation
OHUSAR Mar 27, 2021
98d7e48
[FE] Actually send mutation on submit button click
OHUSAR Mar 27, 2021
66358eb
[BE] Add resolver that saves marina to db
OHUSAR Mar 28, 2021
770bf83
[FE] Show success/error snackbar & redirect to marina
OHUSAR Mar 28, 2021
b261cd1
[FE + BE] Display very slightly better error message
OHUSAR Mar 28, 2021
ed59bd0
[FE] Add marina detail scene & amenities
OHUSAR Mar 28, 2021
b7ed9f9
[FE] Add header
OHUSAR Mar 28, 2021
ba6459f
[BE] Fix addMarina not creating marina_and_amenity rows
OHUSAR Mar 28, 2021
362d678
[FE] Add key={..} to components in .map
OHUSAR Mar 28, 2021
9b909a8
[FE] Tidy up (slightly :))
OHUSAR Mar 28, 2021
0eca233
[BE] Add query for all marinas in city / country
OHUSAR Mar 28, 2021
441b7f5
[BE + FE] Add MarinaConnection & very simple FE pagination
OHUSAR Mar 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/be/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

## gql types / codegen

- `yarn codegen`
- `yarn generate`

## db types

Expand Down
1 change: 1 addition & 0 deletions packages/be/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"dependencies": {
"@babel/runtime": "^7.13.10",
"@koa/cors": "^3.1.0",
"@types/yup": "^0.29.11",
"apollo-server-koa": "^2.21.2",
"cross-env": "^7.0.3",
"dotenv-safe": "^8.2.0",
Expand Down
Binary file modified packages/be/seasy.db
Binary file not shown.
11 changes: 11 additions & 0 deletions packages/be/src/db/amenity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { amenityDb } from "../types/GeneratedDb";
import kx from "./kx";

export const getAmenityByMarinaId = (marinaId: number) => {
return getAmenityBase()
.join(
"marina_and_amenity",
"amenity.code",
"marina_and_amenity.amenity_code"
)
.where("marina_id", marinaId)
.select("code");
};

export const getAmenityBase = () => kx<amenityDb>("amenity");
9 changes: 3 additions & 6 deletions packages/be/src/db/kx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ const kxConfig = {

const kx = Knex(knexStringcase(kxConfig));

// kx.on("query-response", (res) => {
// // if (res && res[0] && res[0].dateTo) {
// // console.log(res.length);
// // }
// console.log(res);
// });
kx.on("query-response", res => {
// console.log(res);
});

export default kx;
64 changes: 62 additions & 2 deletions packages/be/src/db/marina.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,64 @@
import { marinaDb } from "../types/GeneratedDb";
import { marinaDb, cityDb, countryDb, photoDb, marinaAndAmenityDb } from "../types/GeneratedDb";
import { MutationAddMarinaArgs } from "../types/GeneratedGql";

import kx from "./kx";
import { getOrCreateEntity } from "./utils";

export const getMarinaBase = () => {
return kx<marinaDb>("marina");
};

export const getMarinaById = (id: number) => {
return getMarinaBase()
.where("id", id)
.first();
};

export const getAllMarinasInACity = (cityCode: string) => {
return getMarinaBase().where("city_code", cityCode);
}

export const getAllMarinasInACountry = (countryCode: string) => {
return getMarinaBase().where("country_code", countryCode);
}

export const saveMarinaToDb = async (input: MutationAddMarinaArgs["input"]) => {
const countryPromise = getOrCreateEntity<countryDb>(
"country",
"code",
input.country,
{}
);
const cityPromise = getOrCreateEntity<cityDb>("city", "code", input.city, {
countryCode: input.country,
lat: input.lat,
lon: input.lon,
});
let photoPromise: Promise<photoDb | null> = Promise.resolve(null);
if (input.photoUrl) {
photoPromise = getOrCreateEntity<photoDb>("photo", "url", input.photoUrl, {
url: input.photoUrl,
});
}

export const getMarinaBase = () => kx<marinaDb>("marina");
return Promise.all([countryPromise, cityPromise, photoPromise]).then(
([country, city, photo]) => {
return kx<marinaDb>("marina").insert({
name: input.name,
cityCode: city.code,
lat: city.lat,
lon: city.lon,
countryCode: country.code,
photoId: photo ? photo.id : undefined,
});
}
).then(marina => {
const marinaId = marina[0];
const marinaAndAmenity = input.amenities ? input.amenities.map(code => ({marinaId, amenityCode: code})) : null;
let amenitiesPromise = Promise.resolve();
if (marinaAndAmenity) {
amenitiesPromise = kx<marinaAndAmenityDb>("marina_and_amenity").insert(marinaAndAmenity);
}
return Promise.all([Promise.resolve(marina), amenitiesPromise]);
});
};
32 changes: 32 additions & 0 deletions packages/be/src/db/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import kx from "./kx";

export const getOrCreateEntity = <T>(
tableName: string,
whereArgName: string,
whereArgValue: string,
extraDataToInsert: Partial<T>
) => {
return kx
.transaction<T[]>((trx) => {
trx<T>(tableName)
.where(whereArgName, whereArgValue)
.then((res) => {
if (res.length === 0) {
return kx(tableName)
.transacting(trx)
.insert({ [whereArgName]: whereArgValue, ...extraDataToInsert })

.then(() => {
return trx(tableName).where(whereArgName, whereArgValue);
});
} else {
return res;
}
})
.then(trx.commit)
.catch(trx.rollback);
})
.then((res) => {
return res[0];
});
};
43 changes: 40 additions & 3 deletions packages/be/src/mutations/marina.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,52 @@
import { ApolloError } from "apollo-server-koa";
import { fromGlobalId } from "graphql-relay";
import * as Yup from "yup";

import { getMarinaBase, saveMarinaToDb } from "../db/marina";

import { ApolloContext } from "../types/ApolloContext";
import { MutationAddMarinaArgs } from "../types/GeneratedGql";

const schemaValidation = Yup.object().shape({
name: Yup.string()
.min(3)
.required("Required"),
photoUrl: Yup.string().url(),
lat: Yup.number().required("Required"),
lon: Yup.number().required("Required"),
city: Yup.string()
.min(3)
.required("Required"),
country: Yup.string()
.min(3)
.required("Required"),
amenities: Yup.array()
.of(Yup.string().min(3))
.required("Required"),
});

export const addMarina = async (
parent: unknown,
{ input }: MutationAddMarinaArgs,
ctx: ApolloContext
) => {
const dbId = fromGlobalId(input.id);

// TODO:
return schemaValidation
.isValid(input)
.then((isValid) => {
if (isValid) {
return saveMarinaToDb(input);
} else {
throw new ApolloError("Invalid input arguments.");
}
})
.then(async ([result]) => {
if (result && result.length) {
const marina = await getMarinaBase()
.where({ id: result[0] })
.first();
return { marina };
} else {
throw new ApolloError("Marina not created.");
}
});
};
54 changes: 52 additions & 2 deletions packages/be/src/query/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,68 @@
import { gql } from "apollo-server-koa";
import { getMarinaBase } from "../db/marina";
import { getMarinaBase, getMarinaById } from "../db/marina";
import { QueryResolvers } from "../types/GeneratedGql";
import { fromGlobalId } from "graphql-relay";
import { getAmenityBase } from "../db/amenity";
import { getCityBase } from "../db/city";
import { getCountryBase } from "../db/country";
import { getPhotoBase } from "../db/photo";
import { marinaDb } from "../types/GeneratedDb";

export const schema = gql`
type MarinaConnection {
edges: [MarinaEdge]
pageInfo: PageInfo!
}

type MarinaEdge {
cursor: String!
node: Marina
}

type Query {
marinas: [Marina!]
cities: [City!]
countries: [Country!]
amenities: [Amenity!]
photos: [Photo!]

marina(id: ID!): Marina

marinaConnection(first: Int, after: String): MarinaConnection
}
`;

export const resolver: QueryResolvers = {
marinas: () => getMarinaBase(),
// TODO:
amenities: () => getAmenityBase(),
cities: () => getCityBase(),
countries: () => getCountryBase(),
photos: () => getPhotoBase(),

marina: (parent, args) => getMarinaById(parseInt(fromGlobalId(args.id).id)),

marinaConnection: async (parent, args) => {
const first = args.first;
const after = parseInt(args.after || "0"); // could be more opaque
const length = (await getMarinaBase().count("id"))[0]['count(`id`)'] || 0;

let marinasQuery = getMarinaBase().offset(after);
if (first) {
marinasQuery = getMarinaBase().offset(after).limit(first);
}
const marinas = await marinasQuery;

return {
edges: marinas.map((marina, index) => ({
node: marina,
cursor: `${index + after}`,
})),
pageInfo: {
hasNextPage: first ? first + after < length : false,
hasPreviousPage: after > 0,
endCursor: first ? `${first + after}` : `${length}`,
startCursor: `${after}`
}
};
},
};
13 changes: 7 additions & 6 deletions packages/be/src/root.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApolloServer, IResolvers } from "apollo-server-koa";
import type { DocumentNode } from "graphql";
import type { Context as KoaContext } from "koa";
import { DocumentNode } from "graphql";
import { Context as KoaContext } from "koa";

import { ApolloContext } from "./types/ApolloContext";
import * as query from "./query";
Expand All @@ -11,7 +11,7 @@ import * as marina from "./schemas/marina";
import * as photo from "./schemas/photo";
import * as amenity from "./schemas/amenity";
import * as country from "./schemas/country";
// import * as mutation from "./mutation";

import * as node from "./query/node";

const typeDefs: DocumentNode[] = [
Expand All @@ -25,7 +25,7 @@ const typeDefs: DocumentNode[] = [
marina.schema,

query.schema,
mutations.schema,
mutations.schema
];

const resolvers: IResolvers<any, {}> = {
Expand All @@ -36,9 +36,10 @@ const resolvers: IResolvers<any, {}> = {
[country.TYPE]: country.resolver,
[photo.TYPE]: photo.resolver,
[marina.TYPE]: marina.resolver,
[amenity.TYPE]: amenity.resolver,

Query: query.resolver,
Mutation: mutations.resolver,
Mutation: mutations.resolver
};

type Request = {
Expand All @@ -57,7 +58,7 @@ const server = new ApolloServer({
},
introspection: true,
debug: true,
context: async({ ctx}: Request): Promise<ApolloContext> => {
context: async ({ ctx }: Request): Promise<ApolloContext> => {
return {};
}
});
Expand Down
5 changes: 3 additions & 2 deletions packages/be/src/schemas/amenity.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { gql, IResolverObject } from "apollo-server-koa";
import { toGlobalId } from "graphql-relay";

import type { cityDb } from "../types/GeneratedDb";
import { AmenityResolvers } from "../types/GeneratedGql";

export const TYPE = "Amenity";
Expand All @@ -13,4 +12,6 @@ export const schema = gql`
}
`;

export const resolver: AmenityResolvers = {};
export const resolver: AmenityResolvers = {
id: ({ code }) => toGlobalId(TYPE, code)
};
8 changes: 6 additions & 2 deletions packages/be/src/schemas/city.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { gql, IResolverObject } from "apollo-server-koa";
import { toGlobalId } from "graphql-relay";

import type { cityDb } from "../types/GeneratedDb";
import { CityResolvers } from "../types/GeneratedGql";
import { getCountryBase } from "../db/country";

export const TYPE = "City";

Expand All @@ -16,4 +16,8 @@ export const schema = gql`
}
`;

export const resolver: CityResolvers = {};
export const resolver: CityResolvers = {
id: ({ code }) => toGlobalId(TYPE, code),
country: ({ countryCode }) =>
getCountryBase().where("code", countryCode).first(),
};
5 changes: 3 additions & 2 deletions packages/be/src/schemas/country.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { gql, IResolverObject } from "apollo-server-koa";
import { toGlobalId } from "graphql-relay";

import type { cityDb } from "../types/GeneratedDb";
import { CountryResolvers } from "../types/GeneratedGql";

export const TYPE = "Country";
Expand All @@ -13,4 +12,6 @@ export const schema = gql`
}
`;

export const resolver: CountryResolvers = {};
export const resolver: CountryResolvers = {
id: ({ code }) => toGlobalId(TYPE, code)
};
Loading