├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── .vscode └── settings.json ├── .yarnrc ├── LICENSE ├── Makefile ├── babel.config.js ├── bin └── install.sh ├── bootstrap-roles.sql ├── docker-compose.yml ├── extensions └── @launchql │ └── ext-types │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── LICENSE │ ├── Makefile │ ├── deploy │ └── schemas │ │ └── public │ │ ├── domains │ │ ├── attachment.sql │ │ ├── email.sql │ │ ├── hostname.sql │ │ ├── image.sql │ │ ├── multiple_select.sql │ │ ├── single_select.sql │ │ ├── upload.sql │ │ └── url.sql │ │ └── schema.sql │ ├── launchql-ext-types.control │ ├── package.json │ ├── revert │ └── schemas │ │ └── public │ │ ├── domains │ │ ├── attachment.sql │ │ ├── email.sql │ │ ├── hostname.sql │ │ ├── image.sql │ │ ├── multiple_select.sql │ │ ├── single_select.sql │ │ ├── upload.sql │ │ └── url.sql │ │ └── schema.sql │ ├── sqitch.conf │ ├── sqitch.plan │ ├── sql │ └── launchql-ext-types--0.1.0.sql │ ├── test │ ├── domains.test.js │ └── utils │ │ └── index.js │ └── verify │ └── schemas │ └── public │ ├── domains │ ├── attachment.sql │ ├── email.sql │ ├── hostname.sql │ ├── image.sql │ ├── multiple_select.sql │ ├── single_select.sql │ ├── upload.sql │ └── url.sql │ └── schema.sql ├── jest.config.js ├── lerna.json ├── package.json ├── packages └── faker │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .npmignore │ ├── .npmrc │ ├── LICENSE │ ├── Makefile │ ├── deploy │ └── schemas │ │ └── faker │ │ ├── procedures │ │ └── utils.sql │ │ ├── schema.sql │ │ └── tables │ │ ├── cities │ │ ├── fixtures │ │ │ └── 1602987351008_fixture.sql │ │ └── table.sql │ │ └── dictionary │ │ ├── fixtures │ │ └── 1602969089665_fixture.sql │ │ └── table.sql │ ├── launchql-faker.control │ ├── package.json │ ├── readme.md │ ├── revert │ └── schemas │ │ └── faker │ │ ├── procedures │ │ └── utils.sql │ │ ├── schema.sql │ │ └── tables │ │ ├── cities │ │ ├── fixtures │ │ │ └── 1602987351008_fixture.sql │ │ └── table.sql │ │ └── dictionary │ │ ├── fixtures │ │ └── 1602969089665_fixture.sql │ │ └── table.sql │ ├── sqitch.conf │ ├── sqitch.plan │ ├── sql │ └── launchql-faker--0.1.0.sql │ ├── test │ ├── faker.test.js │ └── utils │ │ └── index.js │ └── verify │ └── schemas │ └── faker │ ├── procedures │ └── utils.sql │ ├── schema.sql │ └── tables │ ├── cities │ ├── fixtures │ │ └── 1602987351008_fixture.sql │ └── table.sql │ └── dictionary │ ├── fixtures │ └── 1602969089665_fixture.sql │ └── table.sql ├── readme.md ├── skitch.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['prettier'], 3 | extends: ['eslint:recommended', 'prettier'], 4 | parser: 'babel-eslint', 5 | globals: { 6 | jasmine: true 7 | }, 8 | parserOptions: { 9 | ecmaVersion: 11, 10 | sourceType: 'module', 11 | ecmaFeatures: { 12 | jsx: true 13 | } 14 | }, 15 | env: { 16 | es6: true, 17 | browser: true, 18 | node: true, 19 | jest: true 20 | }, 21 | rules: { 22 | 'no-debugger': 2, 23 | 'no-alert': 2, 24 | 'no-await-in-loop': 0, 25 | 'no-prototype-builtins': 0, 26 | 'no-return-assign': ['error', 'except-parens'], 27 | 'no-restricted-syntax': [ 28 | 2, 29 | 'ForInStatement', 30 | 'LabeledStatement', 31 | 'WithStatement' 32 | ], 33 | 'no-unused-vars': [ 34 | 0, 35 | { 36 | ignoreSiblings: true, 37 | argsIgnorePattern: 'React|res|next|^_' 38 | } 39 | ], 40 | 'prefer-const': [ 41 | 'error', 42 | { 43 | destructuring: 'all' 44 | } 45 | ], 46 | 'no-unused-expressions': [ 47 | 2, 48 | { 49 | allowTaggedTemplates: true 50 | } 51 | ], 52 | 'no-console': 1, 53 | 'comma-dangle': 2, 54 | 'jsx-quotes': [2, 'prefer-double'], 55 | 'linebreak-style': ['error', 'unix'], 56 | quotes: [ 57 | 2, 58 | 'single', 59 | { 60 | avoidEscape: true, 61 | allowTemplateLiterals: true 62 | } 63 | ], 64 | 'prettier/prettier': [ 65 | 'error', 66 | { 67 | trailingComma: 'none', 68 | singleQuote: true, 69 | printWidth: 80 70 | } 71 | ] 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text eol=lf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .eslintcache 4 | *.log 5 | **/node_modules 6 | coverage 7 | packages/**/build 8 | packages/**/main 9 | packages/**/module -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .eslintcache 4 | *.log 5 | **/node_modules 6 | coverage 7 | packages/**/build 8 | packages/**/main 9 | packages/**/module -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | notifications: 5 | email: false 6 | services: 7 | - docker 8 | env: 9 | global: 10 | - POSTGRES_USER=postgres 11 | - POSTGRES_PASSWORD=password 12 | - PGPORT=7777 13 | - PGTEMPLATE_DATABASE=testing-template-db 14 | - PGHOST=localhost 15 | - PGPASSWORD=password 16 | - PGUSER=postgres 17 | - APP_USER=app_user 18 | - APP_PASSWORD=app_password 19 | matrix: 20 | - PACKAGE=packages/faker 21 | 22 | before_install: 23 | - yarn install 24 | - docker run -p 7777:5432 -e POSTGRES_PASSWORD=password -e POSTGRES_USER=postgres --name postgres -v `pwd`/bin:/sql-bin -v `pwd`/extensions:/sql-extensions -v `pwd`/packages:/sql-packages -d pyramation/postgis 25 | - sleep 3 26 | - while ! docker exec -it postgres pg_isready -U postgres -h 127.0.0.1; do echo "$(date) - waiting for database to start"; sleep 1; done 27 | - while ! docker exec postgres /sql-bin/install.sh; do echo "installing plugins"; sleep 3; done 28 | - psql -f ./bootstrap-roles.sql postgres 29 | script: 30 | - cd $PACKAGE 31 | - yarn install 32 | - yarn test 33 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": false, 3 | "[javascriptreact]": { 4 | "editor.formatOnSave": false 5 | }, 6 | "[javascript]": { 7 | "editor.formatOnSave": false 8 | }, 9 | "editor.codeActionsOnSave": { 10 | "source.fixAll.eslint": true 11 | }, 12 | "eslint.validate": [ 13 | "javascript", 14 | "javascriptreact" 15 | ] 16 | } -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | registry "https://registry.npmjs.org/" 2 | workspaces-experimental true 3 | save-prefix false 4 | save-exact true 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Web, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | up: 3 | docker-compose up -d 4 | 5 | down: 6 | docker-compose down -v 7 | 8 | ssh: 9 | docker exec -it faker-postgres /bin/bash 10 | 11 | install: 12 | docker exec faker-postgres /sql-bin/install.sh 13 | 14 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | babelrcRoots: 'packages/*', 3 | presets: ['@pyramation/env'] 4 | }; 5 | -------------------------------------------------------------------------------- /bin/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function installit { 4 | DIR=$(pwd) 5 | 6 | if [ -d "$1" ] 7 | then 8 | echo "SQL Module Directory $1 exists." 9 | echo $1 10 | cd $1 11 | 12 | for x in $(find ./ -type f -name "sqitch.plan") 13 | do 14 | orig=$(pwd) 15 | dir=$(dirname $x) 16 | cd $dir 17 | make install 18 | cd $orig 19 | done 20 | cd $DIR 21 | else 22 | echo "Error: SQL MODULE Directory $1 does not exist, don't worry, moving on." 23 | fi 24 | 25 | } 26 | 27 | installit /sql-extensions 28 | installit /sql-packages -------------------------------------------------------------------------------- /bootstrap-roles.sql: -------------------------------------------------------------------------------- 1 | -- anonymous 2 | CREATE ROLE anonymous; 3 | 4 | ALTER USER anonymous WITH NOCREATEDB; 5 | 6 | ALTER USER anonymous WITH NOSUPERUSER; 7 | 8 | ALTER USER anonymous WITH NOCREATEROLE; 9 | 10 | ALTER USER anonymous WITH NOLOGIN; 11 | 12 | ALTER USER anonymous WITH NOREPLICATION; 13 | 14 | ALTER USER anonymous WITH NOBYPASSRLS; 15 | 16 | -- authenticated 17 | CREATE ROLE authenticated; 18 | 19 | ALTER USER authenticated WITH NOCREATEDB; 20 | 21 | ALTER USER authenticated WITH NOSUPERUSER; 22 | 23 | ALTER USER authenticated WITH NOCREATEROLE; 24 | 25 | ALTER USER authenticated WITH NOLOGIN; 26 | 27 | ALTER USER authenticated WITH NOREPLICATION; 28 | 29 | ALTER USER authenticated WITH NOBYPASSRLS; 30 | 31 | -- administrator 32 | CREATE ROLE administrator; 33 | 34 | ALTER USER administrator WITH NOCREATEDB; 35 | 36 | ALTER USER administrator WITH NOSUPERUSER; 37 | 38 | ALTER USER administrator WITH NOCREATEROLE; 39 | 40 | ALTER USER administrator WITH NOLOGIN; 41 | 42 | ALTER USER administrator WITH NOREPLICATION; 43 | 44 | -- they CAN bypass RLS 45 | ALTER USER administrator WITH BYPASSRLS; 46 | 47 | -- app user 48 | CREATE ROLE app_user LOGIN PASSWORD 'app_password'; 49 | 50 | GRANT anonymous TO app_user; 51 | 52 | GRANT authenticated TO app_user; 53 | 54 | -- admin user 55 | CREATE ROLE app_admin LOGIN PASSWORD 'admin_password'; 56 | 57 | GRANT anonymous TO administrator; 58 | 59 | GRANT authenticated TO administrator; 60 | 61 | GRANT administrator TO app_admin; 62 | 63 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | postgres: 4 | container_name: faker-postgres 5 | image: pyramation/postgis 6 | environment: 7 | - "POSTGRES_USER=postgres" 8 | - "POSTGRES_PASSWORD=password" 9 | ports: 10 | - "5432:5432" 11 | expose: 12 | - "5432" 13 | volumes: 14 | - ./bin:/sql-bin 15 | - ./packages:/sql-packages 16 | - ./extensions:/sql-extensions 17 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@babel/plugin-proposal-class-properties", 4 | "@babel/plugin-proposal-object-rest-spread", 5 | "@babel/plugin-proposal-export-default-from", 6 | "@babel/plugin-transform-runtime" 7 | ], 8 | "presets": [ 9 | "@babel/env" 10 | ] 11 | } -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | main/ 4 | module/ 5 | coverage/ -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['prettier'], 3 | extends: ['eslint:recommended', 'prettier'], 4 | parser: 'babel-eslint', 5 | globals: { 6 | jasmine: true 7 | }, 8 | parserOptions: { 9 | ecmaVersion: 11, 10 | sourceType: 'module', 11 | ecmaFeatures: { 12 | jsx: true 13 | } 14 | }, 15 | env: { 16 | es6: true, 17 | browser: true, 18 | node: true, 19 | jest: true 20 | }, 21 | rules: { 22 | 'no-debugger': 2, 23 | 'no-alert': 2, 24 | 'no-await-in-loop': 0, 25 | 'no-prototype-builtins': 0, 26 | 'no-return-assign': ['error', 'except-parens'], 27 | 'no-restricted-syntax': [ 28 | 2, 29 | 'ForInStatement', 30 | 'LabeledStatement', 31 | 'WithStatement' 32 | ], 33 | 'no-unused-vars': [ 34 | 0, 35 | { 36 | ignoreSiblings: true, 37 | argsIgnorePattern: 'React|res|next|^_' 38 | } 39 | ], 40 | 'prefer-const': [ 41 | 'error', 42 | { 43 | destructuring: 'all' 44 | } 45 | ], 46 | 'no-unused-expressions': [ 47 | 2, 48 | { 49 | allowTaggedTemplates: true 50 | } 51 | ], 52 | 'no-console': 1, 53 | 'comma-dangle': 2, 54 | 'jsx-quotes': [2, 'prefer-double'], 55 | 'linebreak-style': ['error', 'unix'], 56 | quotes: [ 57 | 2, 58 | 'single', 59 | { 60 | avoidEscape: true, 61 | allowTemplateLiterals: true 62 | } 63 | ], 64 | 'prettier/prettier': [ 65 | 'error', 66 | { 67 | trailingComma: 'none', 68 | singleQuote: true, 69 | printWidth: 80 70 | } 71 | ] 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020-present, Web, Inc. 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/Makefile: -------------------------------------------------------------------------------- 1 | EXTENSION = launchql-ext-types 2 | DATA = sql/launchql-ext-types--0.1.0.sql 3 | 4 | PG_CONFIG = pg_config 5 | PGXS := $(shell $(PG_CONFIG) --pgxs) 6 | include $(PGXS) 7 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/attachment.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/attachment to pg 2 | -- requires: schemas/public/schema 3 | 4 | BEGIN; 5 | CREATE DOMAIN attachment AS jsonb CHECK ( 6 | value ?& ARRAY['url', 'mime'] 7 | AND 8 | value->>'url' ~ '^(https?)://[^\s/$.?#].[^\s]*$' 9 | ); 10 | COMMENT ON DOMAIN attachment IS E'@name launchqlInternalTypeAttachment'; 11 | COMMIT; 12 | 13 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/email.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/email to pg 2 | -- requires: schemas/public/schema 3 | 4 | BEGIN; 5 | CREATE DOMAIN email AS citext CHECK (value ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'); 6 | COMMENT ON DOMAIN email IS E'@name launchqlInternalTypeEmail'; 7 | COMMIT; 8 | 9 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/hostname.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/hostname to pg 2 | -- requires: schemas/public/schema 3 | 4 | BEGIN; 5 | CREATE DOMAIN hostname AS text CHECK (VALUE ~ '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'); 6 | COMMENT ON DOMAIN hostname IS E'@name launchqlInternalTypeHostname'; 7 | COMMIT; 8 | 9 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/image.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/image to pg 2 | -- requires: schemas/public/schema 3 | 4 | BEGIN; 5 | CREATE DOMAIN image AS jsonb CHECK ( 6 | value ?& ARRAY['url', 'mime'] 7 | AND 8 | value->>'url' ~ '^(https?)://[^\s/$.?#].[^\s]*$' 9 | ); 10 | COMMENT ON DOMAIN image IS E'@name launchqlInternalTypeImage'; 11 | COMMIT; 12 | 13 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/multiple_select.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/multiple_select to pg 2 | -- requires: schemas/public/schema 3 | 4 | BEGIN; 5 | CREATE DOMAIN multiple_select AS jsonb CHECK (value ?& ARRAY['value']); 6 | COMMENT ON DOMAIN multiple_select IS E'@name launchqlInternalTypeMultipleSelect'; 7 | COMMIT; 8 | 9 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/single_select.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/single_select to pg 2 | 3 | -- requires: schemas/public/schema 4 | 5 | BEGIN; 6 | 7 | CREATE DOMAIN single_select AS jsonb CHECK ( 8 | value ?& ARRAY['value'] 9 | ); 10 | COMMENT ON DOMAIN single_select IS E'@name launchqlInternalTypeSingleSelect'; 11 | 12 | COMMIT; 13 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/upload.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/upload to pg 2 | 3 | -- requires: schemas/public/schema 4 | 5 | BEGIN; 6 | 7 | CREATE DOMAIN upload AS text CHECK (VALUE ~ '^(https?)://[^\s/$.?#].[^\s]*$'); 8 | COMMENT ON DOMAIN upload IS E'@name launchqlInternalTypeUpload'; 9 | 10 | COMMIT; 11 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/domains/url.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/domains/url to pg 2 | -- requires: schemas/public/schema 3 | 4 | BEGIN; 5 | CREATE DOMAIN url AS text CHECK (VALUE ~ '^(https?)://[^\s/$.?#].[^\s]*$'); 6 | COMMENT ON DOMAIN url IS E'@name launchqlInternalTypeUrl'; 7 | COMMIT; 8 | 9 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/deploy/schemas/public/schema.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/public/schema to pg 2 | 3 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/launchql-ext-types.control: -------------------------------------------------------------------------------- 1 | # launchql-ext-types extension 2 | comment = 'launchql-ext-types extension' 3 | default_version = '0.1.0' 4 | module_pathname = '$libdir/launchql-ext-types' 5 | requires = 'plpgsql,citext' 6 | relocatable = false 7 | superuser = false 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "@launchql/ext-types@0.1.0", 3 | "_id": "@launchql/ext-types@0.1.0", 4 | "_inBundle": false, 5 | "_integrity": "sha512-tZBxGxiwZMoc0uC51by52n04YcE2R1Xu07DD3LXlD5oaZstgeZ3JWKJ+9p5mljLIuKIHoBTk3TybM0bUh+MnLw==", 6 | "_location": "/@launchql/ext-types", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "version", 10 | "registry": true, 11 | "raw": "@launchql/ext-types@0.1.0", 12 | "name": "@launchql/ext-types", 13 | "escapedName": "@launchql%2fext-types", 14 | "scope": "@launchql", 15 | "rawSpec": "0.1.0", 16 | "saveSpec": null, 17 | "fetchSpec": "0.1.0" 18 | }, 19 | "_requiredBy": [ 20 | "#USER", 21 | "/" 22 | ], 23 | "_resolved": "https://registry.npmjs.org/@launchql/ext-types/-/ext-types-0.1.0.tgz", 24 | "_shasum": "1ecf3cf99e31352248f086ae1ccc8f7bd047bf62", 25 | "_spec": "@launchql/ext-types@0.1.0", 26 | "_where": "/private/var/folders/kn/177lldss4n9fwn0gh5q5wfn00000gn/T/ig37ai1tf1f908h54j6w0w", 27 | "author": { 28 | "name": "Dan Lynch", 29 | "email": "pyramation@gmail.com" 30 | }, 31 | "bundleDependencies": false, 32 | "deprecated": false, 33 | "description": "types", 34 | "devDependencies": { 35 | "@babel/cli": "7.10.4", 36 | "@babel/core": "7.10.4", 37 | "@babel/plugin-proposal-class-properties": "7.10.4", 38 | "@babel/plugin-proposal-export-default-from": "7.10.4", 39 | "@babel/plugin-proposal-object-rest-spread": "7.10.4", 40 | "@babel/plugin-transform-runtime": "7.10.4", 41 | "@babel/preset-env": "7.10.4", 42 | "@babel/runtime": "^7.4.2", 43 | "@launchql/cli": "1.3.5", 44 | "@launchql/db-testing": "latest", 45 | "babel-eslint": "10.1.0", 46 | "babel-jest": "26.1.0", 47 | "eslint": "^7.3.1", 48 | "eslint-config-prettier": "^6.10.0", 49 | "eslint-plugin-prettier": "^3.1.2", 50 | "jest": "26.1.0", 51 | "prettier": "2.0.5", 52 | "regenerator-runtime": "^0.13.2" 53 | }, 54 | "gitHead": "3445405950e15adf8c6910f86591e042cfe28de5", 55 | "name": "@launchql/ext-types", 56 | "publishConfig": { 57 | "access": "public" 58 | }, 59 | "scripts": { 60 | "prepare": "lql package", 61 | "test": "FAST_TEST=1 launchql-templatedb && jest", 62 | "test:watch": "FAST_TEST=1 jest --watch" 63 | }, 64 | "version": "0.1.0" 65 | } 66 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/attachment.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/attachment from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.attachment; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/email.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/email from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.email; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/hostname.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/hostname from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.domain; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/image.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/image from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.image; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/multiple_select.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/multiple_select from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.multiple_select; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/single_select.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/single_select from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.single_select; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/upload.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/upload from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.upload; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/domains/url.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/domains/url from pg 2 | 3 | BEGIN; 4 | 5 | DROP TYPE public.url; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/revert/schemas/public/schema.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/public/schema from pg 2 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/sqitch.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | # plan_file = sqitch.plan 4 | # top_dir = . 5 | # [engine "pg"] 6 | # target = db:pg: 7 | # registry = sqitch 8 | # client = psql 9 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/sqitch.plan: -------------------------------------------------------------------------------- 1 | %syntax-version=1.0.0 2 | %project=launchql-ext-types 3 | %uri=launchql-ext-types 4 | 5 | schemas/public/schema 2017-08-11T08:11:51Z skitch # add schemas/public/schema 6 | schemas/public/domains/attachment [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/attachment 7 | schemas/public/domains/email [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/email 8 | schemas/public/domains/hostname [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/hostname 9 | schemas/public/domains/image [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/image 10 | schemas/public/domains/multiple_select [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/multiple_select 11 | schemas/public/domains/single_select [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/single_select 12 | schemas/public/domains/upload [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/upload 13 | schemas/public/domains/url [schemas/public/schema] 2017-08-11T08:11:51Z skitch # add schemas/public/domains/url -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/sql/launchql-ext-types--0.1.0.sql: -------------------------------------------------------------------------------- 1 | \echo Use "CREATE EXTENSION launchql-ext-types" to load this file. \quit 2 | CREATE DOMAIN attachment AS jsonb CHECK ( value ?& ARRAY['url', 'mime'] AND (value->>'url') ~ '^(https?)://[^\s/$.?#].[^\s]*$' ); 3 | 4 | COMMENT ON DOMAIN attachment IS E'@name launchqlInternalTypeAttachment'; 5 | 6 | CREATE DOMAIN email AS citext CHECK ( value ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$' ); 7 | 8 | COMMENT ON DOMAIN email IS E'@name launchqlInternalTypeEmail'; 9 | 10 | CREATE DOMAIN hostname AS text CHECK ( value ~ '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$' ); 11 | 12 | COMMENT ON DOMAIN hostname IS E'@name launchqlInternalTypeHostname'; 13 | 14 | CREATE DOMAIN image AS jsonb CHECK ( value ?& ARRAY['url', 'mime'] AND (value->>'url') ~ '^(https?)://[^\s/$.?#].[^\s]*$' ); 15 | 16 | COMMENT ON DOMAIN image IS E'@name launchqlInternalTypeImage'; 17 | 18 | CREATE DOMAIN multiple_select AS jsonb CHECK ( value ?& ARRAY['value'] ); 19 | 20 | COMMENT ON DOMAIN multiple_select IS E'@name launchqlInternalTypeMultipleSelect'; 21 | 22 | CREATE DOMAIN single_select AS jsonb CHECK ( value ?& ARRAY['value'] ); 23 | 24 | COMMENT ON DOMAIN single_select IS E'@name launchqlInternalTypeSingleSelect'; 25 | 26 | CREATE DOMAIN upload AS text CHECK ( value ~ '^(https?)://[^\s/$.?#].[^\s]*$' ); 27 | 28 | COMMENT ON DOMAIN upload IS E'@name launchqlInternalTypeUpload'; 29 | 30 | CREATE DOMAIN url AS text CHECK ( value ~ '^(https?)://[^\s/$.?#].[^\s]*$' ); 31 | 32 | COMMENT ON DOMAIN url IS E'@name launchqlInternalTypeUrl'; -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/test/domains.test.js: -------------------------------------------------------------------------------- 1 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; 2 | import { getConnections } from '@launchql/db-testing'; 3 | 4 | const validUrls = [ 5 | 'http://foo.com/blah_blah', 6 | 'http://foo.com/blah_blah/', 7 | 'http://foo.com/blah_blah_(wikipedia)', 8 | 'http://foo.com/blah_blah_(wikipedia)_(again)', 9 | 'http://www.example.com/wpstyle/?p=364', 10 | 'https://www.example.com/foo/?bar=baz&inga=42&quux', 11 | 'http://✪df.ws/123', 12 | 'http://foo.com/blah_(wikipedia)#cite-1', 13 | 'http://foo.com/blah_(wikipedia)_blah#cite-1', 14 | 'http://foo.com/(something)?after=parens', 15 | 'http://code.google.com/events/#&product=browser', 16 | 'http://j.mp', 17 | 'http://foo.bar/?q=Test%20URL-encoded%20stuff', 18 | 19 | 'http://مثال.إختبار', 20 | 'http://例子.测试', 21 | 'http://उदाहरण.परीक्षा', 22 | "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", 23 | 24 | 'http://1337.net', 25 | 'http://a.b-c.de', 26 | 'https://foo_bar.example.com/' 27 | ]; 28 | 29 | const invalidUrls = [ 30 | 'http://##', 31 | 'http://##/', 32 | 'http://foo.bar?q=Spaces should be encoded', 33 | '//', 34 | '//a', 35 | '///a', 36 | '///', 37 | 'http:///a', 38 | 'foo.com', 39 | 'rdar://1234', 40 | 'h://test', 41 | 'http:// shouldfail.com', 42 | ':// should fail', 43 | 'http://foo.bar/foo(bar)baz quux', 44 | 'ftps://foo.bar/', 45 | 'http://.www.foo.bar/', 46 | 'http://.www.foo.bar./' 47 | ]; 48 | 49 | const validAttachments = [ 50 | { 51 | url: 'http://www.foo.bar/some.jpg', 52 | mime: 'image/jpg' 53 | }, 54 | { 55 | url: 'https://foo.bar/some.PNG', 56 | mime: 'image/jpg' 57 | } 58 | ]; 59 | 60 | const invalidAttachments = [ 61 | { 62 | url: 'hi there' 63 | }, 64 | { 65 | url: 'https://foo.bar/some.png' 66 | } 67 | ]; 68 | 69 | let teardown, db, conn; 70 | let d; 71 | const objs = {}; 72 | beforeAll(async () => { 73 | ({ db, conn, teardown } = await getConnections()); 74 | d = db.helper('public'); 75 | }); 76 | beforeAll(async () => { 77 | await db.any(` 78 | CREATE TABLE customers ( 79 | id serial, 80 | url url, 81 | image image, 82 | attachment attachment, 83 | domain hostname, 84 | email email 85 | ); 86 | `); 87 | }); 88 | afterAll(async () => { 89 | try { 90 | } catch (e) { 91 | await teardown(); 92 | } 93 | }); 94 | describe('types', () => { 95 | it('valid attachment and image', async () => { 96 | for (let i = 0; i < validAttachments.length; i++) { 97 | const value = validAttachments[i]; 98 | await db.any(`INSERT INTO customers (image) VALUES ($1::json);`, [value]); 99 | await db.any(`INSERT INTO customers (attachment) VALUES ($1::json);`, [ 100 | value 101 | ]); 102 | } 103 | }); 104 | it('invalid attachment and image', async () => { 105 | for (let i = 0; i < invalidAttachments.length; i++) { 106 | const value = invalidAttachments[i]; 107 | let failed = false; 108 | try { 109 | await db.any(`INSERT INTO customers (attachment) VALUES ($1);`, [ 110 | value 111 | ]); 112 | } catch (e) { 113 | failed = true; 114 | } 115 | expect(failed).toBe(true); 116 | failed = false; 117 | try { 118 | await db.any(`INSERT INTO customers (image) VALUES ($1);`, [value]); 119 | } catch (e) { 120 | failed = true; 121 | } 122 | expect(failed).toBe(true); 123 | } 124 | }); 125 | it('valid url', async () => { 126 | for (let i = 0; i < validUrls.length; i++) { 127 | const value = validUrls[i]; 128 | await db.any(`INSERT INTO customers (url) VALUES ($1);`, [value]); 129 | } 130 | }); 131 | it('invalid url', async () => { 132 | for (let i = 0; i < invalidUrls.length; i++) { 133 | const value = invalidUrls[i]; 134 | let failed = false; 135 | try { 136 | await db.any(`INSERT INTO customers (url) VALUES ($1);`, [value]); 137 | } catch (e) { 138 | failed = true; 139 | } 140 | expect(failed).toBe(true); 141 | } 142 | }); 143 | it('email', async () => { 144 | await db.any(` 145 | INSERT INTO customers (email) VALUES 146 | ('d@google.com'), 147 | ('d@google.in'), 148 | ('d@google.in'), 149 | ('d@www.google.in'), 150 | ('d@google.io'), 151 | ('dan@google.some.other.com')`); 152 | }); 153 | it('not email', async () => { 154 | let failed = false; 155 | try { 156 | await db.any(` 157 | INSERT INTO customers (email) VALUES 158 | ('http://google.some.other.com')`); 159 | } catch (e) { 160 | failed = true; 161 | } 162 | expect(failed).toBe(true); 163 | }); 164 | it('hostname', async () => { 165 | await db.any(` 166 | INSERT INTO customers (domain) VALUES 167 | ('google.com'), 168 | ('google.in'), 169 | ('google.in'), 170 | ('www.google.in'), 171 | ('google.io'), 172 | ('google.some.other.com')`); 173 | }); 174 | it('not hostname', async () => { 175 | let failed = false; 176 | try { 177 | await db.any(` 178 | INSERT INTO customers (domain) VALUES 179 | ('http://google.some.other.com')`); 180 | } catch (e) { 181 | failed = true; 182 | } 183 | expect(failed).toBe(true); 184 | }); 185 | it('not hostname 2', async () => { 186 | let failed = false; 187 | try { 188 | await db.any(` 189 | INSERT INTO customers (domain) VALUES 190 | ('google.some.other.com/a/b/d')`); 191 | } catch (e) { 192 | failed = true; 193 | } 194 | expect(failed).toBe(true); 195 | }); 196 | }); 197 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/test/utils/index.js: -------------------------------------------------------------------------------- 1 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; 2 | export { getConnections } from '@launchql/db-testing'; 3 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/attachment.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/attachment on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.attachment'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/email.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/email on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.email'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/hostname.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/hostname on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.domain'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/image.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/image on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.image'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/multiple_select.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/multiple_select on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.multiple_select'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/single_select.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/single_select on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.single_select'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/upload.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/upload on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.upload'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/domains/url.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/domains/url on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_type ('public.url'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /extensions/@launchql/ext-types/verify/schemas/public/schema.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/public/schema on pg 2 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | projects: ['/packages/*/jest.config.js'], 3 | coverageDirectory: '/coverage', 4 | transform: { 5 | '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest' 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "3.4.2", 3 | "useWorkspaces": true, 4 | "npmClient": "yarn", 5 | "npmClientArgs": [ 6 | "--no-lockfile" 7 | ], 8 | "packages": [ 9 | "packages/*" 10 | ], 11 | "version": "independent", 12 | "registry": "https://registry.npmjs.org", 13 | "command": { 14 | "create": { 15 | "license": "SEE LICENSE IN LICENSE", 16 | "access": "restricted" 17 | }, 18 | "publish": { 19 | "allowBranch": "master" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "faker", 4 | "scripts": { 5 | "build": "lerna run prepare --parallel", 6 | "bootstrap": "lerna bootstrap --use-workspaces" 7 | }, 8 | "devDependencies": { 9 | "@babel/cli": "7.12.1", 10 | "@babel/core": "7.12.3", 11 | "@pyramation/babel-preset-env": "0.1.0", 12 | "babel-eslint": "10.1.0", 13 | "babel-jest": "26.6.1", 14 | "eslint": "7.12.1", 15 | "eslint-config-prettier": "^6.10.0", 16 | "eslint-plugin-prettier": "^3.1.2", 17 | "jest": "26.6.1", 18 | "lerna": "3.22.1", 19 | "prettier": "2.1.2" 20 | }, 21 | "workspaces": [ 22 | "packages/*" 23 | ] 24 | } -------------------------------------------------------------------------------- /packages/faker/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@babel/plugin-proposal-class-properties", 4 | "@babel/plugin-proposal-object-rest-spread", 5 | "@babel/plugin-proposal-export-default-from", 6 | "@babel/plugin-transform-runtime" 7 | ], 8 | "presets": [ 9 | "@babel/env" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/faker/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /packages/faker/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | main/ 4 | module/ 5 | coverage/ -------------------------------------------------------------------------------- /packages/faker/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: ['prettier'], 3 | extends: ['eslint:recommended', 'prettier'], 4 | parser: 'babel-eslint', 5 | globals: { 6 | jasmine: true 7 | }, 8 | parserOptions: { 9 | ecmaVersion: 11, 10 | sourceType: 'module', 11 | ecmaFeatures: { 12 | jsx: true 13 | } 14 | }, 15 | env: { 16 | es6: true, 17 | browser: true, 18 | node: true, 19 | jest: true 20 | }, 21 | rules: { 22 | 'no-debugger': 2, 23 | 'no-alert': 2, 24 | 'no-await-in-loop': 0, 25 | 'no-prototype-builtins': 0, 26 | 'no-return-assign': ['error', 'except-parens'], 27 | 'no-restricted-syntax': [ 28 | 2, 29 | 'ForInStatement', 30 | 'LabeledStatement', 31 | 'WithStatement' 32 | ], 33 | 'no-unused-vars': [ 34 | 0, 35 | { 36 | ignoreSiblings: true, 37 | argsIgnorePattern: 'React|res|next|^_' 38 | } 39 | ], 40 | 'prefer-const': [ 41 | 'error', 42 | { 43 | destructuring: 'all' 44 | } 45 | ], 46 | 'no-unused-expressions': [ 47 | 2, 48 | { 49 | allowTaggedTemplates: true 50 | } 51 | ], 52 | 'no-console': 1, 53 | 'comma-dangle': 2, 54 | 'jsx-quotes': [2, 'prefer-double'], 55 | 'linebreak-style': ['error', 'unix'], 56 | quotes: [ 57 | 2, 58 | 'single', 59 | { 60 | avoidEscape: true, 61 | allowTemplateLiterals: true 62 | } 63 | ], 64 | 'prettier/prettier': [ 65 | 'error', 66 | { 67 | trailingComma: 'none', 68 | singleQuote: true, 69 | printWidth: 80 70 | } 71 | ] 72 | } 73 | }; 74 | -------------------------------------------------------------------------------- /packages/faker/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /packages/faker/.npmignore: -------------------------------------------------------------------------------- 1 | # NOTE keeping this minimal since we generally want everything 2 | 3 | *.log 4 | npm-debug.log* 5 | 6 | # Dependency directories 7 | node_modules 8 | 9 | # npm package lock 10 | package-lock.json 11 | yarn.lock 12 | -------------------------------------------------------------------------------- /packages/faker/.npmrc: -------------------------------------------------------------------------------- 1 | scripts-prepend-node-path=true -------------------------------------------------------------------------------- /packages/faker/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Web, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/faker/Makefile: -------------------------------------------------------------------------------- 1 | EXTENSION = launchql-faker 2 | DATA = sql/launchql-faker--0.1.0.sql 3 | 4 | PG_CONFIG = pg_config 5 | PGXS := $(shell $(PG_CONFIG) --pgxs) 6 | include $(PGXS) 7 | -------------------------------------------------------------------------------- /packages/faker/deploy/schemas/faker/procedures/utils.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/faker/procedures/utils to pg 2 | 3 | -- requires: schemas/faker/schema 4 | -- requires: schemas/faker/tables/dictionary/table 5 | 6 | BEGIN; 7 | 8 | 9 | CREATE FUNCTION faker.word_type() returns text as $$ 10 | SELECT (CASE (RANDOM() * 2)::INT 11 | WHEN 0 THEN 'adjectives' 12 | WHEN 1 THEN 'colors' 13 | WHEN 2 THEN 'animals' 14 | END); 15 | $$ 16 | LANGUAGE 'sql'; 17 | 18 | CREATE FUNCTION faker.word(wordtype text default null) returns text as $$ 19 | DECLARE 20 | vword text; 21 | vtype text; 22 | BEGIN 23 | IF (wordtype IS NOT NULL) THEN 24 | vtype = wordtype; 25 | ELSE 26 | vtype = faker.word_type(); 27 | END IF; 28 | 29 | SELECT word FROM faker.dictionary 30 | WHERE type = vtype 31 | OFFSET floor( random() * (select count(*) from faker.dictionary WHERE type = vtype ) ) LIMIT 1 32 | INTO vword; 33 | 34 | RETURN vword; 35 | 36 | END; 37 | $$ 38 | LANGUAGE 'plpgsql' VOLATILE; 39 | 40 | CREATE FUNCTION faker.word(wordtypes text[]) returns text as $$ 41 | BEGIN 42 | RETURN faker.word(wordtypes[faker.integer(1, cardinality(wordtypes))]::text); 43 | END; 44 | $$ 45 | LANGUAGE 'plpgsql' VOLATILE; 46 | 47 | CREATE FUNCTION faker.gender(gender text default null) returns text as $$ 48 | DECLARE 49 | BEGIN 50 | IF (gender IS NOT NULL) THEN 51 | RETURN gender; 52 | END IF; 53 | RETURN (CASE (RANDOM() * 1)::INT 54 | WHEN 0 THEN 'M' 55 | WHEN 1 THEN 'F' 56 | END); 57 | END; 58 | $$ 59 | LANGUAGE 'plpgsql' VOLATILE; 60 | 61 | CREATE FUNCTION faker.username() returns text as $$ 62 | DECLARE 63 | BEGIN 64 | RETURN (CASE (RANDOM() * 2)::INT 65 | WHEN 0 THEN faker.word() || (RANDOM() * 100)::INT 66 | WHEN 1 THEN faker.word() || '.' || faker.word() || (RANDOM() * 100)::INT 67 | WHEN 2 THEN faker.word() 68 | END); 69 | END; 70 | $$ 71 | LANGUAGE 'plpgsql' VOLATILE; 72 | 73 | CREATE FUNCTION faker.name(gender text default null) returns text as $$ 74 | DECLARE 75 | 76 | BEGIN 77 | IF (gender IS NULL) THEN 78 | gender = faker.gender(); 79 | END IF; 80 | 81 | IF (gender = 'M') THEN 82 | RETURN initcap(faker.word('boys')); 83 | ELSE 84 | RETURN initcap(faker.word('girls')); 85 | END IF; 86 | 87 | END; 88 | $$ 89 | LANGUAGE 'plpgsql' VOLATILE; 90 | 91 | CREATE FUNCTION faker.surname() returns text as $$ 92 | BEGIN 93 | RETURN initcap(faker.word('surname')); 94 | END; 95 | $$ 96 | LANGUAGE 'plpgsql' VOLATILE; 97 | 98 | CREATE FUNCTION faker.fullname(gender text default null) returns text as $$ 99 | BEGIN 100 | RETURN initcap(faker.name(gender)) || ' ' || initcap(faker.word('surname')); 101 | END; 102 | $$ 103 | LANGUAGE 'plpgsql' VOLATILE; 104 | 105 | CREATE FUNCTION faker.business() returns text as $$ 106 | BEGIN 107 | RETURN (CASE (RANDOM() * 4)::INT 108 | WHEN 0 THEN array_to_string( ARRAY[faker.word('bizname'), faker.word('bizsurname') || ',', faker.word('bizsuffix')]::text[], ' ') 109 | WHEN 1 THEN array_to_string( ARRAY[faker.word('bizname'), faker.word('bizsurname')]::text[], ' ') 110 | WHEN 2 THEN array_to_string( ARRAY[faker.word('bizname'), faker.word('bizsurname')]::text[], ' ') 111 | WHEN 3 THEN array_to_string( ARRAY[faker.word('bizname') || faker.word('bizpostfix'), faker.word('bizsurname') ]::text[], ' ') 112 | WHEN 4 THEN array_to_string( ARRAY[faker.word('bizname') || faker.word('bizpostfix'), faker.word('bizsurname') || ',', faker.word('bizsuffix')]::text[], ' ') 113 | END); 114 | END; 115 | $$ 116 | LANGUAGE 'plpgsql' VOLATILE; 117 | 118 | 119 | CREATE FUNCTION faker.city(state text default null) returns text as $$ 120 | DECLARE 121 | vcity text; 122 | BEGIN 123 | 124 | IF (state IS NOT NULL) THEN 125 | 126 | SELECT city FROM faker.cities 127 | WHERE cities.state = city.state 128 | OFFSET floor( random() * (select count(*) from faker.cities WHERE cities.state = city.state ) ) LIMIT 1 129 | INTO vcity; 130 | 131 | ELSE 132 | 133 | SELECT city FROM faker.cities 134 | OFFSET floor( random() * (select count(*) from faker.cities ) ) LIMIT 1 135 | INTO vcity; 136 | 137 | END IF; 138 | 139 | 140 | RETURN vcity; 141 | 142 | END; 143 | $$ 144 | LANGUAGE 'plpgsql' VOLATILE; 145 | 146 | CREATE FUNCTION faker.zip(city text default null) returns int as $$ 147 | DECLARE 148 | vzips int[]; 149 | BEGIN 150 | 151 | IF (city IS NOT NULL) THEN 152 | 153 | SELECT zips FROM faker.cities 154 | WHERE cities.city = zip.city 155 | OFFSET floor( random() * (select count(*) from faker.cities WHERE cities.city = zip.city ) ) LIMIT 1 156 | INTO vzips; 157 | 158 | ELSE 159 | 160 | SELECT zips FROM faker.cities 161 | OFFSET floor( random() * (select count(*) from faker.cities ) ) LIMIT 1 162 | INTO vzips; 163 | 164 | END IF; 165 | 166 | 167 | RETURN vzips[ faker.integer(1, cardinality(vzips)) ]; 168 | 169 | END; 170 | $$ 171 | LANGUAGE 'plpgsql' VOLATILE; 172 | 173 | 174 | CREATE FUNCTION faker.lnglat(x1 float, y1 float, x2 float, y2 float) returns point as $$ 175 | DECLARE 176 | vlat float; 177 | vlng float; 178 | BEGIN 179 | 180 | RETURN Point( 181 | faker.float(least(x1, x2), greatest(x1, x2)), 182 | faker.float(least(y1, y2), greatest(y1, y2)) 183 | ); 184 | 185 | END; 186 | $$ 187 | LANGUAGE 'plpgsql' VOLATILE; 188 | 189 | CREATE FUNCTION faker.lnglat(city text default null) returns point as $$ 190 | DECLARE 191 | vlat float; 192 | vlng float; 193 | BEGIN 194 | 195 | IF (city IS NOT NULL) THEN 196 | SELECT lat, lng FROM faker.cities 197 | WHERE cities.city = lnglat.city 198 | OFFSET floor( random() * (select count(*) from faker.cities WHERE cities.city = lnglat.city ) ) LIMIT 1 199 | INTO vlat, vlng; 200 | ELSE 201 | SELECT lat, lng FROM faker.cities 202 | OFFSET floor( random() * (select count(*) from faker.cities ) ) LIMIT 1 203 | INTO vlat, vlng; 204 | END IF; 205 | 206 | RETURN Point(vlng, vlat); 207 | 208 | END; 209 | $$ 210 | LANGUAGE 'plpgsql' VOLATILE; 211 | 212 | 213 | 214 | CREATE FUNCTION faker.phone() returns text as $$ 215 | BEGIN 216 | 217 | RETURN concat('+1 ', 218 | 219 | '(', 220 | 221 | array_to_string(ARRAY[ 222 | faker.integer(0,9), 223 | faker.integer(0,9), 224 | faker.integer(0,9) 225 | ]::text[], ''), 226 | 227 | ') ', 228 | 229 | array_to_string(ARRAY[ 230 | faker.integer(0,9), 231 | faker.integer(0,9), 232 | faker.integer(0,9) 233 | ]::text[], ''), 234 | 235 | '-', 236 | 237 | array_to_string(ARRAY[ 238 | faker.integer(0,9), 239 | faker.integer(0,9), 240 | faker.integer(0,9), 241 | faker.integer(0,9) 242 | ]::text[], '') 243 | 244 | ); 245 | 246 | END; 247 | $$ 248 | LANGUAGE 'plpgsql' VOLATILE; 249 | 250 | CREATE FUNCTION faker.street() returns text as $$ 251 | BEGIN 252 | RETURN faker.word('street'); 253 | END; 254 | $$ 255 | LANGUAGE 'plpgsql' VOLATILE; 256 | 257 | CREATE FUNCTION faker.state(state text default null) returns text as $$ 258 | DECLARE 259 | vstate text; 260 | BEGIN 261 | 262 | IF (state IS NULL) THEN 263 | SELECT distinct(c.state) FROM faker.cities c 264 | OFFSET floor( random() * (select count(distinct(c2.state)) from faker.cities c2 ) ) LIMIT 1 265 | INTO vstate; 266 | ELSE 267 | vstate = state; 268 | END IF; 269 | 270 | RETURN vstate; 271 | 272 | END; 273 | $$ 274 | LANGUAGE 'plpgsql' VOLATILE; 275 | 276 | CREATE FUNCTION faker.address(state text default null, city text default null) returns text as $$ 277 | DECLARE 278 | vcity text; 279 | vstate text; 280 | vstreet text; 281 | vstreetnum int; 282 | vzips int[]; 283 | vzip int; 284 | BEGIN 285 | 286 | IF (state IS NULL) THEN 287 | vstate = faker.state(); 288 | ELSE 289 | vstate = state; 290 | END IF; 291 | 292 | SELECT c.city, c.zips FROM faker.cities c 293 | WHERE c.state = vstate 294 | OFFSET floor( random() * (select count(*) from faker.cities WHERE cities.state = vstate ) ) LIMIT 1 295 | INTO vcity, vzips; 296 | 297 | vstreetnum = faker.integer(1, 3000); 298 | vstreet = faker.street(); 299 | vzip = vzips[ faker.integer(1, cardinality(vzips)) ]; 300 | 301 | RETURN concat(vstreetnum::text, ' ', vstreet, E'\n', vcity, ', ', vstate, ' ', vzip::text); 302 | 303 | END; 304 | $$ 305 | LANGUAGE 'plpgsql' VOLATILE; 306 | 307 | CREATE FUNCTION faker.tags(min int default 1, max int default 5, dict text default 'tag') returns citext[] as $$ 308 | DECLARE 309 | words text[]; 310 | lim int = faker.integer(min,max); 311 | BEGIN 312 | 313 | SELECT ARRAY ( 314 | SELECT word FROM faker.dictionary 315 | WHERE type = dict 316 | OFFSET floor( random() * (select count(*) from faker.dictionary WHERE type = dict ) ) LIMIT lim 317 | ) INTO words; 318 | 319 | RETURN words::citext[]; 320 | END; 321 | $$ 322 | LANGUAGE 'plpgsql' VOLATILE; 323 | 324 | CREATE FUNCTION faker.sentence(unit text default 'word', min int default 7, max int default 20, cat text[] default ARRAY['lorem']::text[], period text default '.') returns text as $$ 325 | DECLARE 326 | num int = faker.integer(min, max); 327 | txt text; 328 | vtype text; 329 | n int; 330 | c int; 331 | BEGIN 332 | 333 | IF (unit = 'word') THEN 334 | txt = initcap(faker.word(cat)); 335 | FOR n IN 336 | SELECT * FROM generate_series(1, num) g(n) 337 | LOOP 338 | txt = txt || ' ' || faker.word(cat); 339 | END LOOP; 340 | RETURN txt || period; 341 | ELSEIF (unit = 'char' OR unit = 'chars') THEN 342 | txt = initcap(faker.word(cat)); 343 | c = char_length(txt); 344 | IF (c = num) THEN 345 | RETURN concat(txt, period); 346 | END IF; 347 | IF (c > num) THEN 348 | RETURN substring(txt from 1 for num) || period; 349 | END IF; 350 | WHILE (c < num) 351 | LOOP 352 | txt = txt || ' ' || faker.word(cat); 353 | c = char_length(txt); 354 | END LOOP; 355 | IF (c = num) THEN 356 | RETURN txt || period; 357 | END IF; 358 | IF (c > num) THEN 359 | RETURN substring(txt from 1 for num) || period; 360 | END IF; 361 | RETURN txt || period; 362 | END IF; 363 | RAISE EXCEPTION 'faker.sentence() bad input'; 364 | END; 365 | $$ 366 | LANGUAGE 'plpgsql' VOLATILE; 367 | 368 | CREATE FUNCTION faker.paragraph(unit text default 'word', min int default 7, max int default 20, cat text[] default ARRAY['lorem']::text[]) returns text as $$ 369 | DECLARE 370 | num int = faker.integer(min, max); 371 | txt text; 372 | words text[]; 373 | n int; 374 | needscaps boolean = false; 375 | BEGIN 376 | txt = faker.sentence(unit, min, max, cat, ''); 377 | words = string_to_array(txt, ' '); 378 | txt = ''; 379 | 380 | FOR n IN 381 | SELECT * FROM generate_series(1, cardinality(words)) g(n) 382 | LOOP 383 | IF (needscaps IS TRUE) THEN 384 | txt = concat(txt, ' ', initcap(words[n])); 385 | ELSE 386 | txt = concat(txt, ' ', words[n]); 387 | END IF; 388 | 389 | IF (faker.integer(1,100) > 70) THEN 390 | txt = txt || '.'; 391 | needscaps = true; 392 | ELSE 393 | needscaps = false; 394 | END IF; 395 | 396 | END LOOP; 397 | 398 | IF (trim(txt) ~ '\.$') THEN 399 | RETURN trim(txt); 400 | ELSE 401 | RETURN trim(txt || '.'); 402 | END IF; 403 | 404 | END; 405 | $$ 406 | LANGUAGE 'plpgsql' VOLATILE; 407 | 408 | CREATE FUNCTION faker.email() returns text as $$ 409 | SELECT 410 | faker.word() || (RANDOM() * 100)::INT || '@' || ( 411 | CASE (RANDOM() * 3)::INT 412 | WHEN 0 THEN 'gmail' 413 | WHEN 1 THEN 'hotmail' 414 | WHEN 2 THEN 'yahoo' 415 | WHEN 3 THEN faker.word() 416 | END 417 | ) || '.com' AS email 418 | $$ 419 | LANGUAGE 'sql'; 420 | 421 | CREATE FUNCTION faker.uuid() returns uuid as $$ 422 | SELECT 423 | uuid_generate_v4(); 424 | $$ 425 | LANGUAGE 'sql'; 426 | 427 | CREATE FUNCTION faker.token(bytes int default 16) returns text as $$ 428 | SELECT 429 | encode( gen_random_bytes( bytes ), 'hex' ) 430 | $$ 431 | LANGUAGE 'sql'; 432 | 433 | CREATE FUNCTION faker.password() returns text as $$ 434 | DECLARE 435 | chars text[] = regexp_split_to_array('!@#$%^&*():";''<>?,./~`'::text, ''); 436 | num_special int = faker.integer(0, 4); 437 | n int = 0; 438 | pass text; 439 | BEGIN 440 | 441 | IF (num_special = 0) THEN 442 | pass = encode( gen_random_bytes( 16 ), 'hex' ); 443 | ELSE 444 | pass = encode( gen_random_bytes( 4 ), 'hex' ); 445 | FOR n IN 446 | SELECT * FROM generate_series(1, num_special) g(n) 447 | LOOP 448 | pass = pass || 449 | encode( gen_random_bytes( faker.integer(1,4) ), 'hex' ) || 450 | chars[ faker.integer(1, cardinality(chars)) ] || 451 | encode( gen_random_bytes( faker.integer(1,4) ), 'hex' ); 452 | 453 | END LOOP; 454 | END IF; 455 | 456 | 457 | RETURN pass; 458 | 459 | END; 460 | $$ 461 | LANGUAGE 'plpgsql' VOLATILE; 462 | 463 | CREATE FUNCTION faker.hostname() returns text as $$ 464 | SELECT 465 | faker.word() || '.' || ( 466 | CASE (RANDOM() * 4)::INT 467 | WHEN 0 THEN 'com' 468 | WHEN 1 THEN 'net' 469 | WHEN 2 THEN 'io' 470 | WHEN 3 THEN 'org' 471 | WHEN 4 THEN 'co' 472 | END 473 | ) 474 | $$ 475 | LANGUAGE 'sql'; 476 | 477 | CREATE FUNCTION faker.time_unit() returns text as $$ 478 | SELECT 479 | ( 480 | CASE (RANDOM() * 5)::INT 481 | WHEN 0 THEN 'millisecond' 482 | WHEN 1 THEN 'second' 483 | WHEN 2 THEN 'minute' 484 | WHEN 3 THEN 'hour' 485 | WHEN 4 THEN 'day' 486 | WHEN 5 THEN 'week' 487 | END 488 | ) 489 | $$ 490 | LANGUAGE 'sql'; 491 | 492 | CREATE FUNCTION faker.float(min float default 0, max float default 100) returns float as $$ 493 | DECLARE 494 | num float; 495 | high float; 496 | low float; 497 | BEGIN 498 | high = greatest(min, max); 499 | low = least(min, max); 500 | num = (RANDOM() * ( high - low )) + low; 501 | RETURN num; 502 | END; 503 | $$ 504 | LANGUAGE 'plpgsql' VOLATILE; 505 | 506 | CREATE FUNCTION faker.integer(min int default 0, max int default 100) returns int as $$ 507 | DECLARE 508 | num int; 509 | BEGIN 510 | min = ceil(min); 511 | max = floor(max); 512 | num = floor(RANDOM() * ( max - min + 1 )) + min; 513 | RETURN num; 514 | END; 515 | $$ 516 | LANGUAGE 'plpgsql' VOLATILE; 517 | 518 | CREATE FUNCTION faker.date(min int default 1, max int default 100, future boolean default false) returns date as $$ 519 | DECLARE 520 | d date; 521 | num int = faker.integer(min, max); 522 | BEGIN 523 | IF (future) THEN 524 | d = now()::date + num; 525 | ELSE 526 | d = now()::date - num; 527 | END IF; 528 | RETURN d; 529 | END; 530 | $$ 531 | LANGUAGE 'plpgsql' VOLATILE; 532 | 533 | CREATE FUNCTION faker.birthdate(min int default 1, max int default 100) returns date as $$ 534 | DECLARE 535 | d date; 536 | years int = faker.integer(min, max); 537 | days int = faker.integer(1, 365); 538 | itv interval; 539 | BEGIN 540 | itv = concat(years, ' years')::interval + concat(days, ' days')::interval; 541 | d = now()::date - itv; 542 | RETURN d; 543 | END; 544 | $$ 545 | LANGUAGE 'plpgsql' VOLATILE; 546 | 547 | CREATE FUNCTION faker.interval() returns interval as $$ 548 | DECLARE 549 | ival text; 550 | BEGIN 551 | SELECT faker.time_unit() INTO ival; 552 | ival = (RANDOM() * 100)::text || ' ' || ival; 553 | RETURN ival::interval; 554 | END; 555 | $$ 556 | LANGUAGE 'plpgsql' VOLATILE; 557 | 558 | 559 | CREATE FUNCTION faker.interval(min int, max int) returns interval as $$ 560 | SELECT (faker.integer(min, max)::text || ' ' || 'seconds')::interval; 561 | $$ 562 | LANGUAGE 'sql' VOLATILE; 563 | 564 | CREATE FUNCTION faker.boolean() returns boolean as $$ 565 | BEGIN 566 | RETURN ( 567 | CASE (RANDOM() * 1)::INT 568 | WHEN 0 THEN TRUE 569 | WHEN 1 THEN FALSE 570 | END 571 | ); 572 | END; 573 | $$ 574 | LANGUAGE 'plpgsql' VOLATILE; 575 | 576 | CREATE FUNCTION faker.timestamptz(future boolean default false) returns timestamptz as $$ 577 | DECLARE 578 | ival interval; 579 | t timestamptz; 580 | BEGIN 581 | ival = faker.interval(); 582 | IF (future) THEN 583 | SELECT now() + ival INTO t; 584 | ELSE 585 | SELECT now() - ival INTO t; 586 | END IF; 587 | RETURN t; 588 | END; 589 | $$ 590 | LANGUAGE 'plpgsql' VOLATILE; 591 | 592 | CREATE FUNCTION faker.mime() returns text as $$ 593 | SELECT faker.word('mime'); 594 | $$ 595 | LANGUAGE 'sql'; 596 | 597 | CREATE FUNCTION faker.ext(mime text default faker.mime()) returns text as $$ 598 | DECLARE 599 | ext text; 600 | BEGIN 601 | IF (mime IS NULL) THEN 602 | ext = faker.word(faker.mime()); 603 | ELSE 604 | ext = faker.word(mime); 605 | END IF; 606 | RETURN ext; 607 | END; 608 | $$ 609 | LANGUAGE 'plpgsql' VOLATILE; 610 | 611 | 612 | CREATE FUNCTION faker.image_mime() returns text as $$ 613 | SELECT 614 | ( 615 | CASE (RANDOM() * 3)::INT 616 | WHEN 0 THEN 'image/svg+xml' 617 | WHEN 1 THEN 'image/png' 618 | WHEN 2 THEN 'image/gif' 619 | WHEN 3 THEN 'image/jpeg' 620 | END 621 | ) 622 | $$ 623 | LANGUAGE 'sql'; 624 | 625 | CREATE FUNCTION faker.image(width int default null, height int default null) returns image as $$ 626 | DECLARE 627 | w int; 628 | h int; 629 | obj jsonb = '{}'::jsonb; 630 | url text; 631 | BEGIN 632 | IF (width IS NULL) THEN 633 | w = faker.integer(800,1200); 634 | ELSE 635 | w = width; 636 | END IF; 637 | IF (height IS NULL) THEN 638 | h = faker.integer(800,1200); 639 | ELSE 640 | h = height; 641 | END IF; 642 | 643 | url = concat('https://picsum.photos/', w::text, '/', h::text); 644 | 645 | obj = jsonb_set(obj, '{url}', to_jsonb(url)); 646 | obj = jsonb_set(obj, '{mime}', to_jsonb(faker.image_mime())); 647 | 648 | RETURN obj; 649 | 650 | END; 651 | $$ 652 | LANGUAGE 'plpgsql' VOLATILE; 653 | 654 | CREATE FUNCTION faker.profilepic() returns image as $$ 655 | DECLARE 656 | obj jsonb = '{}'::jsonb; 657 | vurl text = ''; 658 | gndr text = 'women'; 659 | BEGIN 660 | IF ((RANDOM() * 2)::INT = 0) THEN 661 | gndr = 'men'; 662 | END IF; 663 | vurl = concat('https://randomuser.me/api/portraits/', gndr, '/', faker.integer(1, 99) , '.jpg'); 664 | obj = jsonb_set(obj, '{url}', to_jsonb(vurl::text)); 665 | obj = jsonb_set(obj, '{mime}', to_jsonb('image/jpeg'::text)); 666 | RETURN obj; 667 | END; 668 | $$ 669 | LANGUAGE 'plpgsql' VOLATILE; 670 | 671 | CREATE FUNCTION faker.profilepic(gender text) returns image as $$ 672 | DECLARE 673 | obj jsonb = '{}'::jsonb; 674 | vurl text = ''; 675 | gndr text = 'women'; 676 | BEGIN 677 | IF (gender = 'M') THEN 678 | gndr = 'men'; 679 | END IF; 680 | vurl = concat('https://randomuser.me/api/portraits/', gndr, '/', faker.integer(1, 99) , '.jpg'); 681 | obj = jsonb_set(obj, '{url}', to_jsonb(vurl::text)); 682 | obj = jsonb_set(obj, '{mime}', to_jsonb('image/jpeg'::text)); 683 | RETURN obj; 684 | END; 685 | $$ 686 | LANGUAGE 'plpgsql' VOLATILE; 687 | 688 | CREATE FUNCTION faker.file(mime text default null) returns text as $$ 689 | BEGIN 690 | RETURN concat(faker.word(), '.', faker.ext(mime)); 691 | END; 692 | $$ 693 | LANGUAGE 'plpgsql' VOLATILE; 694 | 695 | CREATE FUNCTION faker.url(mime text default null) returns url as $$ 696 | DECLARE 697 | obj jsonb = '{}'::jsonb; 698 | url text; 699 | BEGIN 700 | url = concat('https://', faker.hostname(), '/', faker.file(mime)); 701 | RETURN url; 702 | END; 703 | $$ 704 | LANGUAGE 'plpgsql' VOLATILE; 705 | 706 | CREATE FUNCTION faker.upload(mime text default null) returns upload as $$ 707 | BEGIN 708 | RETURN faker.url(mime); 709 | END; 710 | $$ 711 | LANGUAGE 'plpgsql' VOLATILE; 712 | 713 | CREATE FUNCTION faker.ip(mime text default null) returns text as $$ 714 | BEGIN 715 | RETURN 716 | array_to_string(ARRAY[ 717 | faker.integer(0,255), 718 | faker.integer(0,255), 719 | faker.integer(0,255), 720 | faker.integer(0,255) 721 | ]::text[], '.'); 722 | END; 723 | $$ 724 | LANGUAGE 'plpgsql' VOLATILE; 725 | 726 | CREATE FUNCTION faker.attachment(mime text default null) returns attachment as $$ 727 | DECLARE 728 | obj jsonb = '{}'::jsonb; 729 | BEGIN 730 | IF (mime IS NULL) THEN 731 | mime = faker.mime(); 732 | END IF; 733 | obj = jsonb_set(obj, '{url}', to_jsonb(faker.url(mime)::text)); 734 | obj = jsonb_set(obj, '{mime}', to_jsonb(mime)); 735 | RETURN obj; 736 | END; 737 | $$ 738 | LANGUAGE 'plpgsql' VOLATILE; 739 | 740 | COMMIT; 741 | -------------------------------------------------------------------------------- /packages/faker/deploy/schemas/faker/schema.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/faker/schema to pg 2 | 3 | 4 | BEGIN; 5 | 6 | CREATE SCHEMA faker; 7 | 8 | COMMIT; 9 | -------------------------------------------------------------------------------- /packages/faker/deploy/schemas/faker/tables/cities/table.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/faker/tables/cities/table to pg 2 | 3 | -- requires: schemas/faker/schema 4 | 5 | BEGIN; 6 | 7 | CREATE TABLE faker.cities ( 8 | id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (), 9 | city text, 10 | state text, 11 | zips int[], 12 | lat float, 13 | lng float 14 | ); 15 | 16 | 17 | CREATE INDEX faker_city_idx1 ON faker.cities ( 18 | city 19 | ); 20 | 21 | CREATE INDEX faker_city_idx2 ON faker.cities ( 22 | state 23 | ); 24 | 25 | CREATE INDEX faker_city_idx3 ON faker.cities USING GIN ( 26 | zips 27 | ); 28 | 29 | COMMIT; 30 | -------------------------------------------------------------------------------- /packages/faker/deploy/schemas/faker/tables/dictionary/table.sql: -------------------------------------------------------------------------------- 1 | -- Deploy schemas/faker/tables/dictionary/table to pg 2 | 3 | -- requires: schemas/faker/schema 4 | 5 | BEGIN; 6 | 7 | CREATE TABLE faker.dictionary ( 8 | id uuid PRIMARY KEY DEFAULT uuid_generate_v4 (), 9 | type text, 10 | word text 11 | ); 12 | 13 | CREATE INDEX faker_type_idx ON faker.dictionary ( 14 | type 15 | ); 16 | 17 | COMMIT; 18 | -------------------------------------------------------------------------------- /packages/faker/launchql-faker.control: -------------------------------------------------------------------------------- 1 | # launchql-faker extension 2 | comment = 'launchql-faker extension' 3 | default_version = '0.1.0' 4 | module_pathname = '$libdir/launchql-faker' 5 | requires = 'citext,pgcrypto,plpgsql,uuid-ossp,launchql-ext-types' 6 | relocatable = false 7 | superuser = false 8 | -------------------------------------------------------------------------------- /packages/faker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@launchql/faker", 3 | "version": "0.1.0", 4 | "description": "create fake data in PostgreSQL", 5 | "author": "Web, Inc. ", 6 | "publishConfig": { 7 | "access": "public" 8 | }, 9 | "scripts": { 10 | "test": "FAST_TEST=1 launchql-templatedb && jest", 11 | "test:watch": "FAST_TEST=1 jest --watch", 12 | "prepare": "lql package" 13 | }, 14 | "devDependencies": { 15 | "@babel/cli": "7.10.4", 16 | "@babel/core": "7.10.4", 17 | "@babel/plugin-proposal-class-properties": "7.10.4", 18 | "@babel/plugin-proposal-export-default-from": "7.10.4", 19 | "@babel/plugin-proposal-object-rest-spread": "7.10.4", 20 | "@babel/plugin-transform-runtime": "7.10.4", 21 | "@babel/preset-env": "7.10.4", 22 | "@babel/runtime": "^7.4.2", 23 | "@launchql/cli": "1.3.5", 24 | "@launchql/db-testing": "^1.2.2", 25 | "babel-eslint": "10.1.0", 26 | "babel-jest": "26.1.0", 27 | "eslint": "^7.3.1", 28 | "eslint-config-prettier": "^6.10.0", 29 | "eslint-plugin-prettier": "^3.1.2", 30 | "jest": "26.1.0", 31 | "pg-query-string": "0.1.7", 32 | "prettier": "2.0.5", 33 | "regenerator-runtime": "^0.13.2" 34 | }, 35 | "dependencies": { 36 | "@launchql/ext-types": "^0.1.0" 37 | } 38 | } -------------------------------------------------------------------------------- /packages/faker/readme.md: -------------------------------------------------------------------------------- 1 | # faker [![Build Status](https://travis-ci.com/pyramation/faker.svg?branch=master)](https://travis-ci.com/pyramation/faker) 2 | 3 | create fake data in PostgreSQL 4 | 5 | # Usage 6 | 7 | ## state, city, zip 8 | 9 | ```sql 10 | select faker.state(); 11 | -- CA 12 | 13 | select faker.city(); 14 | -- Belle Haven 15 | 16 | select faker.city('MI'); 17 | -- Livonia 18 | 19 | select faker.zip(); 20 | -- 48105 21 | 22 | select faker.zip('Los Angeles'); 23 | -- 90272 24 | ``` 25 | 26 | ## address, street 27 | 28 | ```sql 29 | select faker.address(); 30 | -- 762 MESA ST 31 | -- Fort Mohave, AZ 86427 32 | 33 | select faker.address('MI'); 34 | -- 2316 LAPHAM WAY 35 | -- Sterling Heights, MI 48312 36 | 37 | select faker.street(); 38 | -- CLAY ST 39 | ``` 40 | 41 | ## tags 42 | 43 | Tags can be seeded in `faker.dictionary` table, here's an example with sustainability 44 | 45 | ```sql 46 | select faker.tags(); 47 | -- {"causes of global warming","electronic waste","solar powered cars"} 48 | ``` 49 | 50 | ## words 51 | 52 | ```sql 53 | select faker.word(); 54 | -- woodpecker 55 | ``` 56 | 57 | Specify word types 58 | 59 | ```sql 60 | select faker.word(ARRAY['adjectives']); 61 | -- decisive 62 | ``` 63 | 64 | ## paragraphs 65 | 66 | ```sql 67 | select faker.paragraph(); 68 | -- Ligula. Aliquet torquent consequat egestas dui. Nullam sed tincidunt mauris porttitor ad taciti rutrum eleifend. Phasellus. 69 | ``` 70 | 71 | ## email 72 | 73 | ```sql 74 | select faker.email(); 75 | -- crimson79@hotmail.com 76 | ``` 77 | 78 | ## uuid 79 | 80 | ```sql 81 | select faker.uuid(); 82 | -- 327cb21d-1680-47ee-9979-3689e1bcb9ab 83 | ``` 84 | 85 | ## tokens, passwords 86 | 87 | ```sql 88 | select faker.token(); 89 | -- 9e23040a7825529beb1528c957eac73f 90 | 91 | select faker.token(20); 92 | -- 7504ef4eafbba04a9645198b10ebc9616afce13a 93 | 94 | select faker.password(); 95 | -- d8f1cca306e4d7^15bb(62618c1e 96 | ``` 97 | 98 | ## hostname 99 | 100 | ```sql 101 | select faker.hostname(); 102 | -- fine.net 103 | ``` 104 | 105 | ## time unit 106 | 107 | ```sql 108 | select faker.time_unit(); 109 | -- hour 110 | ``` 111 | 112 | ## float 113 | 114 | ```sql 115 | select faker.float(); 116 | -- 64.6970694223782 117 | 118 | select faker.float(2.3,10.5); 119 | -- 10.233102884792025 120 | ``` 121 | 122 | ## integer 123 | 124 | ```sql 125 | select faker.integer(); 126 | -- 8 127 | 128 | select faker.integer(2,10); 129 | -- 7 130 | ``` 131 | 132 | ## date 133 | 134 | ```sql 135 | select faker.date(); 136 | -- 2020-10-02 137 | ``` 138 | 139 | Date 1-3 days ago 140 | 141 | ```sql 142 | select faker.date(1,3); 143 | -- 2020-12-02 144 | ``` 145 | 146 | Date in the future between 1-3 days 147 | 148 | ```sql 149 | select faker.date(1,3, true); 150 | -- 2020-12-06 151 | ``` 152 | 153 | ## birthdate 154 | 155 | ```sql 156 | select faker.birthdate(); 157 | -- 2007-02-24 158 | ``` 159 | 160 | Generate birthdate for somebody who is between age of 37 and 64 161 | 162 | ```sql 163 | select faker.birthdate(37, 64); 164 | -- 1972-08-10 165 | ``` 166 | 167 | ## interval 168 | 169 | ```sql 170 | select faker.interval(); 171 | -- 00:01:34.959831 172 | ``` 173 | 174 | Generate an interval between 2 and 300 seconds 175 | 176 | ```sql 177 | select faker.interval(2,300); 178 | -- 00:01:04 179 | ``` 180 | 181 | ## gender 182 | 183 | ```sql 184 | select faker.gender(); 185 | -- F 186 | 187 | select faker.gender(); 188 | -- M 189 | ``` 190 | 191 | ## boolean 192 | 193 | ```sql 194 | select faker.boolean(); 195 | -- TRUE 196 | ``` 197 | 198 | ## timestamptz 199 | 200 | ```sql 201 | select faker.timestamptz(); 202 | -- 2019-12-20 15:57:29.520365+00 203 | ``` 204 | 205 | Future timestamptz 206 | 207 | ```sql 208 | select faker.timestamptz(TRUE); 209 | -- 2020-12-03 23:00:10.013301+00 210 | -- 211 | ``` 212 | 213 | ## mime types 214 | 215 | ```sql 216 | select faker.mime(); 217 | -- text/x-scss 218 | ``` 219 | 220 | ## file extensions 221 | 222 | ```sql 223 | select faker.ext(); 224 | -- html 225 | ``` 226 | 227 | Specify a mimetype 228 | 229 | ```sql 230 | select faker.ext('image/png'); 231 | -- png 232 | ``` 233 | 234 | Image mimetypes 235 | 236 | ```sql 237 | select faker.image_mime(); 238 | -- image/gif 239 | ``` 240 | 241 | ## image 242 | 243 | ```sql 244 | select faker.image(); 245 | -- {"url": "https://picsum.photos/843/874", "mime": "image/gif"} 246 | ``` 247 | 248 | ## profilepic 249 | 250 | credit: thank you https://randomuser.me 251 | 252 | ```sql 253 | select faker.profilepic(); 254 | -- {"url": "https://randomuser.me/api/portraits/women/53.jpg", "mime": "image/jpeg"} 255 | ``` 256 | 257 | Specify a gender 258 | 259 | ```sql 260 | select faker.profilepic('M'); 261 | -- {"url": "https://randomuser.me/api/portraits/men/4.jpg", "mime": "image/jpeg"} 262 | ``` 263 | 264 | ## file 265 | 266 | ```sql 267 | select faker.file(); 268 | -- scarlet.jpg 269 | ``` 270 | 271 | Specify a mimetype 272 | 273 | ```sql 274 | select faker.file('image/png'); 275 | -- anaconda.png 276 | ``` 277 | 278 | ## url 279 | 280 | ```sql 281 | select faker.url(); 282 | -- https://australian.io/copper.gzip 283 | ``` 284 | 285 | ## upload 286 | 287 | ```sql 288 | select faker.upload(); 289 | -- https://magenta.co/moccasin.yaml 290 | ``` 291 | 292 | ## attachment 293 | 294 | ```sql 295 | select faker.attachment(); 296 | -- {"url": "https://silver.io/sapphire.jsx", "mime": "text/jsx"} 297 | ``` 298 | 299 | ## phone 300 | 301 | ```sql 302 | select faker.phone(); 303 | -- +1 (121) 617-3329 304 | ``` 305 | 306 | ## ip 307 | 308 | ```sql 309 | select faker.ip(); 310 | -- 42.122.9.119 311 | ``` 312 | 313 | ## username 314 | 315 | ```sql 316 | select faker.username(); 317 | -- amaranth28 318 | ``` 319 | 320 | ## name 321 | 322 | ```sql 323 | select faker.name(); 324 | -- Lindsay 325 | ``` 326 | 327 | Specify a gender 328 | 329 | ```sql 330 | select faker.name('M'); 331 | -- Stuart 332 | 333 | select faker.name('F'); 334 | -- Shelly 335 | ``` 336 | 337 | ## surname 338 | 339 | ```sql 340 | select faker.surname(); 341 | -- Smith 342 | ``` 343 | 344 | ## fullname 345 | 346 | ```sql 347 | select faker.fullname(); 348 | -- Ross Silva 349 | 350 | select faker.fullname('M'); 351 | -- George Spencer 352 | ``` 353 | 354 | ## business 355 | 356 | ```sql 357 | select faker.business(); 358 | -- Seed Partners, Co. 359 | ``` 360 | 361 | ## longitude / latitude coordinates 362 | 363 | ```sql 364 | select faker.lnglat( -118.561721, 33.59, -117.646374, 34.23302 ); 365 | -- (-118.33162189532844,34.15614699957491) 366 | 367 | select faker.lnglat(); 368 | -- (-74.0205,40.316) 369 | ``` 370 | 371 | # Development 372 | 373 | ## start the postgres db process 374 | 375 | First you'll want to start the postgres docker (you can also just use `docker-compose up -d`): 376 | 377 | ```sh 378 | make up 379 | ``` 380 | 381 | ## install modules 382 | 383 | Install modules 384 | 385 | ```sh 386 | yarn install 387 | ``` 388 | 389 | ## install the Postgres extensions 390 | 391 | Now that the postgres process is running, install the extensions: 392 | 393 | ```sh 394 | make install 395 | ``` 396 | 397 | This basically `ssh`s into the postgres instance with the `packages/` folder mounted as a volume, and installs the bundled sql code as pgxn extensions. 398 | 399 | ## testing 400 | 401 | Testing will load all your latest sql changes and create fresh, populated databases for each sqitch module in `packages/`. 402 | 403 | ```sh 404 | yarn test:watch 405 | ``` 406 | 407 | ## building new modules 408 | 409 | Create a new folder in `packages/` 410 | 411 | ```sh 412 | lql init 413 | ``` 414 | 415 | Then, run a generator: 416 | 417 | ```sh 418 | lql generate 419 | ``` 420 | 421 | You can also add arguments if you already know what you want to do: 422 | 423 | ```sh 424 | lql generate schema --schema myschema 425 | lql generate table --schema myschema --table mytable 426 | ``` 427 | 428 | ## deploy code as extensions 429 | 430 | `cd` into `packages/`, and run `lql package`. This will make an sql file in `packages//sql/` used for `CREATE EXTENSION` calls to install your sqitch module as an extension. 431 | 432 | ## recursive deploy 433 | 434 | You can also deploy all modules utilizing versioning as sqtich modules. Remove `--createdb` if you already created your db: 435 | 436 | ```sh 437 | lql deploy awesome-db --yes --recursive --createdb 438 | ``` 439 | -------------------------------------------------------------------------------- /packages/faker/revert/schemas/faker/procedures/utils.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/faker/procedures/utils from pg 2 | 3 | BEGIN; 4 | 5 | DROP FUNCTION faker.utils; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /packages/faker/revert/schemas/faker/schema.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/faker/schema from pg 2 | 3 | BEGIN; 4 | 5 | DROP SCHEMA faker; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /packages/faker/revert/schemas/faker/tables/cities/fixtures/1602987351008_fixture.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/faker/tables/cities/fixtures/1602987351008_fixture from pg 2 | 3 | BEGIN; 4 | 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /packages/faker/revert/schemas/faker/tables/cities/table.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/faker/tables/cities/table from pg 2 | 3 | BEGIN; 4 | 5 | DROP TABLE faker.cities; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /packages/faker/revert/schemas/faker/tables/dictionary/fixtures/1602969089665_fixture.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/faker/tables/dictionary/fixtures/1602969089665_fixture from pg 2 | 3 | BEGIN; 4 | 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /packages/faker/revert/schemas/faker/tables/dictionary/table.sql: -------------------------------------------------------------------------------- 1 | -- Revert schemas/faker/tables/dictionary/table from pg 2 | 3 | BEGIN; 4 | 5 | DROP TABLE faker.words; 6 | 7 | COMMIT; 8 | -------------------------------------------------------------------------------- /packages/faker/sqitch.conf: -------------------------------------------------------------------------------- 1 | [core] 2 | engine = pg 3 | # plan_file = sqitch.plan 4 | # top_dir = . 5 | # [engine "pg"] 6 | # target = db:pg: 7 | # registry = sqitch 8 | # client = psql 9 | -------------------------------------------------------------------------------- /packages/faker/sqitch.plan: -------------------------------------------------------------------------------- 1 | %syntax-version=1.0.0 2 | %project=launchql-faker 3 | %uri=launchql-faker 4 | 5 | schemas/faker/schema [launchql-ext-types:schemas/public/domains/url] 2017-08-11T08:11:51Z skitch # add schemas/faker/schema 6 | schemas/faker/tables/dictionary/table [schemas/faker/schema] 2017-08-11T08:11:51Z skitch # add schemas/faker/tables/dictionary/table 7 | schemas/faker/procedures/utils [schemas/faker/schema schemas/faker/tables/dictionary/table] 2017-08-11T08:11:51Z skitch # add schemas/faker/procedures/utils 8 | schemas/faker/tables/cities/table [schemas/faker/schema] 2017-08-11T08:11:51Z skitch # add schemas/faker/tables/cities/table 9 | schemas/faker/tables/cities/fixtures/1602987351008_fixture [schemas/faker/schema schemas/faker/tables/cities/table] 2017-08-11T08:11:51Z skitch # add schemas/faker/tables/cities/fixtures/1602987351008_fixture 10 | schemas/faker/tables/dictionary/fixtures/1602969089665_fixture [schemas/faker/schema schemas/faker/tables/dictionary/table] 2017-08-11T08:11:51Z skitch # add schemas/faker/tables/dictionary/fixtures/1602969089665_fixture -------------------------------------------------------------------------------- /packages/faker/test/faker.test.js: -------------------------------------------------------------------------------- 1 | import { getConnections } from './utils'; 2 | 3 | let db, dbs, teardown; 4 | const objs = { 5 | tables: {} 6 | }; 7 | 8 | beforeAll(async () => { 9 | ({ db, teardown } = await getConnections()); 10 | dbs = db.helper('faker'); 11 | }); 12 | 13 | afterAll(async () => { 14 | try { 15 | //try catch here allows us to see the sql parsing issues! 16 | await teardown(); 17 | } catch (e) { 18 | // noop 19 | } 20 | }); 21 | 22 | beforeEach(async () => { 23 | await db.beforeEach(); 24 | }); 25 | 26 | afterEach(async () => { 27 | await db.afterEach(); 28 | }); 29 | 30 | it('gets random words', async () => { 31 | const obj = {}; 32 | const types = [ 33 | // 'word', 34 | // 'sentence', 35 | // 'paragraph', 36 | // 'email', 37 | // 'integer', 38 | // 'float', 39 | // 'timestamptz', 40 | // 'date', 41 | // 'interval', 42 | // 'image', 43 | // 'image_mime', 44 | // 'mime', 45 | // 'uuid', 46 | // 'token', 47 | // 'password', 48 | // 'hostname', 49 | // 'upload', 50 | // 'username', 51 | // 'gender', 52 | // 'name', 53 | // 'surname', 54 | // 'fullname', 55 | // 'phone', 56 | // 'street', 57 | 'lnglat', 58 | 'address', 59 | 'state', 60 | 'city', 61 | 'file', 62 | 'tags', 63 | 'attachment', 64 | 'birthdate', 65 | 'profilepic' 66 | // 'ext', 67 | // 'ip', 68 | // 'business' 69 | ]; 70 | for (const t of types) { 71 | obj[t] = await dbs.callOne(t); 72 | } 73 | console.log(obj); 74 | }); 75 | 76 | it('lnglat', async () => { 77 | const obj = {}; 78 | obj['lnglat'] = await dbs.callOne('lnglat', {}); 79 | obj['bbox'] = await dbs.callOne( 80 | 'lnglat', 81 | { 82 | x1: -118.561721, 83 | y1: 33.59, 84 | x2: -117.646374, 85 | y2: 34.23302 // tighter to LA (from north towards LA) 86 | // y2: 34.823302 // goes further north 87 | }, 88 | { 89 | x1: 'float', 90 | y1: 'float', 91 | x2: 'float', 92 | y2: 'float' 93 | } 94 | ); 95 | console.log(obj); 96 | console.log(obj.bbox.y, ',', obj.bbox.x); 97 | }); 98 | it('tags', async () => { 99 | const obj = {}; 100 | obj['tags'] = await dbs.callOne('tags', {}); 101 | obj['tag with min'] = await dbs.callOne('tags', { 102 | min: 5, 103 | max: 10, 104 | dict: 'tag' 105 | }); 106 | obj['face'] = await dbs.callOne('tags', { 107 | min: 5, 108 | max: 10, 109 | dict: 'face' 110 | }); 111 | console.log(obj); 112 | }); 113 | it('addresses', async () => { 114 | const obj = {}; 115 | obj['any'] = await dbs.callOne('address', {}); 116 | obj['CA'] = await dbs.callOne('address', { 117 | state: 'CA' 118 | }); 119 | obj['MI'] = await dbs.callOne('address', { 120 | state: 'MI' 121 | }); 122 | obj['Los Angeles'] = await dbs.callOne('address', { 123 | state: 'CA', 124 | city: 'Los Angeles' 125 | }); 126 | console.log(obj); 127 | }); 128 | xit('mixed words and args', async () => { 129 | const obj = {}; 130 | obj['english-words'] = await dbs.callOne('sentence', { 131 | unit: 'word', 132 | min: 7, 133 | max: 20, 134 | cat: ['colors'] 135 | }); 136 | obj['mixed-words'] = await dbs.callOne('sentence', { 137 | unit: 'word', 138 | min: 7, 139 | max: 20, 140 | cat: ['colors', 'adjectives', 'surname', 'animals', 'stop', 'stop', 'stop'] 141 | }); 142 | obj['sentence-words'] = await dbs.callOne('sentence', { 143 | unit: 'word', 144 | min: 7, 145 | max: 20, 146 | cat: ['lorem'] 147 | }); 148 | obj['sentence-chars'] = await dbs.callOne('sentence', { 149 | unit: 'char', 150 | min: 100, 151 | max: 140, 152 | cat: ['lorem'] 153 | }); 154 | obj['paragraph-chars'] = await dbs.callOne('paragraph', { 155 | unit: 'char', 156 | min: 300, 157 | max: 500, 158 | cat: ['lorem'] 159 | }); 160 | obj['integer-chars'] = await dbs.callOne('integer', { 161 | min: 300, 162 | max: 500 163 | }); 164 | obj['xenial'] = await dbs.callOne('birthdate', { 165 | min: 34, 166 | max: 39 167 | }); 168 | console.log(obj); 169 | }); 170 | 171 | // it('businesses', async () => { 172 | // for (let i = 0; i < 20; i++) { 173 | // const biz = await dbs.callOne('business'); 174 | // console.log(biz); 175 | // } 176 | // }); 177 | 178 | // it('cities', async () => { 179 | // for (let i = 0; i < 20; i++) { 180 | // const city = await dbs.callOne('city'); 181 | // console.log(city); 182 | // const city2 = await dbs.callOne('city', { 183 | // state: 'MI' 184 | // }); 185 | // console.log(city2); 186 | // const zip = await dbs.callOne('zip'); 187 | // console.log(zip); 188 | // const zip2 = await dbs.callOne('zip', { 189 | // city: 'Los Angeles' 190 | // }); 191 | // console.log(zip2); 192 | // } 193 | // }); 194 | -------------------------------------------------------------------------------- /packages/faker/test/utils/index.js: -------------------------------------------------------------------------------- 1 | jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; 2 | export { getConnections } from '@launchql/db-testing'; 3 | -------------------------------------------------------------------------------- /packages/faker/verify/schemas/faker/procedures/utils.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/faker/procedures/utils on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_function ('faker.utils'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /packages/faker/verify/schemas/faker/schema.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/faker/schema on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_schema ('faker'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /packages/faker/verify/schemas/faker/tables/cities/fixtures/1602987351008_fixture.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/faker/tables/cities/fixtures/1602987351008_fixture on pg 2 | 3 | BEGIN; 4 | 5 | ROLLBACK; 6 | -------------------------------------------------------------------------------- /packages/faker/verify/schemas/faker/tables/cities/table.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/faker/tables/cities/table on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_table ('faker.cities'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /packages/faker/verify/schemas/faker/tables/dictionary/fixtures/1602969089665_fixture.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/faker/tables/dictionary/fixtures/1602969089665_fixture on pg 2 | 3 | BEGIN; 4 | 5 | ROLLBACK; 6 | -------------------------------------------------------------------------------- /packages/faker/verify/schemas/faker/tables/dictionary/table.sql: -------------------------------------------------------------------------------- 1 | -- Verify schemas/faker/tables/dictionary/table on pg 2 | 3 | BEGIN; 4 | 5 | SELECT verify_table ('faker.words'); 6 | 7 | ROLLBACK; 8 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # faker [![Build Status](https://travis-ci.com/pyramation/faker.svg?branch=master)](https://travis-ci.com/pyramation/faker) 2 | 3 | create fake data in PostgreSQL 4 | 5 | # Usage 6 | 7 | ## state, city, zip 8 | 9 | ```sql 10 | select faker.state(); 11 | -- CA 12 | 13 | select faker.city(); 14 | -- Belle Haven 15 | 16 | select faker.city('MI'); 17 | -- Livonia 18 | 19 | select faker.zip(); 20 | -- 48105 21 | 22 | select faker.zip('Los Angeles'); 23 | -- 90272 24 | ``` 25 | 26 | ## address, street 27 | 28 | ```sql 29 | select faker.address(); 30 | -- 762 MESA ST 31 | -- Fort Mohave, AZ 86427 32 | 33 | select faker.address('MI'); 34 | -- 2316 LAPHAM WAY 35 | -- Sterling Heights, MI 48312 36 | 37 | select faker.street(); 38 | -- CLAY ST 39 | ``` 40 | 41 | ## tags 42 | 43 | Tags can be seeded in `faker.dictionary` table, here's an example with sustainability 44 | 45 | ```sql 46 | select faker.tags(); 47 | -- {"causes of global warming","electronic waste","solar powered cars"} 48 | ``` 49 | 50 | ## words 51 | 52 | ```sql 53 | select faker.word(); 54 | -- woodpecker 55 | ``` 56 | 57 | Specify word types 58 | 59 | ```sql 60 | select faker.word(ARRAY['adjectives']); 61 | -- decisive 62 | ``` 63 | 64 | ## paragraphs 65 | 66 | ```sql 67 | select faker.paragraph(); 68 | -- Ligula. Aliquet torquent consequat egestas dui. Nullam sed tincidunt mauris porttitor ad taciti rutrum eleifend. Phasellus. 69 | ``` 70 | 71 | ## email 72 | 73 | ```sql 74 | select faker.email(); 75 | -- crimson79@hotmail.com 76 | ``` 77 | 78 | ## uuid 79 | 80 | ```sql 81 | select faker.uuid(); 82 | -- 327cb21d-1680-47ee-9979-3689e1bcb9ab 83 | ``` 84 | 85 | ## tokens, passwords 86 | 87 | ```sql 88 | select faker.token(); 89 | -- 9e23040a7825529beb1528c957eac73f 90 | 91 | select faker.token(20); 92 | -- 7504ef4eafbba04a9645198b10ebc9616afce13a 93 | 94 | select faker.password(); 95 | -- d8f1cca306e4d7^15bb(62618c1e 96 | ``` 97 | 98 | ## hostname 99 | 100 | ```sql 101 | select faker.hostname(); 102 | -- fine.net 103 | ``` 104 | 105 | ## time unit 106 | 107 | ```sql 108 | select faker.time_unit(); 109 | -- hour 110 | ``` 111 | 112 | ## float 113 | 114 | ```sql 115 | select faker.float(); 116 | -- 64.6970694223782 117 | 118 | select faker.float(2.3,10.5); 119 | -- 10.233102884792025 120 | ``` 121 | 122 | ## integer 123 | 124 | ```sql 125 | select faker.integer(); 126 | -- 8 127 | 128 | select faker.integer(2,10); 129 | -- 7 130 | ``` 131 | 132 | ## date 133 | 134 | ```sql 135 | select faker.date(); 136 | -- 2020-10-02 137 | ``` 138 | 139 | Date 1-3 days ago 140 | 141 | ```sql 142 | select faker.date(1,3); 143 | -- 2020-12-02 144 | ``` 145 | 146 | Date in the future between 1-3 days 147 | 148 | ```sql 149 | select faker.date(1,3, true); 150 | -- 2020-12-06 151 | ``` 152 | 153 | ## birthdate 154 | 155 | ```sql 156 | select faker.birthdate(); 157 | -- 2007-02-24 158 | ``` 159 | 160 | Generate birthdate for somebody who is between age of 37 and 64 161 | 162 | ```sql 163 | select faker.birthdate(37, 64); 164 | -- 1972-08-10 165 | ``` 166 | 167 | ## interval 168 | 169 | ```sql 170 | select faker.interval(); 171 | -- 00:01:34.959831 172 | ``` 173 | 174 | Generate an interval between 2 and 300 seconds 175 | 176 | ```sql 177 | select faker.interval(2,300); 178 | -- 00:01:04 179 | ``` 180 | 181 | ## gender 182 | 183 | ```sql 184 | select faker.gender(); 185 | -- F 186 | 187 | select faker.gender(); 188 | -- M 189 | ``` 190 | 191 | ## boolean 192 | 193 | ```sql 194 | select faker.boolean(); 195 | -- TRUE 196 | ``` 197 | 198 | ## timestamptz 199 | 200 | ```sql 201 | select faker.timestamptz(); 202 | -- 2019-12-20 15:57:29.520365+00 203 | ``` 204 | 205 | Future timestamptz 206 | 207 | ```sql 208 | select faker.timestamptz(TRUE); 209 | -- 2020-12-03 23:00:10.013301+00 210 | -- 211 | ``` 212 | 213 | ## mime types 214 | 215 | ```sql 216 | select faker.mime(); 217 | -- text/x-scss 218 | ``` 219 | 220 | ## file extensions 221 | 222 | ```sql 223 | select faker.ext(); 224 | -- html 225 | ``` 226 | 227 | Specify a mimetype 228 | 229 | ```sql 230 | select faker.ext('image/png'); 231 | -- png 232 | ``` 233 | 234 | Image mimetypes 235 | 236 | ```sql 237 | select faker.image_mime(); 238 | -- image/gif 239 | ``` 240 | 241 | ## image 242 | 243 | ```sql 244 | select faker.image(); 245 | -- {"url": "https://picsum.photos/843/874", "mime": "image/gif"} 246 | ``` 247 | 248 | ## profilepic 249 | 250 | credit: thank you https://randomuser.me 251 | 252 | ```sql 253 | select faker.profilepic(); 254 | -- {"url": "https://randomuser.me/api/portraits/women/53.jpg", "mime": "image/jpeg"} 255 | ``` 256 | 257 | Specify a gender 258 | 259 | ```sql 260 | select faker.profilepic('M'); 261 | -- {"url": "https://randomuser.me/api/portraits/men/4.jpg", "mime": "image/jpeg"} 262 | ``` 263 | 264 | ## file 265 | 266 | ```sql 267 | select faker.file(); 268 | -- scarlet.jpg 269 | ``` 270 | 271 | Specify a mimetype 272 | 273 | ```sql 274 | select faker.file('image/png'); 275 | -- anaconda.png 276 | ``` 277 | 278 | ## url 279 | 280 | ```sql 281 | select faker.url(); 282 | -- https://australian.io/copper.gzip 283 | ``` 284 | 285 | ## upload 286 | 287 | ```sql 288 | select faker.upload(); 289 | -- https://magenta.co/moccasin.yaml 290 | ``` 291 | 292 | ## attachment 293 | 294 | ```sql 295 | select faker.attachment(); 296 | -- {"url": "https://silver.io/sapphire.jsx", "mime": "text/jsx"} 297 | ``` 298 | 299 | ## phone 300 | 301 | ```sql 302 | select faker.phone(); 303 | -- +1 (121) 617-3329 304 | ``` 305 | 306 | ## ip 307 | 308 | ```sql 309 | select faker.ip(); 310 | -- 42.122.9.119 311 | ``` 312 | 313 | ## username 314 | 315 | ```sql 316 | select faker.username(); 317 | -- amaranth28 318 | ``` 319 | 320 | ## name 321 | 322 | ```sql 323 | select faker.name(); 324 | -- Lindsay 325 | ``` 326 | 327 | Specify a gender 328 | 329 | ```sql 330 | select faker.name('M'); 331 | -- Stuart 332 | 333 | select faker.name('F'); 334 | -- Shelly 335 | ``` 336 | 337 | ## surname 338 | 339 | ```sql 340 | select faker.surname(); 341 | -- Smith 342 | ``` 343 | 344 | ## fullname 345 | 346 | ```sql 347 | select faker.fullname(); 348 | -- Ross Silva 349 | 350 | select faker.fullname('M'); 351 | -- George Spencer 352 | ``` 353 | 354 | ## business 355 | 356 | ```sql 357 | select faker.business(); 358 | -- Seed Partners, Co. 359 | ``` 360 | 361 | ## longitude / latitude coordinates 362 | 363 | ```sql 364 | select faker.lnglat( -118.561721, 33.59, -117.646374, 34.23302 ); 365 | -- (-118.33162189532844,34.15614699957491) 366 | 367 | select faker.lnglat(); 368 | -- (-74.0205,40.316) 369 | ``` 370 | 371 | # Development 372 | 373 | ## start the postgres db process 374 | 375 | First you'll want to start the postgres docker (you can also just use `docker-compose up -d`): 376 | 377 | ```sh 378 | make up 379 | ``` 380 | 381 | ## install modules 382 | 383 | Install modules 384 | 385 | ```sh 386 | yarn install 387 | ``` 388 | 389 | ## install the Postgres extensions 390 | 391 | Now that the postgres process is running, install the extensions: 392 | 393 | ```sh 394 | make install 395 | ``` 396 | 397 | This basically `ssh`s into the postgres instance with the `packages/` folder mounted as a volume, and installs the bundled sql code as pgxn extensions. 398 | 399 | ## testing 400 | 401 | Testing will load all your latest sql changes and create fresh, populated databases for each sqitch module in `packages/`. 402 | 403 | ```sh 404 | yarn test:watch 405 | ``` 406 | 407 | ## building new modules 408 | 409 | Create a new folder in `packages/` 410 | 411 | ```sh 412 | lql init 413 | ``` 414 | 415 | Then, run a generator: 416 | 417 | ```sh 418 | lql generate 419 | ``` 420 | 421 | You can also add arguments if you already know what you want to do: 422 | 423 | ```sh 424 | lql generate schema --schema myschema 425 | lql generate table --schema myschema --table mytable 426 | ``` 427 | 428 | ## deploy code as extensions 429 | 430 | `cd` into `packages/`, and run `lql package`. This will make an sql file in `packages//sql/` used for `CREATE EXTENSION` calls to install your sqitch module as an extension. 431 | 432 | ## recursive deploy 433 | 434 | You can also deploy all modules utilizing versioning as sqtich modules. Remove `--createdb` if you already created your db: 435 | 436 | ```sh 437 | lql deploy awesome-db --yes --recursive --createdb 438 | ``` 439 | -------------------------------------------------------------------------------- /skitch.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*", 4 | "extensions/*" 5 | ] 6 | } --------------------------------------------------------------------------------