added createTestDataForResults
This commit is contained in:
parent
5a56e13d04
commit
e7086b8137
@ -2,6 +2,7 @@ package tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"gitea.pena/SQuiz/common/model"
|
||||
@ -22,9 +23,9 @@ import (
|
||||
// todo нужно определить из кликхауса на чем будем тестировать статистику
|
||||
|
||||
var PublicKey = `-----BEGIN PUBLIC KEY-----MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm6980fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6BdA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y+3GyaOY536H47qyXAgMBAAE=-----END PUBLIC KEY-----`
|
||||
|
||||
var baseURL = "http://127.0.0.1:1488" //os.Getenv("API_BASE_URL")
|
||||
var validToken = CreateJWT(validUserID) // validUserID
|
||||
var postgresCred = "postgres://squiz:Redalert2@localhost:35432/squiz?sslmode=disable" //os.Getenv("POSTGRES_CRED")
|
||||
var baseURL = "http://127.0.0.1:1488" //os.Getenv("API_BASE_URL")
|
||||
var validToken = CreateJWT(validUserID) // validUserID
|
||||
var expiredToken = CreateExpiredToken(validUserID)
|
||||
|
||||
// todo
|
||||
@ -7250,6 +7251,221 @@ func TestCreateQuizTemplate_SpecialCases(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// todo перевроверить через дамп
|
||||
type TestData struct {
|
||||
Quiz model.Quiz
|
||||
Questions []model.Question
|
||||
Answers []model.Answer
|
||||
}
|
||||
|
||||
func createTestDataForResults(t *testing.T, token string, quizName string) *TestData {
|
||||
quizResp, err := createQuizRequest(token, map[string]interface{}{
|
||||
"name": quizName,
|
||||
"status": "start",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer quizResp.Body.Close()
|
||||
assert.Equal(t, http.StatusCreated, quizResp.StatusCode)
|
||||
|
||||
var quizResult model.Quiz
|
||||
err = json.NewDecoder(quizResp.Body).Decode(&quizResult)
|
||||
assert.NoError(t, err)
|
||||
|
||||
questions := []model.Question{}
|
||||
questionData := []map[string]interface{}{
|
||||
{
|
||||
"title": "Какой основной компонент воздуха?",
|
||||
"type": "variant",
|
||||
"description": "Выберите один правильный ответ.",
|
||||
"required": true,
|
||||
"page": 1,
|
||||
"content": `{"variants": ["Кислород", "Азот", "Углекислый газ", "Водород"], "correct": 1}`,
|
||||
},
|
||||
{
|
||||
"title": "Столица России?",
|
||||
"type": "text",
|
||||
"description": "Введите название столицы.",
|
||||
"required": true,
|
||||
"page": 1,
|
||||
"content": `{"maxLength": 50}`,
|
||||
},
|
||||
{
|
||||
"title": "Ваш возраст",
|
||||
"type": "number",
|
||||
"description": "Укажите ваш возраст.",
|
||||
"required": false,
|
||||
"page": 2,
|
||||
"content": `{"min": 0, "max": 120}`,
|
||||
},
|
||||
{
|
||||
"title": "Форма контактов",
|
||||
"type": "result",
|
||||
"description": "Оставьте свои контактные данные.",
|
||||
"required": true,
|
||||
"page": 2,
|
||||
"content": `{"fields": ["name", "email", "phone"]}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, qData := range questionData {
|
||||
qData["quiz_id"] = quizResult.Id
|
||||
questionResp, err := createQuestionRequest(token, qData)
|
||||
assert.NoError(t, err)
|
||||
defer questionResp.Body.Close()
|
||||
assert.Equal(t, http.StatusOK, questionResp.StatusCode)
|
||||
|
||||
var questionResult model.Question
|
||||
err = json.NewDecoder(questionResp.Body).Decode(&questionResult)
|
||||
assert.NoError(t, err)
|
||||
questions = append(questions, questionResult)
|
||||
}
|
||||
|
||||
answers := createAnswersInDB(t, quizResult.Id, questions)
|
||||
|
||||
return &TestData{
|
||||
Quiz: quizResult,
|
||||
Questions: questions,
|
||||
Answers: answers,
|
||||
}
|
||||
}
|
||||
|
||||
func createAnswersInDB(t *testing.T, quizID uint64, questions []model.Question) []model.Answer {
|
||||
db, err := sql.Open("postgres", postgresCred)
|
||||
assert.NoError(t, err)
|
||||
defer db.Close()
|
||||
|
||||
answers := []model.Answer{}
|
||||
|
||||
sessions := []string{faker.String(), faker.String(), faker.String()}
|
||||
|
||||
for i, session := range sessions {
|
||||
for j, question := range questions {
|
||||
if question.Type == "result" {
|
||||
continue
|
||||
}
|
||||
|
||||
answerContent := ""
|
||||
switch question.Type {
|
||||
case "variant":
|
||||
answerContent = `{"selected": 1, "answer": "Азот"}`
|
||||
case "text":
|
||||
answerContent = `{"answer": "Москва"}`
|
||||
case "number":
|
||||
answerContent = `{"answer": 25}`
|
||||
default:
|
||||
answerContent = `{"answer": "тестовый ответ"}`
|
||||
}
|
||||
|
||||
query := `
|
||||
INSERT INTO answer (content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||||
RETURNING id, content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version, created_at
|
||||
`
|
||||
|
||||
var answer model.Answer
|
||||
err := db.QueryRow(
|
||||
query,
|
||||
answerContent,
|
||||
quizID,
|
||||
question.Id,
|
||||
fmt.Sprintf("fingerprint_%d_%d", i, j),
|
||||
session,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
faker.Email(),
|
||||
"desktop",
|
||||
"Chrome",
|
||||
"Chrome 120.0",
|
||||
"192.168.1.1",
|
||||
"Windows 10",
|
||||
j == 0,
|
||||
1,
|
||||
).Scan(
|
||||
&answer.Id,
|
||||
&answer.Content,
|
||||
&answer.QuizId,
|
||||
&answer.QuestionId,
|
||||
&answer.Fingerprint,
|
||||
&answer.Session,
|
||||
&answer.Result,
|
||||
&answer.New,
|
||||
&answer.Deleted,
|
||||
&answer.Email,
|
||||
&answer.DeviceType,
|
||||
&answer.Device,
|
||||
&answer.Browser,
|
||||
&answer.IP,
|
||||
&answer.OS,
|
||||
&answer.Start,
|
||||
&answer.Version,
|
||||
&answer.CreatedAt,
|
||||
)
|
||||
|
||||
assert.NoError(t, err)
|
||||
answers = append(answers, answer)
|
||||
}
|
||||
|
||||
for _, question := range questions {
|
||||
if question.Type == "result" {
|
||||
answerContent := `{"name": "Иван Иванов", "email": "ivan@test.com", "phone": "+7-999-123-45-67"}`
|
||||
|
||||
query := `
|
||||
INSERT INTO answer (content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
|
||||
RETURNING id, content, quiz_id, question_id, fingerprint, session, result, new, deleted, email, device_type, device, browser, ip, os, start, version, created_at
|
||||
`
|
||||
|
||||
var answer model.Answer
|
||||
err := db.QueryRow(
|
||||
query,
|
||||
answerContent,
|
||||
quizID,
|
||||
question.Id,
|
||||
fmt.Sprintf("fingerprint_result_%d", i),
|
||||
session,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
faker.Email(),
|
||||
"desktop",
|
||||
"Chrome",
|
||||
"Chrome 120.0",
|
||||
"192.168.1.1",
|
||||
"Windows 10",
|
||||
false,
|
||||
1,
|
||||
).Scan(
|
||||
&answer.Id,
|
||||
&answer.Content,
|
||||
&answer.QuizId,
|
||||
&answer.QuestionId,
|
||||
&answer.Fingerprint,
|
||||
&answer.Session,
|
||||
&answer.Result,
|
||||
&answer.New,
|
||||
&answer.Deleted,
|
||||
&answer.Email,
|
||||
&answer.DeviceType,
|
||||
&answer.Device,
|
||||
&answer.Browser,
|
||||
&answer.IP,
|
||||
&answer.OS,
|
||||
&answer.Start,
|
||||
&answer.Version,
|
||||
&answer.CreatedAt,
|
||||
)
|
||||
|
||||
assert.NoError(t, err)
|
||||
answers = append(answers, answer)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return answers
|
||||
}
|
||||
|
||||
func getResultsRequest(token string, quizId string, body map[string]interface{}) (*http.Response, error) {
|
||||
payload, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
@ -7264,58 +7480,11 @@ func getResultsRequest(token string, quizId string, body map[string]interface{})
|
||||
return http.DefaultClient.Do(req)
|
||||
}
|
||||
|
||||
// todo для этих тестов нужно заранее заполнять бдшку ответами на вопросы
|
||||
// отсмотрено
|
||||
func TestGetResults_Success(t *testing.T) {
|
||||
quizResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||||
"name": "Квиз для тестирования результатов",
|
||||
"status": "start",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer quizResp.Body.Close()
|
||||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования результатов")
|
||||
|
||||
var quizResult model.Quiz
|
||||
err = json.NewDecoder(quizResp.Body).Decode(&quizResult)
|
||||
assert.NoError(t, err)
|
||||
quizID := quizResult.Id
|
||||
|
||||
question1Resp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||||
"quiz_id": quizID,
|
||||
"title": "Какой основной компонент воздуха?",
|
||||
"type": "variant",
|
||||
"description": "Выберите один правильный ответ.",
|
||||
"required": true,
|
||||
"page": 1,
|
||||
"content": `{"variants": ["Кислород", "Азот", "Углекислый газ", "Водород"]}`,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer question1Resp.Body.Close()
|
||||
|
||||
var question1Result model.Question
|
||||
err = json.NewDecoder(question1Resp.Body).Decode(&question1Result)
|
||||
assert.NoError(t, err)
|
||||
|
||||
question2Resp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||||
"quiz_id": quizID,
|
||||
"title": "Столица России?",
|
||||
"type": "text",
|
||||
"description": "Введите название города.",
|
||||
"required": true,
|
||||
"page": 1,
|
||||
"content": `{"placeholder": "Введите ответ"}`,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer question2Resp.Body.Close()
|
||||
|
||||
var question2Result model.Question
|
||||
err = json.NewDecoder(question2Resp.Body).Decode(&question2Result)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Создаем тестовые ответы (симулируем прохождение квиза)
|
||||
// В реальном приложении ответы создаются через отдельный API
|
||||
// Здесь мы будем тестировать получение результатов без ответов
|
||||
|
||||
// Тестируем получение результатов
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||||
"Page": 0,
|
||||
"Limit": 10,
|
||||
})
|
||||
@ -7331,18 +7500,14 @@ func TestGetResults_Success(t *testing.T) {
|
||||
assert.NotNil(t, result.TotalCount)
|
||||
assert.NotNil(t, result.Results)
|
||||
|
||||
// Проверяем, что результаты возвращаются в правильном формате
|
||||
assert.IsType(t, uint64(0), result.TotalCount)
|
||||
assert.IsType(t, []model.AnswerExport{}, result.Results)
|
||||
|
||||
// Если есть результаты, проверяем их структуру
|
||||
if len(result.Results) > 0 {
|
||||
for _, answer := range result.Results {
|
||||
assert.NotEmpty(t, answer.Id)
|
||||
assert.NotEmpty(t, answer.CreatedAt)
|
||||
assert.IsType(t, bool(false), answer.New)
|
||||
assert.IsType(t, int32(0), answer.Version)
|
||||
}
|
||||
assert.Greater(t, result.TotalCount, uint64(0))
|
||||
assert.Greater(t, len(result.Results), 0)
|
||||
|
||||
for _, answer := range result.Results {
|
||||
assert.NotEmpty(t, answer.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7403,40 +7568,11 @@ func TestGetResults_InputValidation(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// todo для этих тестов нужно заранее заполнять бдшку ответами на вопросы
|
||||
func TestGetResults_Pagination(t *testing.T) {
|
||||
// Создаем квиз для тестирования пагинации
|
||||
quizResp, err := createQuizRequest(validToken, map[string]interface{}{
|
||||
"name": "Квиз для тестирования пагинации результатов",
|
||||
"status": "start",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer quizResp.Body.Close()
|
||||
|
||||
var quizResult model.Quiz
|
||||
err = json.NewDecoder(quizResp.Body).Decode(&quizResult)
|
||||
assert.NoError(t, err)
|
||||
quizID := quizResult.Id
|
||||
|
||||
// Создаем несколько вопросов для квиза
|
||||
questionResp, err := createQuestionRequest(validToken, map[string]interface{}{
|
||||
"quiz_id": quizID,
|
||||
"title": "Тестовый вопрос для пагинации",
|
||||
"type": "text",
|
||||
"description": "Введите ответ.",
|
||||
"required": true,
|
||||
"page": 1,
|
||||
"content": `{"placeholder": "Введите ответ"}`,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer questionResp.Body.Close()
|
||||
|
||||
var questionResult model.Question
|
||||
err = json.NewDecoder(questionResp.Body).Decode(&questionResult)
|
||||
assert.NoError(t, err)
|
||||
testData := createTestDataForResults(t, validToken, "Квиз для тестирования пагинации результатов")
|
||||
|
||||
t.Run("FirstPage", func(t *testing.T) {
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||||
"Page": 0,
|
||||
"Limit": 5,
|
||||
})
|
||||
@ -7448,13 +7584,12 @@ func TestGetResults_Pagination(t *testing.T) {
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Проверяем, что количество результатов не превышает лимит
|
||||
assert.LessOrEqual(t, uint64(len(result.Results)), uint64(5))
|
||||
assert.Equal(t, result.TotalCount, uint64(len(result.Results)))
|
||||
})
|
||||
|
||||
t.Run("SecondPage", func(t *testing.T) {
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||||
"Page": 1,
|
||||
"Limit": 5,
|
||||
})
|
||||
@ -7472,7 +7607,7 @@ func TestGetResults_Pagination(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("EmptyPage", func(t *testing.T) {
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||||
"Page": 100,
|
||||
"Limit": 5,
|
||||
})
|
||||
@ -7490,7 +7625,7 @@ func TestGetResults_Pagination(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("ZeroLimit", func(t *testing.T) {
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", quizID), map[string]interface{}{
|
||||
resp, err := getResultsRequest(validToken, fmt.Sprintf("%v", testData.Quiz.Id), map[string]interface{}{
|
||||
"Page": 0,
|
||||
"Limit": 0,
|
||||
})
|
||||
|
24
tests/schema/000001_init.down.sql
Normal file
24
tests/schema/000001_init.down.sql
Normal file
@ -0,0 +1,24 @@
|
||||
-- Drop indexes
|
||||
DROP INDEX IF EXISTS subquizes;
|
||||
DROP INDEX IF EXISTS birthtime;
|
||||
DROP INDEX IF EXISTS groups;
|
||||
DROP INDEX IF EXISTS timeouted;
|
||||
DROP INDEX IF EXISTS active ON quiz;
|
||||
DROP INDEX IF EXISTS questiontype;
|
||||
DROP INDEX IF EXISTS required;
|
||||
DROP INDEX IF EXISTS relation;
|
||||
DROP INDEX IF EXISTS active ON question;
|
||||
|
||||
-- Drop tables
|
||||
DROP TABLE IF EXISTS privileges;
|
||||
DROP TABLE IF EXISTS answer;
|
||||
DROP TABLE IF EXISTS question;
|
||||
DROP TABLE IF EXISTS quiz;
|
||||
DROP TABLE IF EXISTS account;
|
||||
|
||||
-- Drop types
|
||||
DO $$
|
||||
BEGIN
|
||||
DROP TYPE IF EXISTS question_type;
|
||||
DROP TYPE IF EXISTS quiz_status;
|
||||
END$$;
|
120
tests/schema/000001_init.up.sql
Normal file
120
tests/schema/000001_init.up.sql
Normal file
@ -0,0 +1,120 @@
|
||||
-- Create types
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'question_type') THEN
|
||||
CREATE TYPE question_type AS ENUM (
|
||||
'variant',
|
||||
'images',
|
||||
'varimg',
|
||||
'emoji',
|
||||
'text',
|
||||
'select',
|
||||
'date',
|
||||
'number',
|
||||
'file',
|
||||
'page',
|
||||
'rating'
|
||||
);
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'quiz_status') THEN
|
||||
CREATE TYPE quiz_status AS ENUM (
|
||||
'draft',
|
||||
'template',
|
||||
'stop',
|
||||
'start',
|
||||
'timeout',
|
||||
'offlimit'
|
||||
);
|
||||
END IF;
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
END$$;
|
||||
|
||||
-- Create tables
|
||||
CREATE TABLE IF NOT EXISTS account (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id VARCHAR(24),
|
||||
email VARCHAR(50),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted BOOLEAN DEFAULT false
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS quiz (
|
||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
||||
qid uuid DEFAULT uuid_generate_v4(),
|
||||
accountid varchar(30) NOT NULL,
|
||||
deleted boolean DEFAULT false,
|
||||
archived boolean DEFAULT false,
|
||||
fingerprinting boolean DEFAULT false,
|
||||
repeatable boolean DEFAULT false,
|
||||
note_prevented boolean DEFAULT false,
|
||||
mail_notifications boolean DEFAULT false,
|
||||
unique_answers boolean DEFAULT false,
|
||||
super boolean DEFAULT false,
|
||||
group_id bigint DEFAULT 0,
|
||||
name varchar(280),
|
||||
description text,
|
||||
config text,
|
||||
status quiz_status DEFAULT 'draft',
|
||||
limit_answers integer DEFAULT 0,
|
||||
due_to integer DEFAULT 0,
|
||||
time_of_passing integer DEFAULT 0,
|
||||
pausable boolean DEFAULT false,
|
||||
version smallint DEFAULT 0,
|
||||
version_comment text DEFAULT '',
|
||||
parent_ids integer[],
|
||||
created_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
questions_count integer DEFAULT 0,
|
||||
answers_count integer DEFAULT 0,
|
||||
average_time_passing integer DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS question (
|
||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
||||
quiz_id bigint NOT NULL,
|
||||
title varchar(512) NOT NULL,
|
||||
description text,
|
||||
questiontype question_type DEFAULT 'text',
|
||||
required boolean DEFAULT false,
|
||||
deleted boolean DEFAULT false,
|
||||
page smallint DEFAULT 0,
|
||||
content text,
|
||||
version smallint DEFAULT 0,
|
||||
parent_ids integer[],
|
||||
created_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT quiz_relation FOREIGN KEY(quiz_id) REFERENCES quiz(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS answer (
|
||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
||||
content text,
|
||||
quiz_id bigint NOT NULL REFERENCES quiz(id),
|
||||
question_id bigint NOT NULL REFERENCES question(id),
|
||||
fingerprint varchar(1024),
|
||||
session varchar(20),
|
||||
created_at timestamp DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS privileges (
|
||||
id SERIAL PRIMARY KEY,
|
||||
privilegeID VARCHAR(50),
|
||||
account_id UUID,
|
||||
privilege_name VARCHAR(255),
|
||||
amount INT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (account_id) REFERENCES account (id)
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX IF NOT EXISTS active ON question(deleted) WHERE deleted=false;
|
||||
CREATE INDEX IF NOT EXISTS relation ON question(quiz_id DESC);
|
||||
CREATE INDEX IF NOT EXISTS required ON question(required DESC);
|
||||
CREATE INDEX IF NOT EXISTS questiontype ON question(questiontype);
|
||||
CREATE INDEX IF NOT EXISTS active ON quiz(deleted, archived, status) WHERE deleted = false AND archived = false AND status = 'start';
|
||||
CREATE INDEX IF NOT EXISTS timeouted ON quiz(due_to DESC) WHERE deleted = false AND due_to <> 0 AND status <> 'timeout';
|
||||
CREATE INDEX IF NOT EXISTS groups ON quiz(super) WHERE super = true;
|
||||
CREATE INDEX IF NOT EXISTS birthtime ON quiz(created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS subquizes ON quiz(group_id DESC) WHERE group_id <> 0;
|
1
tests/schema/000002_init.down.sql
Normal file
1
tests/schema/000002_init.down.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE answer DROP COLUMN IF EXISTS result;
|
1
tests/schema/000002_init.up.sql
Normal file
1
tests/schema/000002_init.up.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE answer ADD COLUMN result BOOLEAN DEFAULT FALSE;
|
1
tests/schema/000003_init.down.sql
Normal file
1
tests/schema/000003_init.down.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE quiz DROP COLUMN IF EXISTS sessions_count;
|
1
tests/schema/000003_init.up.sql
Normal file
1
tests/schema/000003_init.up.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE quiz ADD COLUMN sessions_count integer;
|
2
tests/schema/000004_init.down.sql
Normal file
2
tests/schema/000004_init.down.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE quiz DROP COLUMN IF EXISTS new;
|
||||
ALTER TABLE quiz DROP COLUMN IF EXISTS deleted;
|
2
tests/schema/000004_init.up.sql
Normal file
2
tests/schema/000004_init.up.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE answer ADD COLUMN new BOOLEAN DEFAULT TRUE;
|
||||
ALTER TABLE answer ADD COLUMN deleted BOOLEAN DEFAULT FALSE;
|
2
tests/schema/000005_init.down.sql
Normal file
2
tests/schema/000005_init.down.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE answer DROP COLUMN IF EXISTS email;
|
||||
DROP INDEX IF EXISTS answer_email_unique_idx;
|
2
tests/schema/000005_init.up.sql
Normal file
2
tests/schema/000005_init.up.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE answer ADD COLUMN email VARCHAR(50) NOT NULL DEFAULT '';
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS answer_email_unique_idx ON answer (quiz_id, email) WHERE email <> '';
|
6
tests/schema/000006_init.down.sql
Normal file
6
tests/schema/000006_init.down.sql
Normal file
@ -0,0 +1,6 @@
|
||||
ALTER TABLE answer
|
||||
DROP COLUMN device_type,
|
||||
DROP COLUMN device,
|
||||
DROP COLUMN os,
|
||||
DROP COLUMN browser,
|
||||
DROP COLUMN ip;
|
6
tests/schema/000006_init.up.sql
Normal file
6
tests/schema/000006_init.up.sql
Normal file
@ -0,0 +1,6 @@
|
||||
ALTER TABLE answer
|
||||
ADD COLUMN device_type VARCHAR(50) NOT NULL DEFAULT '',
|
||||
ADD COLUMN device VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ADD COLUMN os VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ADD COLUMN browser VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ADD COLUMN ip VARCHAR(50) NOT NULL DEFAULT '';
|
2
tests/schema/000007_init.down.sql
Normal file
2
tests/schema/000007_init.down.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE answer
|
||||
DROP COLUMN start;
|
2
tests/schema/000007_init.up.sql
Normal file
2
tests/schema/000007_init.up.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE answer
|
||||
ADD COLUMN start BOOLEAN NOT NULL DEFAULT FALSE;
|
4
tests/schema/000008_init.down.sql
Normal file
4
tests/schema/000008_init.down.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE answer
|
||||
ALTER COLUMN device TYPE VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ALTER COLUMN os TYPE VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ALTER COLUMN browser TYPE VARCHAR(100) NOT NULL DEFAULT '',
|
4
tests/schema/000008_init.up.sql
Normal file
4
tests/schema/000008_init.up.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE answer
|
||||
ALTER COLUMN device TYPE VARCHAR(1024),
|
||||
ALTER COLUMN os TYPE VARCHAR(1024),
|
||||
ALTER COLUMN browser TYPE VARCHAR(1024);
|
4
tests/schema/000009_init.down.sql
Normal file
4
tests/schema/000009_init.down.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE answer
|
||||
ALTER COLUMN device VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ALTER COLUMN os VARCHAR(100) NOT NULL DEFAULT '',
|
||||
ALTER COLUMN browser VARCHAR(100) NOT NULL DEFAULT '',
|
4
tests/schema/000009_init.up.sql
Normal file
4
tests/schema/000009_init.up.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE answer
|
||||
ALTER COLUMN device TYPE VARCHAR(512),
|
||||
ALTER COLUMN os TYPE VARCHAR(512),
|
||||
ALTER COLUMN browser TYPE VARCHAR(512);
|
31
tests/schema/000010_init.down.sql
Normal file
31
tests/schema/000010_init.down.sql
Normal file
@ -0,0 +1,31 @@
|
||||
DROP INDEX IF EXISTS idx_unique_users;
|
||||
DROP INDEX IF EXISTS idx_unique_pipeline;
|
||||
DROP INDEX IF EXISTS idx_unique_step;
|
||||
DROP INDEX IF EXISTS idx_unique_field;
|
||||
DROP INDEX IF EXISTS idx_unique_tag;
|
||||
DROP INDEX IF EXISTS idx_unique_rules;
|
||||
|
||||
DROP TABLE IF EXISTS amoCRMStatuses;
|
||||
DROP TABLE IF EXISTS rules;
|
||||
DROP TABLE IF EXISTS utms;
|
||||
DROP TABLE IF EXISTS tags;
|
||||
DROP TABLE IF EXISTS fields;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entitytype') THEN
|
||||
DROP TYPE EntityType;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'fieldtype') THEN
|
||||
DROP TYPE FieldType;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DROP TABLE IF EXISTS steps;
|
||||
DROP TABLE IF EXISTS pipelines;
|
||||
DROP TABLE IF EXISTS tokens;
|
||||
DROP TABLE IF EXISTS users;
|
119
tests/schema/000010_init.up.sql
Normal file
119
tests/schema/000010_init.up.sql
Normal file
@ -0,0 +1,119 @@
|
||||
CREATE TABLE IF NOT EXISTS tokens (
|
||||
AccountID VARCHAR(30) PRIMARY KEY, -- связь с users AccountID неявная посредством join
|
||||
RefreshToken TEXT NOT NULL ,
|
||||
AccessToken TEXT NOT NULL ,
|
||||
AuthCode TEXT NOT NULL , -- код авторизации который получаем при вебхук
|
||||
Expiration TIMESTAMP NOT NULL, -- время истечения токенов
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(30) NOT NULL DEFAULT '', -- id квизе из токена
|
||||
AmoID INT NOT NULL , -- id в амо
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', -- имя в амо
|
||||
Email VARCHAR(50) NOT NULL DEFAULT '', -- почта в амо
|
||||
Role INT NOT NULL DEFAULT 0, -- роль в амо
|
||||
"Group" INT NOT NULL DEFAULT 0, -- вложенная структура так как в амо группы хранятся массивом структур
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
Subdomain VARCHAR(50) NOT NULL DEFAULT '',
|
||||
AmoUserID INT NOT NULL , -- id пользователя который подключал интеграцию
|
||||
Country VARCHAR(50) NOT NULL DEFAULT '' -- страна в амо
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS pipelines (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AmoID INT NOT NULL , --id воронки в амо
|
||||
AccountID INT NOT NULL , --id аккаунта в амо связь с таблицей users AmoID неявная посредством join
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', --название воронки в амо
|
||||
IsArchive BOOLEAN NOT NULL DEFAULT FALSE, --флаг архивной воронки в амо
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS steps (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AmoID INT NOT NULL, --id шага воронки в амо
|
||||
PipelineID INT NOT NULL, --id воронки AmoID pipelines неявная посредством join
|
||||
AccountID INT NOT NULL, --id аккаунта в амо связь с таблицей users AmoID неявная посредством join
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', --название воронки в амо
|
||||
Color VARCHAR(50) NOT NULL DEFAULT '', --цвет шага в амо*
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'entitytype') THEN
|
||||
CREATE TYPE EntityType AS ENUM ('leads', 'contacts', 'companies', 'customers');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'fieldtype') THEN
|
||||
CREATE TYPE FieldType AS ENUM ('text', 'numeric', 'checkbox', 'select', 'multiselect', 'date', 'url', 'textarea', 'radiobutton', 'streetaddress', 'smart_address', 'birthday', 'legal_entity', 'date_time', 'price', 'category', 'items', 'tracking_data', 'linked_entity', 'chained_list', 'monetary', 'file', 'payer', 'supplier', 'multitext');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fields (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AmoID INT NOT NULL, -- айдишник кастомного поля в амо
|
||||
Code VARCHAR(255) NOT NULL DEFAULT '', -- кодовое слово в амо
|
||||
AccountID INT NOT NULL, -- id аккаунта в амо связь с таблицей users AmoID неявная посредством join
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', -- название воронки в амо
|
||||
Entity EntityType NOT NULL, -- тип сущности в амо, для которой это кастомное поле
|
||||
Type FieldType NOT NULL, -- тип поля
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AmoID INT NOT NULL, -- айдишник тега в амо
|
||||
AccountID INT NOT NULL, -- id аккаунта в амо связь с таблицей users AmoID неявная посредством join
|
||||
Entity EntityType NOT NULL, -- сущность, к которой принадлежит этот тег
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', -- название тега в амо
|
||||
Color VARCHAR(50) NOT NULL DEFAULT '', -- цвет тега в амо
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS utms (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AmoFieldID INT NOT NULL DEFAULT 0, -- id field в амо
|
||||
QuizID INT NOT NULL, -- id опроса
|
||||
AccountID INT NOT NULL, -- id аккаунта в амо AMOID
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', -- название utm
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rules (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID INT NOT NULL, -- id аккаунта в амо AMOID
|
||||
QuizID INT NOT NULL, -- id опроса
|
||||
PerformerID INT NOT NULL, -- айдишник ответственного за сделку
|
||||
PipelineID INT NOT NULL, --id воронки AmoID pipelines неявная посредством join
|
||||
StepID INT NOT NULL , -- id этапа steps AmoID join
|
||||
UTMS INTEGER[], -- список UTM для этого опроса id utm
|
||||
FieldsRule JSONB NOT NULL DEFAULT '{}', -- вложенная структура
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_unique_users ON users (amoID);
|
||||
CREATE UNIQUE INDEX idx_unique_pipeline ON pipelines (amoID, accountID);
|
||||
CREATE UNIQUE INDEX idx_unique_step ON steps (amoID, accountID, PipelineID);
|
||||
CREATE UNIQUE INDEX idx_unique_field ON fields (amoID, accountID, entity);
|
||||
CREATE UNIQUE INDEX idx_unique_tag ON tags (amoID, accountID, entity);
|
||||
CREATE UNIQUE INDEX idx_unique_rules ON rules (accountID, QuizID);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS amoCRMStatuses (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID INT NOT NULL, -- id аккаунта в амо
|
||||
DealID INT NOT NULL, -- id сделки в которую добавлялось
|
||||
AnswerID BIGINT NOT NULL REFERENCES answer(id), -- id true result который вызвал действие
|
||||
Status TEXT NOT NULL DEFAULT '', -- запись о ошибке, либо успехе
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
15
tests/schema/000011_init.down.sql
Normal file
15
tests/schema/000011_init.down.sql
Normal file
@ -0,0 +1,15 @@
|
||||
ALTER TABLE answer
|
||||
DROP COLUMN utm;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS utms (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AmoFieldID INT NOT NULL DEFAULT 0, -- id field в амо
|
||||
QuizID INT NOT NULL, -- id опроса
|
||||
AccountID INT NOT NULL, -- id аккаунта в амо AMOID
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', -- название utm
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE rules
|
||||
ADD COLUMN UTMS INTEGER[];
|
5
tests/schema/000011_init.up.sql
Normal file
5
tests/schema/000011_init.up.sql
Normal file
@ -0,0 +1,5 @@
|
||||
ALTER TABLE answer
|
||||
ADD COLUMN utm jsonb NOT NULL DEFAULT '{}';
|
||||
DROP TABLE IF EXISTS utms;
|
||||
ALTER TABLE rules
|
||||
DROP COLUMN IF EXISTS UTMS;
|
4
tests/schema/000012_init.down.sql
Normal file
4
tests/schema/000012_init.down.sql
Normal file
@ -0,0 +1,4 @@
|
||||
DROP INDEX IF EXISTS idx_unique_users;
|
||||
DROP INDEX IF EXISTS idx_unique_rules;
|
||||
CREATE UNIQUE INDEX idx_unique_users ON users (amoID);
|
||||
CREATE UNIQUE INDEX idx_unique_rules ON rules (accountID, QuizID);
|
4
tests/schema/000012_init.up.sql
Normal file
4
tests/schema/000012_init.up.sql
Normal file
@ -0,0 +1,4 @@
|
||||
DROP INDEX IF EXISTS idx_unique_users;
|
||||
DROP INDEX IF EXISTS idx_unique_rules;
|
||||
CREATE UNIQUE INDEX idx_unique_users ON users (amoID) WHERE Deleted = false;
|
||||
CREATE UNIQUE INDEX idx_unique_rules ON rules (accountID, QuizID) WHERE Deleted = false;
|
4
tests/schema/000013_init.down.sql
Normal file
4
tests/schema/000013_init.down.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE rules
|
||||
DROP COLUMN IF EXISTS TagsToAdd;
|
||||
ALTER TABLE users
|
||||
DROP COLUMN IF EXISTS DriveURL;
|
4
tests/schema/000013_init.up.sql
Normal file
4
tests/schema/000013_init.up.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE rules
|
||||
ADD COLUMN TagsToAdd JSONB NOT NULL DEFAULT '{}';
|
||||
ALTER TABLE users
|
||||
ADD COLUMN DriveURL text NOT NULL DEFAULT '';
|
20
tests/schema/000014_init.down.sql
Normal file
20
tests/schema/000014_init.down.sql
Normal file
@ -0,0 +1,20 @@
|
||||
DROP TABLE IF EXISTS usersAmo;
|
||||
DROP INDEX IF EXISTS idx_unique_accountsAmo;
|
||||
DROP TABLE IF EXISTS accountsAmo;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(30) NOT NULL DEFAULT '', -- id квизе из токена
|
||||
AmoID INT NOT NULL , -- id в амо
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '', -- имя в амо
|
||||
Email VARCHAR(50) NOT NULL DEFAULT '', -- почта в амо
|
||||
Role INT NOT NULL DEFAULT 0, -- роль в амо
|
||||
"Group" INT NOT NULL DEFAULT 0, -- вложенная структура так как в амо группы хранятся массивом структур
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
Subdomain VARCHAR(50) NOT NULL DEFAULT '',
|
||||
AmoUserID INT NOT NULL , -- id пользователя который подключал интеграцию
|
||||
Country VARCHAR(50) NOT NULL DEFAULT '' -- страна в амо
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_unique_users ON users (amoID) WHERE Deleted = false;
|
28
tests/schema/000014_init.up.sql
Normal file
28
tests/schema/000014_init.up.sql
Normal file
@ -0,0 +1,28 @@
|
||||
DROP TABLE IF EXISTS users;
|
||||
DROP INDEX IF EXISTS idx_unique_users;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS accountsAmo (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(30) NOT NULL DEFAULT '', -- ID аккаунта у нас
|
||||
AmoID INT NOT NULL, -- ID "компании" в амо
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '',
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
Subdomain VARCHAR(50) NOT NULL DEFAULT '', -- поддомен - пример https://penadigitaltech.amocrm.ru
|
||||
Country VARCHAR(50) NOT NULL DEFAULT '',
|
||||
DriveURL VARCHAR(255) NOT NULL DEFAULT '' -- URL объктного хранилища
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_unique_accountsAmo ON accountsAmo (amoID) WHERE Deleted = false;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS usersAmo (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AmoID INT NOT NULL, -- ID компании в амо (внешний ключ)
|
||||
AmoUserID INT NOT NULL, -- ID пользователя в амо
|
||||
Name VARCHAR(512) NOT NULL DEFAULT '',
|
||||
Email VARCHAR(50) NOT NULL DEFAULT '',
|
||||
Role INT NOT NULL DEFAULT 0,
|
||||
"Group" INT NOT NULL DEFAULT 0,
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
0
tests/schema/000015_init.down.sql
Normal file
0
tests/schema/000015_init.down.sql
Normal file
19
tests/schema/000015_init.up.sql
Normal file
19
tests/schema/000015_init.up.sql
Normal file
@ -0,0 +1,19 @@
|
||||
UPDATE answer
|
||||
SET content =
|
||||
CASE
|
||||
WHEN content ~ '<tr>|<td>' THEN
|
||||
regexp_replace(content, '<\/?tr[^>]*>|<\/?td[^>]*>', '', 'g')
|
||||
WHEN content ~ '<a download>[^<]+</a>' THEN
|
||||
regexp_replace(content, '<a download>([^<]+)</a>', '\1', 'g')
|
||||
WHEN content ~ '<img[^>]*src="([^"]*)"[^>]*' THEN
|
||||
regexp_replace(content, '<img[^>]*src="\s*"[^>]*', '', 'g')
|
||||
ELSE content
|
||||
END;
|
||||
|
||||
UPDATE answer
|
||||
SET content =
|
||||
CASE
|
||||
WHEN content ~ '<img' THEN
|
||||
regexp_replace(content, '(.*?)(<img[^>]*src=["'']?([^"''>]+)["'']?[^>]*>)', '\1\3', 'g')
|
||||
ELSE content
|
||||
END;
|
1
tests/schema/000016_init.down.sql
Normal file
1
tests/schema/000016_init.down.sql
Normal file
@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS amoContact;
|
6
tests/schema/000016_init.up.sql
Normal file
6
tests/schema/000016_init.up.sql
Normal file
@ -0,0 +1,6 @@
|
||||
CREATE TABLE IF NOT EXISTS amoContact (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID INT NOT NULL, -- ID "компании" в амо
|
||||
AmoID INT NOT NULL, -- ID контакта в амо
|
||||
Field text NOT NULL DEFAULT '' -- значение чего то email? phone? etc
|
||||
)
|
11
tests/schema/000017_init.down.sql
Normal file
11
tests/schema/000017_init.down.sql
Normal file
@ -0,0 +1,11 @@
|
||||
ALTER table question DROP column session;
|
||||
ALTER TABLE account ADD column email varchar(50) NOT NULL default '';
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'leadtargettype') THEN
|
||||
DROP TYPE LeadTargetType;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DROP TABLE IF EXISTS leadtarget;
|
31
tests/schema/000017_init.up.sql
Normal file
31
tests/schema/000017_init.up.sql
Normal file
@ -0,0 +1,31 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_enum
|
||||
WHERE enumlabel = 'ai' AND enumtypid = 'quiz_status'::regtype
|
||||
) THEN
|
||||
ALTER TYPE quiz_status ADD VALUE 'ai';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
ALTER TABLE question ADD column session varchar(20) NOT NULL DEFAULT '';
|
||||
|
||||
AlTER TABLE account DROP column email;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'leadtargettype') THEN
|
||||
CREATE TYPE LeadTargetType AS ENUM ('mail', 'telegram', 'whatsapp');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS leadtarget(
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID varchar(30) NOT NULL,
|
||||
Type LeadTargetType NOT NULL,
|
||||
QuizID integer NOT NULL DEFAULT 0,
|
||||
Target text NOT NULL,
|
||||
InviteLink text NOT NULL DEFAULT '',
|
||||
Deleted boolean NOT NULL DEFAULT false,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
12
tests/schema/000018_init.down.sql
Normal file
12
tests/schema/000018_init.down.sql
Normal file
@ -0,0 +1,12 @@
|
||||
DROP TABLE IF EXISTS gigachatAudience;
|
||||
|
||||
DROP TABLE IF EXISTS tgAccounts;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'tgAccountStatus') THEN
|
||||
DROP TYPE TgAccountStatus;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DROP INDEX IF EXISTS idx_apiid_apihash;
|
29
tests/schema/000018_init.up.sql
Normal file
29
tests/schema/000018_init.up.sql
Normal file
@ -0,0 +1,29 @@
|
||||
CREATE TABLE IF NOT EXISTS gigachatAudience (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
QuizID BIGINT NOT NULL,
|
||||
Sex BOOLEAN NOT NULL,
|
||||
Age VARCHAR(5) NOT NULL,
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT fk_quiz FOREIGN KEY (QuizID) REFERENCES quiz(ID)
|
||||
);
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'tgAccountStatus') THEN
|
||||
CREATE TYPE TgAccountStatus AS ENUM ('active', 'inactive', 'ban');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tgAccounts (
|
||||
id bigserial primary key ,
|
||||
ApiID integer not null,
|
||||
ApiHash text not null ,
|
||||
PhoneNumber text not null ,
|
||||
Password text not null ,
|
||||
Status TgAccountStatus not null,
|
||||
Deleted bool not null default false,
|
||||
CreatedAt timestamp not null default current_timestamp
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_apiid_apihash ON tgAccounts (ApiID, ApiHash) WHERE Deleted = false;
|
11
tests/schema/000019_init.down.sql
Normal file
11
tests/schema/000019_init.down.sql
Normal file
@ -0,0 +1,11 @@
|
||||
ALTER TABLE account
|
||||
ALTER COLUMN user_id DROP NOT NULL,
|
||||
ALTER COLUMN created_at DROP NOT NULL,
|
||||
ALTER COLUMN deleted DROP NOT NULL;
|
||||
|
||||
ALTER TABLE privileges
|
||||
ALTER COLUMN privilegeID DROP NOT NULL,
|
||||
ALTER COLUMN account_id DROP NOT NULL,
|
||||
ALTER COLUMN privilege_name DROP NOT NULL,
|
||||
ALTER COLUMN amount DROP NOT NULL,
|
||||
ALTER COLUMN created_at DROP NOT NULL;
|
11
tests/schema/000019_init.up.sql
Normal file
11
tests/schema/000019_init.up.sql
Normal file
@ -0,0 +1,11 @@
|
||||
ALTER TABLE account
|
||||
ALTER COLUMN user_id SET NOT NULL,
|
||||
ALTER COLUMN created_at SET NOT NULL,
|
||||
ALTER COLUMN deleted SET NOT NULL;
|
||||
|
||||
ALTER TABLE privileges
|
||||
ALTER COLUMN privilegeID SET NOT NULL,
|
||||
ALTER COLUMN account_id SET NOT NULL,
|
||||
ALTER COLUMN privilege_name SET NOT NULL,
|
||||
ALTER COLUMN amount SET NOT NULL,
|
||||
ALTER COLUMN created_at SET NOT NULL;
|
19
tests/schema/000020_init.down.sql
Normal file
19
tests/schema/000020_init.down.sql
Normal file
@ -0,0 +1,19 @@
|
||||
DROP TABLE IF EXISTS telegram_integration;
|
||||
DROP TABLE IF EXISTS respondent_state;
|
||||
DROP TABLE IF EXISTS telegram_integration_instance;
|
||||
drop table if exists telegram_user_quiz_result;
|
||||
DROP INDEX results_for_quiz;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'bot_status') THEN
|
||||
DROP TYPE bot_status;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'user_result_tg_status') THEN
|
||||
DROP TYPE user_result_tg_status;
|
||||
END IF;
|
||||
END $$;
|
57
tests/schema/000020_init.up.sql
Normal file
57
tests/schema/000020_init.up.sql
Normal file
@ -0,0 +1,57 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'bot_status') THEN
|
||||
CREATE TYPE bot_status AS ENUM ('active','stopped', 'banned');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'user_result_tg_status') THEN
|
||||
CREATE TYPE user_result_tg_status AS ENUM ('in_progress','completed');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS results_for_quiz ON answer(quiz_id, result);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS telegram_integration(
|
||||
id bigserial unique not null primary key,
|
||||
accountid varchar(30) NOT NULL, -- связь с аккаунтом квиза
|
||||
quizID integer NOT NULL , -- айдишник квиза, с которым связываем интеграцию
|
||||
bot_token text NOT NULL, -- токен бота
|
||||
bot_name text NOT NULL DEFAULT '', -- имя бота
|
||||
repeatable boolean DEFAULT false, -- флаг возможности повторить опрос
|
||||
deleted boolean NOT NULL default false, -- флаг удаленного
|
||||
status bot_status NOT NULL DEFAULT 'active',
|
||||
instance_id integer NOT NULL default 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS respondent_state(
|
||||
id bigserial unique not null primary key,
|
||||
telegram_id integer NOT NULL, -- айдишник пользователя в телеграме, скорее всего чат id
|
||||
quizID integer NOT NULL, -- айдишник квиза, который проходится этим респондентом
|
||||
state bigint NOT NULL,
|
||||
lang text NOT NULL default '', -- язык опрашиваемого
|
||||
contact text NOT NULL default '', -- ник пользователя в телеге, если доступен
|
||||
finish boolean not null default false, -- статус, пройден опрос или нет
|
||||
session varchar(20) -- сессия пользователя
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS telegram_integration_instance(
|
||||
id bigserial unique not null primary key,
|
||||
checkout bigint not null , -- время "подтверждения активности". в идеале должно быть актуальным, но отличаться от всех остальных минимум на 10 секунд. т.е. если у нас есть бот с временем в 10:10:10 и бот с временем в 10:10:31, а сейчас 10:10:32, то валидные слоты это 10:10:21 и 10:10:41. но как это сделать я не знаю. как вариант, можно просто взять бот с максимальным временем и сделать ему +10. и наверное это правильныйй вариант
|
||||
limited integer not null, --константа с лимитом ботов
|
||||
amount integer not null -- актуальное количество ботов
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS telegram_user_quiz_result(
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
bot_id BIGINT NOT NULL,
|
||||
quiz_id BIGINT NOT NULL,
|
||||
current_field TEXT,
|
||||
user_answer TEXT DEFAULT '',
|
||||
state user_result_tg_status not null default 'in_progress',
|
||||
session varchar(20) NOT NULL ,
|
||||
question_id bigint NOT NULL, -- id вопроса результата
|
||||
iter integer not null
|
||||
)
|
35
tests/schema/000021_init.down.sql
Normal file
35
tests/schema/000021_init.down.sql
Normal file
@ -0,0 +1,35 @@
|
||||
DROP TABLE IF EXISTS BitrixTokens;
|
||||
DROP TABLE IF EXISTS StepBitrix;
|
||||
|
||||
DROP TABLE IF EXISTS PipelineBitrix;
|
||||
|
||||
DROP TABLE IF EXISTS BitrixAccounts;
|
||||
|
||||
DROP TABLE IF EXISTS BitrixAccountUsers;
|
||||
|
||||
DROP TABLE IF EXISTS BitrixFields;
|
||||
|
||||
DROP TABLE IF EXISTS BitrixRule;
|
||||
|
||||
DROP TABLE IF EXISTS bitrixCRMStatuses;
|
||||
|
||||
DROP TABLE IF EXISTS bitrixContact;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'CustomFieldsType') THEN
|
||||
DROP TYPE CustomFieldsType;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM pg_type WHERE typname = 'FieldsType') THEN
|
||||
DROP TYPE FieldsType;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DROP INDEX IF EXISTS idx_unique_pipeline_bitrix;
|
||||
DROP INDEX IF EXISTS idx_unique_step_bitrix;
|
||||
DROP INDEX IF EXISTS idx_unique_field_bitrix;
|
||||
ALTER TABLE answer DROP COLUMN IF EXISTS version;
|
149
tests/schema/000021_init.up.sql
Normal file
149
tests/schema/000021_init.up.sql
Normal file
@ -0,0 +1,149 @@
|
||||
CREATE TABLE IF NOT EXISTS BitrixTokens (
|
||||
AccountID VARCHAR(30) PRIMARY KEY, -- связь с users AccountID неявная посредством join
|
||||
RefreshToken TEXT NOT NULL ,
|
||||
AccessToken TEXT NOT NULL ,
|
||||
AuthCode TEXT NOT NULL , -- код авторизации который получаем при вебхук
|
||||
Expiration TIMESTAMP NOT NULL, -- время истечения токенов
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'FieldsType') THEN
|
||||
CREATE TYPE FieldsType AS ENUM (
|
||||
'CRM_LEAD',
|
||||
'CRM_COMPANY',
|
||||
'CRM_CONTACT',
|
||||
'CRM_DEAL',
|
||||
'CRM_INVOICE',
|
||||
'CRM_SMART_INVOICE',
|
||||
'CRM_QUOTE',
|
||||
'CRM_REQUISITE'
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'CustomFieldsType') THEN
|
||||
CREATE TYPE CustomFieldsType AS ENUM (
|
||||
'string',
|
||||
'integer',
|
||||
'double',
|
||||
'boolean',
|
||||
'datetime',
|
||||
'enumeration',
|
||||
'iblock_section',
|
||||
'iblock_element',
|
||||
'employee',
|
||||
'crm_status',
|
||||
'crm',
|
||||
'address',
|
||||
'money',
|
||||
'url',
|
||||
'file',
|
||||
'crm_pena_tag'
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS BitrixFields (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
BitrixID VARCHAR(255) NOT NULL, -- Айдишник field в битриксе
|
||||
AccountID VARCHAR(255) NOT NULL,-- ID портала битрикса
|
||||
EntityID FieldsType NOT NULL,-- тип поля
|
||||
FieldName VARCHAR(255) NOT NULL,-- имя поля
|
||||
EditFromLabel VARCHAR(255) NOT NULL,-- заголовок вопроса
|
||||
FieldType CustomFieldsType NOT NULL, -- тип поля
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS BitrixAccountUsers (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(255) NOT NULL, -- ID портала битрикса
|
||||
BitrixIDUserID VARCHAR(255) NOT NULL, -- ID пользователя в битриксе
|
||||
Name VARCHAR(255) NOT NULL default '', -- Имя
|
||||
LastName VARCHAR(255) NOT NULL default '',-- Фамилия
|
||||
SecondName VARCHAR(255) NOT NULL default '', -- Отчество
|
||||
Title VARCHAR(255) NOT NULL default '',
|
||||
Email VARCHAR(255) NOT NULL default '', -- Почта
|
||||
UFDepartment INT[], -- Массив департаментов
|
||||
WorkPosition VARCHAR(255) NOT NULL default '', -- Должность
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS BitrixAccounts (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(30) NOT NULL, -- ID аккаунта у нас
|
||||
BitrixID VARCHAR(255) NOT NULL, -- ID портала битрикса
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
Subdomain VARCHAR(50) NOT NULL -- поддомен
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS PipelineBitrix (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
BitrixID INT NOT NULL, -- Айдишник воронки в битриксе
|
||||
AccountID VARCHAR(255) NOT NULL, -- ID портала битрикса
|
||||
Name VARCHAR(255) NOT NULL, -- Название воронки
|
||||
EntityTypeId INT NOT NULL, -- Тип по номерам
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT validEntityType CHECK (EntityTypeId IN (1, 2, 3, 4, 5, 7, 8, 31))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS StepBitrix (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(255) NOT NULL, -- ID портала битрикса
|
||||
BitrixID VARCHAR(255) NOT NULL, -- Айдишник состояния в битриксе
|
||||
EntityID VARCHAR(255) NOT NULL, -- Тип сущности
|
||||
StatusID VARCHAR(255) NOT NULL, -- Текстовый формат ID статуса
|
||||
Name VARCHAR(255) NOT NULL default '', -- Название
|
||||
NameInit VARCHAR(255) NOT NULL default '', -- возможно это изначальное название
|
||||
Color VARCHAR(50) NOT NULL default '', -- Цвет
|
||||
PipelineID INT NOT NULL, -- ID воронки
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS BitrixRule (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(255) NOT NULL, -- ID портала битрикса
|
||||
QuizID INT NOT NULL, -- ID квиза на которое вешается правило
|
||||
PerformerID VARCHAR(255) NOT NULL, -- ID пользователя в битриксе который ответсвенный
|
||||
PipelineID INT NOT NULL, -- ID воронки
|
||||
TypeID VARCHAR(255) NOT NULL, -- шаг сделки только с "ENTITY_ID":"DEAL_TYPE","STATUS_ID":"SALE"
|
||||
StageID VARCHAR(255) NOT NULL, -- стадия сделки, шаг "ENTITY_ID":"DEAL_STAGE","STATUS_ID":"NEW"
|
||||
SourceID VARCHAR(255) NOT NULL, -- тип источника, шаг "ENTITY_ID":"SOURCE","STATUS_ID":"CALL"
|
||||
StatusID VARCHAR(255) NOT NULL, -- тип источника, шаг "ENTITY_ID":"STATUS","STATUS_ID":"IN_PROCESS"
|
||||
FieldsRule JSONB NOT NULL DEFAULT '{}', -- вложенная структура
|
||||
TagsToAdd JSONB NOT NULL DEFAULT '{}', -- структура тегов которые надо дбавлять
|
||||
Deleted BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
LeadFlag BOOLEAN NOT NULL DEFAULT FALSE -- если true то делаем лид а не сделку
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bitrixCRMStatuses (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(255) NOT NULL, -- ID портала битрикса
|
||||
DealID INT NOT NULL, -- id сделки или лида в которую добавлялось
|
||||
AnswerID BIGINT NOT NULL REFERENCES answer(id), -- id true result который вызвал действие
|
||||
Status TEXT NOT NULL DEFAULT '', -- запись о ошибке, либо успехе
|
||||
CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS bitrixContact (
|
||||
ID BIGSERIAL UNIQUE NOT NULL PRIMARY KEY,
|
||||
AccountID VARCHAR(255) NOT NULL, -- ID "компании" в амо
|
||||
BitrixID INT NOT NULL, -- ID контакта в амо
|
||||
Field text NOT NULL DEFAULT '' -- значение чего то email? phone? etc
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_unique_pipeline_bitrix ON PipelineBitrix (BitrixID, AccountID) WHERE Deleted = false;
|
||||
CREATE UNIQUE INDEX idx_unique_step_bitrix ON StepBitrix (BitrixID, AccountID) WHERE Deleted = false;
|
||||
CREATE UNIQUE INDEX idx_unique_field_bitrix ON BitrixFields (BitrixID, AccountID, EntityID);
|
||||
ALTER TABLE answer ADD COLUMN version integer NOT NULL default 0;
|
1
tests/schema/000022_init.down.sql
Normal file
1
tests/schema/000022_init.down.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE question DROP COLUMN IF EXISTS auditory;
|
1
tests/schema/000022_init.up.sql
Normal file
1
tests/schema/000022_init.up.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE question ADD COLUMN auditory BIGINT NOT NULL DEFAULT 0;
|
0
tests/schema/000023_init.down.sql
Normal file
0
tests/schema/000023_init.down.sql
Normal file
14
tests/schema/000023_init.up.sql
Normal file
14
tests/schema/000023_init.up.sql
Normal file
@ -0,0 +1,14 @@
|
||||
BEGIN;
|
||||
ALTER TABLE gigachatAudience RENAME COLUMN Sex TO Sex_old;
|
||||
ALTER TABLE gigachatAudience ADD COLUMN Sex INTEGER;
|
||||
UPDATE gigachatAudience
|
||||
SET Sex = CASE
|
||||
WHEN Sex_old = FALSE THEN 0
|
||||
WHEN Sex_old = TRUE THEN 1
|
||||
ELSE 2
|
||||
END;
|
||||
ALTER TABLE gigachatAudience DROP COLUMN Sex_old;
|
||||
ALTER TABLE gigachatAudience ALTER COLUMN Sex SET NOT NULL;
|
||||
ALTER TABLE gigachatAudience
|
||||
ADD CONSTRAINT check_sex_valid_values CHECK (Sex IN (0, 1, 2));
|
||||
COMMIT;
|
1
tests/schema/000024_init.down.sql
Normal file
1
tests/schema/000024_init.down.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE quiz DROP COLUMN IF EXISTS gigachat;
|
1
tests/schema/000024_init.up.sql
Normal file
1
tests/schema/000024_init.up.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE quiz ADD COLUMN gigachat boolean NOT NULL DEFAULT false;
|
1
tests/schema/000025_init.down.sql
Normal file
1
tests/schema/000025_init.down.sql
Normal file
@ -0,0 +1 @@
|
||||
drop table if exists quiz_utm;
|
7
tests/schema/000025_init.up.sql
Normal file
7
tests/schema/000025_init.up.sql
Normal file
@ -0,0 +1,7 @@
|
||||
CREATE TABLE IF NOT EXISTS quiz_utm (
|
||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
||||
quizID bigint not null,
|
||||
utm text not null default '',
|
||||
deleted boolean not null default false,
|
||||
created_at TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
2
tests/schema/000026_init.down.sql
Normal file
2
tests/schema/000026_init.down.sql
Normal file
@ -0,0 +1,2 @@
|
||||
DROP INDEX IF EXISTS idx_quiz_privilege_unique;
|
||||
drop table if exists quiz_privilege_usage;
|
10
tests/schema/000026_init.up.sql
Normal file
10
tests/schema/000026_init.up.sql
Normal file
@ -0,0 +1,10 @@
|
||||
CREATE TABLE quiz_privilege_usage (
|
||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
||||
quiz_id BIGINT NOT NULL REFERENCES quiz(id) ON DELETE CASCADE,
|
||||
privilege_id VARCHAR(50) NOT NULL,
|
||||
used_count INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP not null DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_quiz_privilege_unique ON quiz_privilege_usage (quiz_id, privilege_id);
|
Loading…
Reference in New Issue
Block a user