Restriction when using boss_db? - erlang

I am trying to use boss_db for accessing pgsql. The table should have the column name, id, it should be primary key
The Id type is only be uuid or serial. Is it right?
I want that id is varchar(20), the value of id is decided by the program, not auto decided by DBMS. Is it possible?
create table operators(
id serial primary key, /*I want id is varchar(20), is it possible*/
tag_id varchar(20),
name text,
barcode varchar(20),
tel varchar(12),
mobile varchar(20),
email text,
ldap_user_id varchar(20),
operator_barcode varchar(20)
);
A = operator:new(id,"0102030405060708",
"operator_01","B001","12345678",
"13812345678",
"p001#gmail.com",
"ldap001",
"PB001"),
The follwing codes is from boss_sql_lib.erl file:
infer_type_from_id(Id) when is_list(Id) ->
[Type, TableId] = re:split(Id, "-", [{return, list}, {parts, 2}]),
TypeAtom = list_to_atom(Type),
IdColumn = proplists:get_value(id, boss_record_lib:database_columns(TypeAtom)),
IdValue = case keytype(Type) of
uuid -> TableId;
serial -> list_to_integer(TableId)
end,
{TypeAtom, boss_record_lib:database_table(TypeAtom), IdColumn, IdValue}.

Assign an ID when you create the BossRecord by using your own ID rather than the atom id:
> AutoId = operator:new(id,
"0102030405060708",
"operator_01","B001","12345678",
"13812345678",
"p001#gmail.com",
"ldap001",
"PB001"),
> ManualID = operator:new("operator-01",
"0102030405060708",
"operator_01","B001","12345678",
"13812345678",
"p001#gmail.com",
"ldap001",
"PB001"),
> AutoID:save(), % will just work
> ManualId:save(). % good luck
Record IDs are typically created by the framework. They must be globally unique. I recommend allowing the framework to assign its own IDs, rather than creating them manually as you will probably encounter bugs. However, there is nothing stopping you doing whatever you want.

Related

Is it possible to alter a table to include reference to an upstream table in datajoint for python?

We want to alter a table to include a non-primary key reference to a new table. The old definition is:
#schema
class SpikeSortingParameters(dj.Manual):
definition = """
# Table for holding parameters for each spike sorting run
-> SortGroup
-> SpikeSorterParameters
-> SortInterval
---
-> SpikeSortingMetrics
-> IntervalList
import_path = '': varchar(200) # optional path to previous curated sorting output
"""
We'd like to add
-> SpikeSortingArtifactParameters
as a non primary key, and before we spent time trying to get this to work, we wanted to know if it was possible given that we don't know of a way to assign a default value here.
thanks in advance...
Loren
Unfortunately, foreign key updates are not currently supported with table.alter(). There is a workaround that can be used but there are a few steps and those should be taken carefully. It would be best to file this as a feature request in the issue tracker.
Using Alter
For instance, consider the following:
If you have 2 tables defined as follows:
import datajoint as dj
schema = dj.Schema('rguzman_alter_example')
#schema
class Student(dj.Lookup):
definition = """
student_first_name: varchar(30)
student_last_name: varchar(30)
---
student_location: varchar(30)
"""
contents = [('Joe', 'Schmoe', 'Los Angeles, CA'), ('Suzie', 'Queue', 'Miami, FL')]
#schema
class Assignment (dj.Lookup):
definition = """
assignment_id: int
---
assignment_due_date: date
#-> [nullable] Student # Standard way to define a foreign key on secondary attributes with NULL as default
"""
contents = [dict(assignment_id=100, assignment_due_date='2021-04-21')]
Now suppose that you'd like to have a foreign key on secondary attributes with NULL as the default. You can pass options to foreign keys in secondary attributes (see the comment above where we allow it to default to NULL). Initializing a table from scratch in this way works just fine. For the case where we want to add a foreign key on a secondary attribute after a table has been initialized with existing data, Assignment.alter() would be the best means to achieve this so long as we establish a default value to fill existing records with. Let's see what happens when we uncomment the foreign key on secondary attributes, redefine the Assignment table class, and try to alter.
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-23-09997168281c> in <module>
----> 1 Assignment.alter()
~/.local/lib/python3.7/site-packages/datajoint/table.py in alter(self, prompt, context)
84 del frame
85 old_definition = self.describe(context=context, printout=False)
---> 86 sql, external_stores = alter(self.definition, old_definition, context)
87 if not sql:
88 if prompt:
~/.local/lib/python3.7/site-packages/datajoint/declare.py in alter(definition, old_definition, context)
367 raise NotImplementedError('table.alter cannot alter the primary key (yet).')
368 if foreign_key_sql != foreign_key_sql_:
--> 369 raise NotImplementedError('table.alter cannot alter foreign keys (yet).')
370 if index_sql != index_sql_:
371 raise NotImplementedError('table.alter cannot alter indexes (yet)')
NotImplementedError: table.alter cannot alter foreign keys (yet).
Oh, there's an exception... So it turns out that it is not implemented yet for this use case. However, there is a manual workaround that can be leveraged so let me detail those steps until there is support.
Workaround
Instead of defining the foreign key on secondary attributes as above, define it in this way:
#schema
class Assignment (dj.Lookup):
definition = f"""
assignment_id: int
---
assignment_due_date: date
{newline.join(['' + a.name + '=null: ' + a.type for a in Student.heading.attributes.values() if a.in_key])}
"""
contents = [dict(assignment_id=100, assignment_due_date='2021-04-21')]
This 'copies' over the primary attributes of the parent table into the secondary attributes of your child table.
Perform alter as normal: Assignment.alter()
Manually add the foreign key using a SQL query directly. Like this:
q = """
ALTER TABLE {table}
ADD FOREIGN KEY ({fk})
REFERENCES {ref} ({pk})
ON UPDATE CASCADE
ON DELETE RESTRICT
""".format(table=Assignment.full_table_name,
fk=','.join([f'`{k}`' for k in Student.primary_key]),
ref=f'`{Student.table_name}`',
pk=','.join([f'`{k}`' for k in Student.primary_key]))
dj.conn().query(q)
Make sure to remove the portion that was added in step 1 and replace it with the proper specification i.e. -> [nullable] Student
Restart your kernel
To verify it has been properly set, check Assignment.describe(). If everything worked properly, the result should be:
assignment_id : int
---
assignment_due_date : date
-> [nullable] Student
Additionally, any pre-existing records should now be prefilled with NULL.

