From 5577247a99e0359d43346bb6f539d154cc31d907 Mon Sep 17 00:00:00 2001 From: thefosk Date: Thu, 19 Mar 2015 20:37:29 -0700 Subject: [PATCH 1/4] Introducing "represents" to fix the schema types problem --- spec/integration/api/api_spec.lua | 5 +++++ src/constants.lua | 4 ++++ src/dao/cassandra/accounts.lua | 7 ++++--- src/dao/cassandra/apis.lua | 11 ++++++----- src/dao/cassandra/applications.lua | 11 ++++++----- src/dao/cassandra/base_dao.lua | 4 ++-- src/dao/cassandra/plugins.lua | 10 +++++----- src/plugins/ratelimiting/schema.lua | 2 +- src/plugins/tcplog/schema.lua | 8 ++++---- src/plugins/udplog/schema.lua | 6 +++--- 10 files changed, 40 insertions(+), 28 deletions(-) diff --git a/spec/integration/api/api_spec.lua b/spec/integration/api/api_spec.lua index 3dbef4359e6..b01839024fe 100644 --- a/spec/integration/api/api_spec.lua +++ b/spec/integration/api/api_spec.lua @@ -113,6 +113,11 @@ describe("Web API #web", function() local response, status, headers = http_client.post(kWebURL.."/"..v.collection.."/", v.entity) local body = cjson.decode(response) + if status == 400 then + print(response) + local inspect= require "inspect" + print(inspect(v.entity)) + end assert.are.equal(201, status) assert.truthy(body) diff --git a/src/constants.lua b/src/constants.lua index fece0411f95..a3dfefe8bb8 100644 --- a/src/constants.lua +++ b/src/constants.lua @@ -8,6 +8,10 @@ return { UNIQUE = "unique", FOREIGN = "foreign" }, + DATABASE_TYPES = { + ID = "id", + TIMESTAMP = "timestamp" + }, HEADERS = { SERVER = "Server", PROXY_TIME = "X-Kong-Proxy-Time", diff --git a/src/dao/cassandra/accounts.lua b/src/dao/cassandra/accounts.lua index ecae9ca3bfb..b7b1ace7aa9 100644 --- a/src/dao/cassandra/accounts.lua +++ b/src/dao/cassandra/accounts.lua @@ -1,9 +1,10 @@ local BaseDao = require "kong.dao.cassandra.base_dao" +local constants = require "kong.constants" local SCHEMA = { - id = { type = "id" }, - provider_id = { unique = true, queryable = true }, - created_at = { type = "timestamp" } + id = { type = "string", represents = constants.DATABASE_TYPES.ID }, + provider_id = { type = "string", unique = true, queryable = true }, + created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } } local Accounts = BaseDao:extend() diff --git a/src/dao/cassandra/apis.lua b/src/dao/cassandra/apis.lua index 4be2c9999d6..c992c75f435 100644 --- a/src/dao/cassandra/apis.lua +++ b/src/dao/cassandra/apis.lua @@ -1,12 +1,13 @@ local BaseDao = require "kong.dao.cassandra.base_dao" +local constants = require "kong.constants" local SCHEMA = { - id = { type = "id" }, - name = { required = true, unique = true, queryable = true }, - public_dns = { required = true, unique = true, queryable = true, + id = { type = "string", represents = constants.DATABASE_TYPES.ID }, + name = { type = "string", required = true, unique = true, queryable = true }, + public_dns = { type = "string", required = true, unique = true, queryable = true, regex = "(([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])" }, - target_url = { required = true }, - created_at = { type = "timestamp" } + target_url = { type = "string", required = true }, + created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } } local Apis = BaseDao:extend() diff --git a/src/dao/cassandra/applications.lua b/src/dao/cassandra/applications.lua index 85abfb26a15..653e0a35e67 100644 --- a/src/dao/cassandra/applications.lua +++ b/src/dao/cassandra/applications.lua @@ -1,11 +1,12 @@ local BaseDao = require "kong.dao.cassandra.base_dao" +local constants = require "kong.constants" local SCHEMA = { - id = { type = "id" }, - account_id = { type = "id", required = true, foreign = true, queryable = true }, - public_key = { required = true, unique = true, queryable = true }, - secret_key = {}, - created_at = { type = "timestamp" } + id = { type = "string", represents = constants.DATABASE_TYPES.ID }, + account_id = { type = "string", represents = constants.DATABASE_TYPES.ID, required = true, foreign = true, queryable = true }, + public_key = { type = "string", required = true, unique = true, queryable = true }, + secret_key = { type = "string" }, + created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } } local Applications = BaseDao:extend() diff --git a/src/dao/cassandra/base_dao.lua b/src/dao/cassandra/base_dao.lua index dcb2a346f28..7d7c3bab604 100644 --- a/src/dao/cassandra/base_dao.lua +++ b/src/dao/cassandra/base_dao.lua @@ -47,13 +47,13 @@ local function encode_cassandra_values(schema, t, parameters) local schema_field = schema[column] local value = t[column] - if schema_field.type == "id" and value then + if schema_field.represents == constants.DATABASE_TYPES.ID and value then if is_valid_uuid(value) then value = cassandra.uuid(value) else errors = utils.add_error(errors, column, value.." is an invalid uuid") end - elseif schema_field.type == "timestamp" and value then + elseif schema_field.represents == constants.DATABASE_TYPES.TIMESTAMP and value then value = cassandra.timestamp(value) elseif value == nil then value = cassandra.null diff --git a/src/dao/cassandra/plugins.lua b/src/dao/cassandra/plugins.lua index 0a7597fd499..f6b5a30e988 100644 --- a/src/dao/cassandra/plugins.lua +++ b/src/dao/cassandra/plugins.lua @@ -12,13 +12,13 @@ local function load_value_schema(plugin_t) end local SCHEMA = { - id = { type = "id" }, - api_id = { type = "id", required = true, foreign = true, queryable = true }, - application_id = { type = "id", foreign = true, queryable = true, default = constants.DATABASE_NULL_ID }, - name = { required = true, queryable = true, immutable = true }, + id = { type = "string", represents = constants.DATABASE_TYPES.ID }, + api_id = { type = "string", represents = constants.DATABASE_TYPES.ID, required = true, foreign = true, queryable = true }, + application_id = { type = "string", represents = constants.DATABASE_TYPES.ID, foreign = true, queryable = true, default = constants.DATABASE_NULL_ID }, + name = { type = "string", required = true, queryable = true, immutable = true }, value = { type = "table", required = true, schema = load_value_schema }, enabled = { type = "boolean", default = true }, - created_at = { type = "timestamp" } + created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } } local Plugins = BaseDao:extend() diff --git a/src/plugins/ratelimiting/schema.lua b/src/plugins/ratelimiting/schema.lua index bf2db7ae84d..337d60619f1 100644 --- a/src/plugins/ratelimiting/schema.lua +++ b/src/plugins/ratelimiting/schema.lua @@ -2,5 +2,5 @@ local constants = require "kong.constants" return { limit = { required = true, type = "number" }, - period = { required = true, enum = constants.RATELIMIT.PERIODS } + period = { required = true, type = "string", enum = constants.RATELIMIT.PERIODS } } diff --git a/src/plugins/tcplog/schema.lua b/src/plugins/tcplog/schema.lua index 4482b913701..5875720a41f 100644 --- a/src/plugins/tcplog/schema.lua +++ b/src/plugins/tcplog/schema.lua @@ -1,6 +1,6 @@ return { - host = { required = true }, - port = { required = true }, - timeout = { required = false, default = 10000 }, - keepalive = { required = false, default = 60000 } + host = { required = true, type = "string" }, + port = { required = true, type = "number" }, + timeout = { required = false, default = 10000, type = "number" }, + keepalive = { required = false, default = 60000, type = "number" } } diff --git a/src/plugins/udplog/schema.lua b/src/plugins/udplog/schema.lua index fa8c204afa5..9e8c4a9ed3c 100644 --- a/src/plugins/udplog/schema.lua +++ b/src/plugins/udplog/schema.lua @@ -1,5 +1,5 @@ return { - host = { required = true }, - port = { required = true }, - timeout = { required = false, default = 10000 } + host = { required = true, type = "string" }, + port = { required = true, type = "number" }, + timeout = { required = false, default = 10000, type = "number" } } From 20deb9911a7193bf765d36c2366638bb0334e63f Mon Sep 17 00:00:00 2001 From: thefosk Date: Thu, 19 Mar 2015 20:40:35 -0700 Subject: [PATCH 2/4] removing debug print --- spec/integration/api/api_spec.lua | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/integration/api/api_spec.lua b/spec/integration/api/api_spec.lua index b01839024fe..3dbef4359e6 100644 --- a/spec/integration/api/api_spec.lua +++ b/spec/integration/api/api_spec.lua @@ -113,11 +113,6 @@ describe("Web API #web", function() local response, status, headers = http_client.post(kWebURL.."/"..v.collection.."/", v.entity) local body = cjson.decode(response) - if status == 400 then - print(response) - local inspect= require "inspect" - print(inspect(v.entity)) - end assert.are.equal(201, status) assert.truthy(body) From 0a01a2c6738abd73b9aef6d4748f31c2bce8859e Mon Sep 17 00:00:00 2001 From: thefosk Date: Thu, 19 Mar 2015 20:52:44 -0700 Subject: [PATCH 3/4] making database types actual data types --- src/dao/cassandra/accounts.lua | 4 ++-- src/dao/cassandra/apis.lua | 4 ++-- src/dao/cassandra/applications.lua | 6 +++--- src/dao/cassandra/base_dao.lua | 4 ++-- src/dao/cassandra/plugins.lua | 8 ++++---- src/dao/schemas.lua | 13 ++++++++++++- 6 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/dao/cassandra/accounts.lua b/src/dao/cassandra/accounts.lua index b7b1ace7aa9..c4e3de678cf 100644 --- a/src/dao/cassandra/accounts.lua +++ b/src/dao/cassandra/accounts.lua @@ -2,9 +2,9 @@ local BaseDao = require "kong.dao.cassandra.base_dao" local constants = require "kong.constants" local SCHEMA = { - id = { type = "string", represents = constants.DATABASE_TYPES.ID }, + id = { type = constants.DATABASE_TYPES.ID }, provider_id = { type = "string", unique = true, queryable = true }, - created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } + created_at = { type = constants.DATABASE_TYPES.TIMESTAMP } } local Accounts = BaseDao:extend() diff --git a/src/dao/cassandra/apis.lua b/src/dao/cassandra/apis.lua index c992c75f435..573cfa46198 100644 --- a/src/dao/cassandra/apis.lua +++ b/src/dao/cassandra/apis.lua @@ -2,12 +2,12 @@ local BaseDao = require "kong.dao.cassandra.base_dao" local constants = require "kong.constants" local SCHEMA = { - id = { type = "string", represents = constants.DATABASE_TYPES.ID }, + id = { type = constants.DATABASE_TYPES.ID }, name = { type = "string", required = true, unique = true, queryable = true }, public_dns = { type = "string", required = true, unique = true, queryable = true, regex = "(([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])" }, target_url = { type = "string", required = true }, - created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } + created_at = { type = constants.DATABASE_TYPES.TIMESTAMP } } local Apis = BaseDao:extend() diff --git a/src/dao/cassandra/applications.lua b/src/dao/cassandra/applications.lua index 653e0a35e67..fc439e53174 100644 --- a/src/dao/cassandra/applications.lua +++ b/src/dao/cassandra/applications.lua @@ -2,11 +2,11 @@ local BaseDao = require "kong.dao.cassandra.base_dao" local constants = require "kong.constants" local SCHEMA = { - id = { type = "string", represents = constants.DATABASE_TYPES.ID }, - account_id = { type = "string", represents = constants.DATABASE_TYPES.ID, required = true, foreign = true, queryable = true }, + id = { type = constants.DATABASE_TYPES.ID }, + account_id = { type = constants.DATABASE_TYPES.ID, required = true, foreign = true, queryable = true }, public_key = { type = "string", required = true, unique = true, queryable = true }, secret_key = { type = "string" }, - created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } + created_at = { type = constants.DATABASE_TYPES.TIMESTAMP } } local Applications = BaseDao:extend() diff --git a/src/dao/cassandra/base_dao.lua b/src/dao/cassandra/base_dao.lua index 7d7c3bab604..0f4e9a217a9 100644 --- a/src/dao/cassandra/base_dao.lua +++ b/src/dao/cassandra/base_dao.lua @@ -47,13 +47,13 @@ local function encode_cassandra_values(schema, t, parameters) local schema_field = schema[column] local value = t[column] - if schema_field.represents == constants.DATABASE_TYPES.ID and value then + if schema_field.type == constants.DATABASE_TYPES.ID and value then if is_valid_uuid(value) then value = cassandra.uuid(value) else errors = utils.add_error(errors, column, value.." is an invalid uuid") end - elseif schema_field.represents == constants.DATABASE_TYPES.TIMESTAMP and value then + elseif schema_field.type == constants.DATABASE_TYPES.TIMESTAMP and value then value = cassandra.timestamp(value) elseif value == nil then value = cassandra.null diff --git a/src/dao/cassandra/plugins.lua b/src/dao/cassandra/plugins.lua index f6b5a30e988..e490cdb6395 100644 --- a/src/dao/cassandra/plugins.lua +++ b/src/dao/cassandra/plugins.lua @@ -12,13 +12,13 @@ local function load_value_schema(plugin_t) end local SCHEMA = { - id = { type = "string", represents = constants.DATABASE_TYPES.ID }, - api_id = { type = "string", represents = constants.DATABASE_TYPES.ID, required = true, foreign = true, queryable = true }, - application_id = { type = "string", represents = constants.DATABASE_TYPES.ID, foreign = true, queryable = true, default = constants.DATABASE_NULL_ID }, + id = { type = constants.DATABASE_TYPES.ID }, + api_id = { type = constants.DATABASE_TYPES.ID, required = true, foreign = true, queryable = true }, + application_id = { type = constants.DATABASE_TYPES.ID, foreign = true, queryable = true, default = constants.DATABASE_NULL_ID }, name = { type = "string", required = true, queryable = true, immutable = true }, value = { type = "table", required = true, schema = load_value_schema }, enabled = { type = "boolean", default = true }, - created_at = { type = "number", represents = constants.DATABASE_TYPES.TIMESTAMP } + created_at = { type = constants.DATABASE_TYPES.TIMESTAMP } } local Plugins = BaseDao:extend() diff --git a/src/dao/schemas.lua b/src/dao/schemas.lua index 7e324e0c0eb..aec708beb1f 100644 --- a/src/dao/schemas.lua +++ b/src/dao/schemas.lua @@ -1,5 +1,6 @@ local rex = require "rex_pcre" -- Why? Lua has built in pattern which should do the job too local utils = require "kong.tools.utils" +local constants = require "kong.constants" local LUA_TYPES = { boolean = true, @@ -8,6 +9,16 @@ local LUA_TYPES = { table = true } +local function get_type(type_val) + if type_val == constants.DATABASE_TYPES.ID then + return "string" + elseif type_val == constants.DATABASE_TYPES.ID then + return "number" + else + return type_val + end +end + -- -- Schemas -- @@ -38,7 +49,7 @@ function _M.validate(t, schema, is_update) errors = utils.add_error(errors, column, column.." is required") -- Check type if valid - elseif v.type ~= nil and t[column] ~= nil and type(t[column]) ~= v.type and LUA_TYPES[v.type] then + elseif v.type ~= nil and t[column] ~= nil and type(t[column]) ~= get_type(v.type) and LUA_TYPES[v.type] then errors = utils.add_error(errors, column, column.." is not a "..v.type) -- Check type if value is allowed in the enum From 11e97acced5a16d00ff254b1b5694efb1ffa8b4b Mon Sep 17 00:00:00 2001 From: thefosk Date: Thu, 19 Mar 2015 21:02:41 -0700 Subject: [PATCH 4/4] Spec and refactoring --- spec/unit/validations_spec.lua | 10 ++++++++++ src/dao/schemas.lua | 25 +++++++++++++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/spec/unit/validations_spec.lua b/spec/unit/validations_spec.lua index 3bd16f9b9a0..614c0d92cb3 100644 --- a/spec/unit/validations_spec.lua +++ b/spec/unit/validations_spec.lua @@ -1,8 +1,18 @@ local schemas = require "kong.dao.schemas" +local constants = require "kong.constants" local validate = schemas.validate describe("Validation #schema", function() + it("should return the right alias", function() + assert.are.same("number", schemas.get_type("number")) + assert.are.same("string", schemas.get_type("string")) + assert.are.same("boolean", schemas.get_type("boolean")) + assert.are.same("table", schemas.get_type("table")) + assert.are.same("string", schemas.get_type(constants.DATABASE_TYPES.ID)) + assert.are.same("number", schemas.get_type(constants.DATABASE_TYPES.TIMESTAMP)) + end) + describe("#validate()", function() -- Ok kids, today we're gonna test a custom validation schema, -- grab a pair of glasses, this stuff can literally explode. diff --git a/src/dao/schemas.lua b/src/dao/schemas.lua index aec708beb1f..9bd9f0cb8ef 100644 --- a/src/dao/schemas.lua +++ b/src/dao/schemas.lua @@ -9,21 +9,26 @@ local LUA_TYPES = { table = true } -local function get_type(type_val) - if type_val == constants.DATABASE_TYPES.ID then - return "string" - elseif type_val == constants.DATABASE_TYPES.ID then - return "number" - else - return type_val - end -end +local LUA_TYPE_ALIASES = { + [constants.DATABASE_TYPES.ID] = "string", + [constants.DATABASE_TYPES.TIMESTAMP] = "number" +} -- -- Schemas -- local _M = {} + +-- Returns the proper Lua type from a schema type, handling aliases +-- @param {string} type_val The type of the schema property +-- @return {string} A valid Lua type +function _M.get_type(type_val) + local alias = LUA_TYPE_ALIASES[type_val] + return alias and alias or type_val +end + + -- Validate a table against a given schema -- @param {table} t Table to validate -- @param {table} schema Schema against which to validate the table @@ -49,7 +54,7 @@ function _M.validate(t, schema, is_update) errors = utils.add_error(errors, column, column.." is required") -- Check type if valid - elseif v.type ~= nil and t[column] ~= nil and type(t[column]) ~= get_type(v.type) and LUA_TYPES[v.type] then + elseif v.type ~= nil and t[column] ~= nil and type(t[column]) ~= _M.get_type(v.type) and LUA_TYPES[v.type] then errors = utils.add_error(errors, column, column.." is not a "..v.type) -- Check type if value is allowed in the enum