diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/api/accounts/accounts-middleware.js b/api/accounts/accounts-middleware.js index ca95d597..b099f504 100644 --- a/api/accounts/accounts-middleware.js +++ b/api/accounts/accounts-middleware.js @@ -1,12 +1,77 @@ +const Account = require("./accounts-model"); +const yup = require("yup"); +//yup ile yaparsak: +const accountSchema = yup.object().shape({ + name: yup + .string() + .required("name and budget are required") + .min(3, "name of account must be between 3 and 100") + .max(100, "name of account must be between 3 and 100"), + budget: yup + .number("budget of account must be a number") + .required("name and budget are required") + .min(0, "budget of account is too large or too small") + .max(1000000, "budget of account is too large or too small"), +}); exports.checkAccountPayload = (req, res, next) => { // KODLAR BURAYA // Not: Validasyon için Yup(şu an yüklü değil!) kullanabilirsiniz veya kendiniz manuel yazabilirsiniz. -} + //yup ile yaparsak:(async ile yaptık) + // try { + // await accountSchema.validate(req.body); + // req.account=req.body + // } catch (error) { + // res.status(400).json({mesaage:error.mesaage || "Hata oluştu"}) + // } + const { name, budget } = req.body; + if (!name || budget === undefined) { + res.status(400).json({ message: "name and budget are required" }); + } else if (name.trim().length < 3 || name.trim().length > 100) { + res + .status(400) + .json({ message: "name of account must be between 3 and 100" }); + } else if (typeof budget !== "number") { + res.status(400).json({ message: "budget of account must be a number" }); + } else if (budget < 0 || budget > 1000000) { + res + .status(400) + .json({ message: "budget of account is too large or too small" }); + } + next(); +}; -exports.checkAccountNameUnique = (req, res, next) => { +exports.checkAccountNameUnique = async (req, res, next) => { // KODLAR BURAYA -} + try { + req.body.name = req.body.name.trim(); + //await accountSchema.validate(req.body); + let allAccount = await Account.getAll(); + let isFound = false; + for (let i = 0; i < allAccount.length; i++) { + if (allAccount[i].name == req.body.name) { + isFound = true; + break; + } + } + if (isFound) { + res.status(400).json({ message: "that name is taken" }); + } + } catch (error) { + next(error); + } + next(); +}; -exports.checkAccountId = (req, res, next) => { - // KODLAR BURAYA -} +exports.checkAccountId = async (req, res, next) => { + try { + const account = await Account.getById(req.params.id); + if (!account) { + res.status(404).json({ message: "account not found" }); + } else { + req.account = account; + next(); + } + } catch (error) { + next(error); + } +}; diff --git a/api/accounts/accounts-model.js b/api/accounts/accounts-model.js index b963499f..301febec 100644 --- a/api/accounts/accounts-model.js +++ b/api/accounts/accounts-model.js @@ -1,22 +1,40 @@ +const db = require("../../data/db-config"); + const getAll = () => { - // KODLAR BURAYA -} + //select * from accounts + return db("accounts"); +}; -const getById = id => { - // KODLAR BURAYA -} +const getById = (id) => { + //select * from accounts where id=id + // return db("accounts").where({id}).first(); + return db("accounts").where("id", id).first(); +}; -const create = account => { - // KODLAR BURAYA -} +const create = (account) => { + //inset into account values (id,name,budget) + const insertedAccount = db("accounts") + .insert(account) + .then((id) => { + return getById(id[0]); + }); + return insertedAccount; +}; const updateById = (id, account) => { - // KODLAR BURAYA -} + // update accounts name=account.name, budget=account.budget where id=id + return db("accounts") + .where("id", id) + .update(account) + .then((rows) => { + return getById(id); + }); +}; -const deleteById = id => { - // KODLAR BURAYA -} +const deleteById = (id) => { + // delete from accounts where id=id + return db("accounts").where("id", id).del(); +}; module.exports = { getAll, @@ -24,4 +42,4 @@ module.exports = { create, updateById, deleteById, -} +}; diff --git a/api/accounts/accounts-router.js b/api/accounts/accounts-router.js index a8ba969f..f1b5ac3f 100644 --- a/api/accounts/accounts-router.js +++ b/api/accounts/accounts-router.js @@ -1,27 +1,71 @@ -const router = require('express').Router() +const router = require("express").Router(); +const Account = require("./accounts-model"); +const mw = require("./accounts-middleware"); -router.get('/', (req, res, next) => { - // KODLAR BURAYA -}) +router.get("/", (req, res, next) => { + Account.getAll() + .then((account) => { + res.json(account); + }) + .catch((err) => { + res.json([]); + }); +}); -router.get('/:id', (req, res, next) => { - // KODLAR BURAYA -}) +router.get("/:id", mw.checkAccountId, async (req, res, next) => { + try { + res.json(req.account); + } catch (error) { + next(error); + } +}); -router.post('/', (req, res, next) => { - // KODLAR BURAYA -}) +router.post( + "/", + mw.checkAccountPayload, + mw.checkAccountNameUnique, + async (req, res, next) => { + // KODLAR BURAYA + try { + let insertData = await Account.create(req.body); + res.status(201).json(insertData); + } catch (error) { + next(error); + } + } +); -router.put('/:id', (req, res, next) => { - // KODLAR BURAYA -}); +router.put( + "/:id", + mw.checkAccountId, + mw.checkAccountPayload, + async (req, res, next) => { + try { + const updateAccount = await Account.updateById(req.params.id, req.body); + res.json(updateAccount); + } catch (error) { + next(error); + } + } +); -router.delete('/:id', (req, res, next) => { +router.delete("/:id", mw.checkAccountId, async (req, res, next) => { // KODLAR BURAYA -}) + try { + await Account.deleteById(req.params.id); + res.json(req.account); + } catch (error) { + next(error); + } +}); -router.use((err, req, res, next) => { // eslint-disable-line +router.use((err, req, res, next) => { + // eslint-disable-line // KODLAR BURAYA -}) + res.status(err.status || 500).json({ + customMessage: "Bir hata oluştu", + message: err.message, + }); +}); module.exports = router; diff --git a/api/server.js b/api/server.js index 5d25c978..e2a64bd8 100644 --- a/api/server.js +++ b/api/server.js @@ -4,4 +4,11 @@ const server = express(); server.use(express.json()); +const userAccount = require("./accounts/accounts-router"); + +server.use("/api/accounts", userAccount); +server.get("/", (req, res) => { + res.json({ message: "Hey, server is up and running..." }); +}); + module.exports = server; diff --git a/data/budget.db3 b/data/budget.db3 index 0df1e8ec..a906b8bd 100644 Binary files a/data/budget.db3 and b/data/budget.db3 differ diff --git a/data/testing.db3 b/data/testing.db3 new file mode 100644 index 00000000..893650bc Binary files /dev/null and b/data/testing.db3 differ diff --git a/package-lock.json b/package-lock.json index 4ce88d1e..16a055c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { - "name": "node-db1-project", + "name": "node-db-project-1", "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "node-db1-project", + "name": "node-db-project-1", "version": "1.0.0", "dependencies": { "express": "^4.18.1", "knex": "^2.0.0", - "sqlite3": "^5.0.8" + "sqlite3": "^5.0.8", + "yup": "^1.0.2" }, "devDependencies": { "@types/jest": "^27.5.0", @@ -5719,6 +5720,11 @@ "node": ">= 6" } }, + "node_modules/property-expr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", + "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6544,6 +6550,11 @@ "node": ">=8" } }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -6588,6 +6599,11 @@ "node": ">=0.6" } }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + }, "node_modules/touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -6974,6 +6990,28 @@ "engines": { "node": ">=12" } + }, + "node_modules/yup": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.0.2.tgz", + "integrity": "sha512-Lpi8nITFKjWtCoK3yQP8MUk78LJmHWqbFd0OOMXTar+yjejlQ4OIIoZgnTW1bnEUKDw6dZBcy3/IdXnt2KDUow==", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { @@ -11350,6 +11388,11 @@ "sisteransi": "^1.0.5" } }, + "property-expr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", + "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -11965,6 +12008,11 @@ "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" }, + "tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -11997,6 +12045,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" + }, "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -12300,6 +12353,24 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true + }, + "yup": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.0.2.tgz", + "integrity": "sha512-Lpi8nITFKjWtCoK3yQP8MUk78LJmHWqbFd0OOMXTar+yjejlQ4OIIoZgnTW1bnEUKDw6dZBcy3/IdXnt2KDUow==", + "requires": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + }, + "dependencies": { + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + } + } } } } diff --git a/package.json b/package.json index 95ffa00e..916c56d8 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,10 @@ "resetdb": "knex migrate:rollback && knex migrate:latest && knex seed:run" }, "dependencies": { - "sqlite3": "^5.0.8", "express": "^4.18.1", - "knex": "^2.0.0" + "knex": "^2.0.0", + "sqlite3": "^5.0.8", + "yup": "^1.0.2" }, "devDependencies": { "@types/jest": "^27.5.0", diff --git a/queries.sql b/queries.sql index 6c251068..ac9f41ef 100644 --- a/queries.sql +++ b/queries.sql @@ -2,16 +2,42 @@ -- Posta kodu 1010 olan tüm müşterileri bulun + SELECT * FROM Customers + WHERE PostalCode=1010; + -- id'si 11 olan tedarikçinin telefon numarasını bulun + SELECT Phone FROM Suppliers + WHERE SupplierID=11; + -- Verilen ilk 10 siparişi, sipariş tarihine göre azalan şekilde listeleyin + SELECT * FROM Orders + ORDER BY OrderDate DESC + Limit 10; + -- Londra, Madrid veya Brezilya'da yaşayan tüm müşterileri bulun + SELECT * FROM Customers + WHERE City="London" OR + City="Madrid" OR Country="Brazil"; + -- "The Shire" için bir müşteri kaydı ekleyin, ilgili kişi adı "Bilbo Baggins", adres - "Bag End" içinde "1 Hobbit-Hole", posta kodu "111" ve ülke "Middle Earth" + INSERT INTO Customers + (CustomerName,ContactName,Address,City,PostalCode,Country) + VALUES + ("The Shire","Bilbo Baggins","Bag End","1 Hobbit-Hole",111,"Middle Earth"); + -- Posta kodu "11122" olarak değişecek şekilde Bilbo Baggins kaydını güncelleyin + UPDATE Customers SET PostalCode=11122 + WHERE ContactName="Bilbo Baggins"; + -- (Zorlayıcı Görev) Müşteriler tablosunda kaç farklı şehrin saklandığını keşfetmek için bir sorgu bulun. Tekrarlar çift sayılmamalıdır --- (Zorlayıcı Görev) 20 karakterden uzun adları olan tüm tedarikçileri bulun. Adın uzunluğunu almak için "length(SupplierName)" kullanabilirsiniz. \ No newline at end of file + SELECT COUNT(DISTINCT City) AS NumberOfCity FROM Customers; + +-- (Zorlayıcı Görev) 20 karakterden uzun adları olan tüm tedarikçileri bulun. Adın uzunluğunu almak için "length(SupplierName)" kullanabilirsiniz. + + SELECT * from Suppliers WHERE LEN("SupplierName") > 20 ; \ No newline at end of file