Hyperlink base on another column

I'm new to BigQuery. Is there a way to Hyperlink base on another column's info?
In other words, how to hyperlink a specific column based on a specific ID (in another column) in the same table? E.g. How to create a hyperlink column "Program" by referencing the "SF_Record_ID" ID
SELECT CASE WHEN PMD_PRODUCT_NAME LIKE '%MANO%' THEN 'Brazil MAO'
WHEN PC.COUNTRY ='BR' THEN 'Brazil'
ELSE GEO.COUNTRY_DESCRIPTION
END AS Country
, IFNULL(PMD.PMD_FRANCHISE,"Unspecified") as Franchise
, PC.PMD_PROGRAM_NAME AS Progam
, PC.PMD_PRODUCT_NAME AS Product
, PC.KEY_CUSTOMER AS Key_Customer
, PC.PRODUCT_STATUS AS Product_Status
, PC.SF_RECORD_ID AS SF_Record_ID
, PC.PRODUCT_COST AS Cost
SF_Record_ID is the unique ID
Link: "https://XXXXXXXXXXXXXX/SF_Record_ID/view"
You can use dynamic SQL to achieve this:
DECLARE HLINK_PREFIX STRING;
DECLARE HLINK_POSTFIX STRING;
SET HLINK_PREFIX = "https://XXXXXXXXXXXXXX/";
SET HLINK_POSTFIX = "/view";
EXECUTE IMMEDIATE FORMAT("""SELECT concat(concat('%t', SF_Record_ID),'%t') FROM table""",HLINK_PREFIX,HLINK_POSTFIX);

Doctrine Assocation Mapping Join Not Executing In ZF3

I am creating my first Association Mapping for a Join. This is also the first time I've used a Foreign Key in pgSQL.
I am working with ZF3. The error I am receiving is:
An exception occurred while executing 'SELECT p0_.reference AS reference_0, p0_.meta_keyword_reference AS meta_keyword_reference_1, p0_.add_date AS add_date_2, p0_.add_membership_reference AS add_membership_reference_3, p0_.remove_date AS remove_date_4, p0_.remove_membership_reference AS remove_membership_reference_5 FROM page_about_meta_keyword_link p0_ INNER JOIN meta_keyword m1_':
SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at end of input LINE 1: ...page_about_meta_keyword_link p0_ INNER JOIN meta_keyword m1_
The query I am trying to create is
SELECT MetaKeywords.Keyword FROM PageAboutMetaKeywordLink INNER JOIN MetaKeywords ON PageAboutMetaKeywordLink.MetaKeywordReference = MetaKeywords.Reference WHERE PageAboutMetaKeywordLink.RemoveDate IS NULL ORDER BY MetaKeywords.Keyword ASC
From my database experience I expect it is creating the error due to the missing
ON p0_.meta_keyword_reference = m1_reference
I don't understand how to communicate the Join. Based on the documentation I had expected this was automatic. Maybe I misunderstood.
The tables I am trying to Join are page_about_meta_keyword_link.meta_keyword_reference ON meta_keyword.reference . This is the first time I've created a foreign key in pgSQL.
This is the table structure for page_about_meta_keyword_link
CREATE TABLE public.page_about_meta_keyword_link
(
reference bigint NOT NULL DEFAULT nextval('page_about_meta_keyword_link_reference_seq'::regclass),
meta_keyword_reference bigint,
add_date timestamp with time zone DEFAULT now(), -- UTC
add_membership_reference bigint,
remove_date timestamp with time zone, -- UTC
remove_membership_reference bigint,
CONSTRAINT page_about_meta_keyword_link_pkey PRIMARY KEY (reference),
CONSTRAINT page_about_meta_keyword_link_fk FOREIGN KEY (meta_keyword_reference)
REFERENCES public.meta_keyword (reference) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT page_about_meta_keyword_link_reference_unique UNIQUE (reference)
)
This is the meta_keyword
CREATE TABLE public.meta_keyword
(
reference bigint NOT NULL DEFAULT nextval('meta_keyword_reference_seq'::regclass),
keyword text,
effective_date timestamp with time zone DEFAULT now(), -- UTC
membership_reference bigint,
CONSTRAINT meta_keyword_pkey PRIMARY KEY (reference),
CONSTRAINT meta_keyword_reference_unique UNIQUE (reference)
)
This is the query I've created in the Service; The complete Service is found here.
$repository = $this->entityManager->getRepository(PageAboutMetaKeywordLink::class);
$keywords = $this->entityManager->getRepository(MetaKeyword::class);
$qb = $repository->createQueryBuilder('l');
$qb ->join('\Application\Entity\MetaKeyword' , 'k')
->expr()->isNull('l.removeDate');
return $qb->getQuery()->getResult();
The Association Mapping I created is for meta_keyword_reference; The complete Entity is found here.
/**
* #var int|null
*
* #ORM\ManyToOne(targetEntity="MetaKeyword")
* #ORM\JoinColumn(name="meta_keyword_reference", referencedColumnName="reference")
* #ORM\Column(name="meta_keyword_reference", type="bigint", nullable=true)
*/
private $metaKeywordReference;
I have not made any changes to the MetaKeywords Entity. It is found here.
Overall the various sections of the web site will share the meta_keywords. If I understand correctly the connection I am trying to make is ManyToOne.
I am wanting to leave a good reference for other newbies as they are their journey with Zend Framework 3 - Doctrine. Please advise of edits I should be making to this post so it is clear, understandable and concise so I receive the help I need and others will benefit from this in the future.
You double declared a column (meta_keyword_reference). Looking at the docs (same page you linked in question), you've made a mistake in your Annotation. Remove the ORM\Column line (the definition is already in JoinColumn). If you need it to be nullable (not required), add nullable=true to the JoinColumn; use either, not both
/**
* #var int|null
*
* #ORM\ManyToOne(targetEntity="MetaKeyword")
* #ORM\JoinColumn(name="meta_keyword_id", referencedColumnName="id", nullable=true)
*/
private $metaKeywordReference;
Do not worry about declaring a "type", Doctrine will automatically match it to the column you're referencing. Also, you should be referencing Primary Keys. I've assumed reference is not the PK, so I've changed it to id, change it to what it actually is.
Next, I think you're also using DBAL QueryBuilder instead of the ORM QueryBuilder.
The Query you need would be like this:
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
/** #var QueryBuilder $qb */
$qb = $this->entityManager->createQueryBuilder();
$qb->select('l')
->from(PageAboutMetaKeywordLink::class, 'l')
->join(MetaKeyword::class, 'k', Join::ON, 'l.reference = k.id') // check these property names (NOT DB COLUMNS!)
->where('l.removeDate is null');
Might be a few small errors in there, but that should be about it.

Masterdata Services udpValidateModel Procedure

i've got a few tables in MDS.
One table (clients) ist filled via SQL and the other one is a masterdata table (country) filled by hand.
I have a business rule on table clients:
"Name must be unique" and no b-rule on Country.
I want to validate the data PROGRAMMATICALLY i do not want to CLICK "apply business rules" in explorer window on the webinterface.
I found several threads about how to use the sp mentioned in the title (udpValidateModel) to validate all entities in a model.
well...this thing does nothing. I can see the validationStatus in each of my tables "Awaiting Revalidation" after changing business rules or update data via sql. It doesnt matter what i do the status wont change (neither the validation icons in webui).
i also tried validateentity but the same "nothing" happens.
The SP below:
DECLARE #User_ID int
DECLARE #Model_ID int
DECLARE #Version_ID int
SET #User_ID = (SELECT ID FROM [MasterDataServices].[mdm].[tblUser] where userName = SYSTEM_USER )
SET #Model_ID = (SELECT Top 1 Model_Id FROM [MasterDataServices].[mdm].[viw_SYSTEM_SCHEMA_VERSION]
WHERE Model_MUID = 'MYMODELID')
SET #Version_ID = (SELECT Top 1 VersionNbr FROM [MasterDataServices].[mdm].[viw_SYSTEM_SCHEMA_VERSION]
WHERE Model_MUID = 'MYMODELID'
ORDER BY ID DESC )
EXECUTE [MasterDataServices].[mdm].[udpValidateModel] #User_ID, #Model_ID, #Version_ID, 1
Can anyone help?
SP 'udpValidateModel' works perfectly fine, looks like the parameters you are populating is not correct.
You may correct this as below and try; make sure that the system user has full authorization for the model.
SET #User_ID = (SELECT ID FROM [MasterDataServices].[mdm].[tblUser] where userName = SYSTEM_USER )
SET #Model_ID = (SELECT Top 1 Model_Id FROM [MasterDataServices].[mdm].[viw_SYSTEM_SCHEMA_VERSION]
WHERE Model_MUID = 'MYMODELID')
SET #Version_ID = (SELECT Top 1 VersionNbr FROM [MasterDataServices].[mdm].[viw_SYSTEM_SCHEMA_VERSION]
WHERE Model_MUID = #Model_ID
ORDER BY ID DESC )

autogenerated keys for entities with multipart keys

I was trying to create a new object with multicolumn primary key formed by a foreign key and a self-generated field and I found this error:
Ids can not be autogenerated for entities with multipart keys.
For now, and although not the most appropriate, I will change the key but the question is:
Are you planning support multicolumn primary key autogenerated soon?
I will add the request to uservoice too.
A greeting.
Edit to explain the use case:
Hello,
True, it may not make sense to have a primary key composed by a foreign key and a self-generated field.
My idea was to build a table like this:
ParentID ChildID Data
1 1 Some Data...
1 2 Some Data...
2 1 Some Data...
2 2 Some Data...
As a first step I did a table like this:
ParentID ChildID Data
1 1 Some Data...
1 2 Some Data...
2 3 Some Data...
2 4 Some Data...
Where ChildID was a self-generated field.
So you can ignore my question.
A greeting.
I've had the same problem but I have successfully solved it without changing the Primary Key (PK).
My PK had 2 columns
ProductId (identity)
TenantId (multitenant application)
so the first problem was Breeze couldn't generate new PK when the new item was added to the EntityManager. And I have defined custom entity initialization function:
var manager = new breeze.EntityManager(breezeServiceUrl);
var store = manager.metadataStore;
function itemInitializer(item) {
if (item.ProductId() == 0) {
item.ProductId(/*Some counter value*/);
}
if (item.TenantId() == 0) {
item.TenantId(TenantId);
}
if (item.isBeingEdited === undefined) {
item.isBeingEdited = ko.observable(false);
}
};
store.registerEntityTypeCtor("ProductItem", function() {/*Leave empty to use default constructor*/}, itemInitializer);
The second problem is that Breeze couldn't update the ProductId with the real value from EntityFramework because it gets the entity by PK and the returned value had only ProductId. So you need to override the function:
var entityType = store.getEntityType("ProductItem");
var entityGroup = manager.findEntityGroup(entityType);
entityGroup._fixupKey = function (tempValue, realValue) {
var ix = this._indexMap[tempValue + ":::" + TenantId]; //Changed line
if (ix === undefined) {
throw new Error("Internal Error in key fixup - unable to locate entity");
}
var entity = this._entities[ix];
var keyPropName = entity.entityType.keyProperties[0].name;
entity.setProperty(keyPropName, realValue);
delete entity.entityAspect.hasTempKey;
delete this._indexMap[tempValue];
this._indexMap[realValue] = ix;
};
If you have any other questions about multipart keys, you can read it in the blog.
This feature is not currently on the roadmap, but I want to better understand your use case for this. As you already know, Breeze supports auto-generated keys, and Breeze supports multi-part keys, but what scenarios do you find using both at the same time to be helpful?
Thanks!
Actually having a multipart key where part of the key is autogenerated is actually pretty common. This usually occurs with legacy databases where the primary key consists of a foreign key property and a 'autogenerated' sequence number property. Usually this autogenerated key is not globally unique by itself, but only in conjunction with the foreign key property. Think of an orderDetail with a foreign key of "OrderId, SequenceNumber".
What doesn't seem to make as much sense is when the primary key consists of more than one autogenerated property.
In Breeze the autogenerated keys are intended to be globally unique. Whereas, in the multipart key mentioned above the SequenceNumber would not be globally unique ( and if it were then why not make it the primary key all by itself).
Does this make sense?

Resources